C++程序设计课件 设计制作:徐龙琴 2
教学内容:
8.1 指针 的 概念 及 其运算
8.2 void指针和 const指针
8.3 指针 与 数组
8.4 指针 与 字符串
8.5 指针 与 函数
8.6 动态内存分配
8.7 引用
C++程序设计课件 设计制作:徐龙琴 3
?熟练掌握 指针 的 概念, 定义, 初始化 及 指针运算
?掌握 指针 与 数组, 函数, 字符串 等的 联系 ;
?掌握 动态空间操作;
?掌握 引用 的 定义格式 及其 使用规则
教学目的:
C++程序设计课件 设计制作:徐龙琴 4
§⒏ 1指针的概念及其运算
若 定义了一个变量, 编译系统就会 根据定义中变
量的类型,为其分配一定字节数的内存空间 (如:字
符型占 1字节、整型占 2字节、实型占 4字节、双精度
型占 8字节 …… )。
例, int a=1,b=2; float x=3.5;
每个 变量的地址是指该变量所占存储单元的第一个字节的
地址 。在此称的 a地址为,1012; b为 1015; x为 1201
a
1012 1013
b
1015 1016
x
1201 1202 1203 1204
C++程序设计课件 设计制作:徐龙琴 5
例如,语句 printf(“%d”,a+b); 的 执行是这样的,
① 依变量名与地址的对应关系(此对应关系是
在编译是确定的) 找到变量 a的地址 1012和变
量 b的地址 1015
② 从 1012开始的两个字节中 取出 a的值 (1);再
从 1015开始的两个字节中 取出 b的值 (2)
③ 将 a的值 (1)与 b的值 (2)相加 后,按, %d”格式
输出
总之, 变量和变量内存地址有一一对应关
系,变量的地址 我们 又称 变量的指针 。
C++程序设计课件 设计制作:徐龙琴 6
指针变量 是一个变量,它和普通变量一样占用一
定的存储空间。但与普通变量不同之处在于,指针变
量的存储空间存的不是普同数据,而是一个地址,因
此指针变量是一个地址变量。
指针 是一个地址,是一个地址常量,若我们要存
放该地址常量的值,可用定义一个变量来存放。
a
1012 1013
1012p
2002
变量 p指向了变量 a
⒈ 指针 概念
C++程序设计课件 设计制作:徐龙琴 7
◆ 指针变量和它所指向的变量之间的关系的表示,
■ 在程序中用, *” 号 表示, 指向,,如,p代表指
针变量,而 *p是 p所指向的变量,见下图
1012
p
2002
a
1012
1
*p
■ 可以看到* p也代表一个变量,它和变量 a是同一
回事。 因此语句 a=1;和 *p=1;的作用相同
&P
◇ 变量的指针 和指向变量的 指针变量
◆ 变量的指针, 即变量的地址
◆ 指针变量, 存放变量地址的变量是指针变量,用
来指向另一个变量。
C++程序设计课件 设计制作:徐龙琴 8
⒉ 指针变量定义格式:
数据类型 *指针变量名;
float *p1,*p2; (p1和 p2是指向实型变量的指针变量 )
char *p; (p是指向字符型变量的指针变量 )
例,
? ◆ 数据类型, 指该指针变量 所指的变量的类型 。
◆ *, 是一个说明符,用来 说明该变量是指针变量
◆ 指针变量名,是用户自定义的任意 合法的标识符 。
C++程序设计课件 设计制作:徐龙琴 9
⒊ 指针初始化格式:
数据类型 *指针名=初始地址;
注意,① 所有 指针变量 在使 用 之 前 都 要有确定的指向, 如果暂时不知
道给指针变量赋什么值,就 赋 NULL(它是 iostream.h头文件
中的预定义符 ),值为, NULL”的指针称为 空指针 。
② 指针变量 占 4个存储单元, 不能将一个整型数据赋给指针变量
例,float x;
float *p=&x;
等价,float *p,x;
p=&x; //p只能指向 float型 变量
C++程序设计课件 设计制作:徐龙琴 10
注意,
&,它是 取地址运算符,即 取&运算符右侧的对象的地址
*, 它是 指针运算符,它 有两个含义:
在定义时 * 指 后面的变量是指针变量, char *cp;
除 定义之外 * 指取 指针所指 向的变量的值 。
如,char *cp= &a; //*cp指 a的值
*cp=2; //将 2的值赋给 a
例, 若 int *p,a= 1; 则下列语句的含义是:
p=&a;
a= *p;
p = &( *p) ;
a = *(&a) ;
// 将 a的地址赋给 p
//将 p所指向的值赋给 a
//将 p所指向的值的地址赋给 p
//将 a的值赋给 a
C++程序设计课件 设计制作:徐龙琴 11
“&“和, *,运算符,优先级相同,结合性为自右向左
//&*p1代表 a的地址( &a或 p1),
//它的作用是使 p2指向 a
例, 若 int *p1,*p2,a=5,b,c;
则下列语句的含义是:
p1=&a;
b=(*p1)++;
p2=&*p1;
c=*&a; //*&a与 a等价
//相当于 a++
若写成 *p1++作用就不一样了,因为 ++和 *为
同一优先级,且 都为右结合性,因此它 相当于
*(p1++),因此 先对 p1的原值进行 *运算,得到 a的
值,然后使 p1的值改变,这样 p1不再指向 a了
C++程序设计课件 设计制作:徐龙琴 12
例,指针变量的引用
#include <iostream.h>
void main()
{ int i1=600,i2=800;
int *p1,*p2;
p1=&i1,p2=&i2; //使 p1指向 i1,p2指向 i2
cout<<"i1="<<*p1<<" "<<"i2="<<*p2<<endl;
*p1=300,*p2=400; //作用相当于 i1=300,i2=400
cout<<"i1="<<*p1<<" "<<"i2="<<*p2<<endl;
*p1=*p1+1; //相当于 i1=i1+ 1;
cout<<"i1="<<*p1<<" "<<"i2="<<*p2<<endl;
p1=p2; //使 p1指向 p2所指向的目标 i2
cout<<"i1="<<*p1<<" "<<"i2="<<*p2<<endl; }
运行该程序将得到如下结果:
i1=600 i2=800
i1=300 i2=400
i1=301 i2=400
i1=400 i2=400
C++程序设计课件 设计制作:徐龙琴 13
例,通过指针变量访问整型变量
运行结果为,100,10
100,10
#include <stdio.h>
void main( )
{ int a=100,b=10;
int *p1,*p2; /* 定义指针变量 p1和 p2 */
p1=&a; p2=&b; /* 使 p1指向 a,p2指向 b */
printf(“%d,%d\n”,a,b);
printf(“%d,%d\n”,*p1,*p2); /*输出 a,b的值 */
}
C++程序设计课件 设计制作:徐龙琴 14
例,输入 a和 b两个整数,按先大后小的顺序输出 a和 b
#include <stdio.h>
void main( )
{int *p1,*p2,*p,a,b;
scanf(“%d,%d”,&a,&b);
p1=&a; p2=&b; /* 先使 p1指向 a,p2指向 b */
if(a<b)
{p=p1;p1=p2;p2=p;} //使 p1和 p2改变指向,使 p1指向 b,p2指向 a
printf(“\na=%d,b=%d\n\n”,a,b);
printf(“max=%d,min=%d\n”,*p1,*p2);
}
运行结果:
60 80
60 80
80 60
C++程序设计课件 设计制作:徐龙琴 15
⒋ 指针运算 (其实质为地址运算 ):
① 指针 与整数的加减 运算:其 结果 仍然 是 一个 地址, 它是以
该指针为基点的前方或后方第 n
个数据的地址
⑴ 算术运算:
② 指针 自加,自减 ( p++,p--),自加 是指向下一个数据,
自减 是指向上一个数据
③ 同类型的指针相减, 得出 它们所指向的地址之间包含的
数据的个数
C++程序设计课件 设计制作:徐龙琴 16
例, int *p,a[]={1,2,3,4};
p=&a[0];
p+=3;
printf(“%d”,*p); 运行的结果,
若 &a[0] =1022,则 最后 p的值:
p± n × sizeof(所指向变量的类型)
p=1022+3× 2=1028
4
总结, p± n表示实际的地址是:
C++程序设计课件 设计制作:徐龙琴 17
例:
#include <iostream.h>
void main()
{ double a[10];
double *iptr=&a[0];
for(int i=0;i<5;i++)
a[i]=i*2.5;
for(int j=0;j<5;j++)
{ cout<<"a["<<j<<"] "<<iptr<<" "<<*iptr<<endl;
iptr++; }
}
程序运行结果如下,
a[0] 0x0012FF30 0
a[1] 0x0012FF38 2.5
a[2] 0x0012FF40 5
a[3] 0x0012FF48 7.5
a[4] 0x0012FF50 10
C++程序设计课件 设计制作:徐龙琴 18
⑵ 关系运算,相同类型的两指针,指向 后方的指针大于指向前
方的指针,指针的内容为 0时我们称为 空指针 (p== 0)
例,char c,*p;
p=&c;
① 把变量的地址赋给相同目标类型的指针
② 把一个指针的值赋给相同目标类型的另一指针
例,char *p1,*p2= &b;
p1=p2;
③ 把数组地址赋给相同目标类型的另一指针
例,char a[10],*p;
p= a;
⑶ 赋值运算
C++程序设计课件 设计制作:徐龙琴 19
◇ 对指针变量进行 *,++,- -混合运算的理解,
① 若,int a[4]={1,2,34,5},*q=a;
则,*q++,等价于 *(q++)。它 先得到 *q,然 后 再使 q自增 1,
(*q)++,表示 q所指向的元素 值 加 1
▲ *(p++)或 *p++相当于 a[i++],先 对 p进行 *运算,再使 p自增 1
▲ *(++p)或 *++p相当于 a[++i],先 使 p自增 1,再对 p进行 *运算
▲ *(p- -)或 *p- -相当于 a[i- -],p先进行 *运算,p再自减 1
▲ *(- -p)或 *- -p相当于 a[- -i],p先自减 1,p再 进行 *运算
② 若,p当前 指向 a数组的第 i个元素,则:
C++程序设计课件 设计制作:徐龙琴 20
§ 8.2 void指针和 const指针
⒈ void(空) 指针,是一种不确定类型的指针,它 可以指向任
何类型的变量 。其 语法格式 为:
void *指针变量 ;
? ◆ 指针变量,不指向任何具体的数据类型,任何地址都可
以赋给指针变量
例, int a=9;
void *p1=&a;
int b=*(int *)p1;
int *p2=(int *)p1;
注意:
①如果需要将 void指针的值赋给其他类型的指针,则需要
进行强制类型转换。
② void型指针 p指向了整型变量 i,则应用 *(int*)p才能访
问 i。
C++程序设计课件 设计制作:徐龙琴 21
⒉ const指针,关键字 const放在不同的位置表示的意义也不相
同,它有以下 三种形式:
① 指向常量的指针,指针 指向的 内存 数据不能修改,但 指针 本
身 是变量,可允许 这种指针变量 指向另外 一
个同类型的 别的变量 。 其定义的格式 为:
const int *指针变量名;
const int *pci;
const int a=1;
pci=&a;
const char *pc=“Point”;
例:
C++程序设计课件 设计制作:徐龙琴 22
② 指针常量 (常指针 ),
int a=1;
int b=2;
int *const cpi=&a; //定义指针常量 cpi
*cpi=5; //ok! 可以改变变量 a的值
cpi=&b; //error! 不能改变指针
例:
在指针 定义 语句的 指针名前加 const,
表示 指针 本身 是常 量,所以在定义指
针时 必须初始化,此后不能再赋其他
地址,但 指针指向的变量是可变的
C++程序设计课件 设计制作:徐龙琴 23
③ 指向常量的指针常量,
const int a=7;
int b= 34 ;
const int *const cpi=&a
const int *const cpc=&b;
cpc=&a; //error! 指针值不能改变
*cpi=33; //error! 不能修改指针指向的值
*cpc=44; //error! 不能修改指针指向的值
例:
其在 定义 指针 时必须 初始化,即 不能
改变指针值,也 不能改变指针指向的
常 量 的值 。
C++程序设计课件 设计制作:徐龙琴 24
综上所述,可知道,
① 指向常量的指针变量 可以 被 初始化为变量的地址值,但 不
能通过指针修改该变量的值。
② 不能将 常量 的 地址 赋给 不指向常量 的 指针变量 。
例如,const int a=100;
int *p;
p=&a; //error!
C++程序设计课件 设计制作:徐龙琴 25
§ 8.3 指针与数组
指针变量 既然可以指向变量,当然 也可以指向数组 或
数组元素 (将数组起始地址或某一元素的地
址放到一个变量中)。
数组的指针,指 数组的起始地址。
数组元素的指针,指 数组元素的地址。
指向数组的指针变量, 指 存放数组首地址的指针变量
指向数组元素的指针变量, 指 存放数组元素的指针变量
C++程序设计课件 设计制作:徐龙琴 26
例 1,int a[10];
int *p=a; //等价与 int *p; p=a;
则, 该数组的 第 i个元素可表示为:
a[i] 或 p[i]或 *(p+i)或 *(a+i)
数组 ap
a[0]
a[1]
* (p+i)
p+1,a+1
p+i,a+i
a[2]
a[i]
a[9]p+9,a+9
该数组的 第 i个元素的地址可表示为:
&a[i] 或 &p[i] 或 a+i 或 p+i 或
⒈ 用指针访问一维数组元素,
注意,a是地址常量,不允许对其赋值,
诸如,a++,a=&x等都是非法的
C++程序设计课件 设计制作:徐龙琴 27
例, 利用指针变量访问数组元素
#include <iostream.h>
void main()
{ int size;
double array[ ]={5.5,6.7,3.6,6.8,1.2};
double *p_array;
p_array=array;
size=sizeof(array)/sizeof(*array);
for (int i=0;i<size;i++)
{ cout<<*(p_array+i)<<endl;
}
}
运行结果是:
5.5
6.7
3.6
6.8
1.2
{ cout<<*p <<endl;
p_array++; }
}
C++程序设计课件 设计制作:徐龙琴 28
① 对二维数组的理解
数组名是数组的 首地址 。
例,int a[3][4]; //a是数组的首地址。
那么,a[0],a[1],a[2] 是什么呢?
也是地址量。
把二维数组,理解 成下面的图的形式:
a00
a10
a20
a01
a11
a21
a02
a12
a22
a03
a13
a23
a
a00
a10
a20
a01
a11
a21
a02
a12
a22
a03
a13
a23
a[0]
a[1]
a[2]
a
⒉ 用指针访问多维数组元素,
C++程序设计课件 设计制作:徐龙琴 29
? a, a[0] 是 a[0][0]的地址,是第一行的首地址。
a00
a10
a20
a01
a11
a21
a02
a12
a22
a03
a13
a23
a[0]
a[1]
a[2]
a
a+1, a[1]是 a[1][0]的地址,是第二行的首地址。
*a 是 a[0]的 内容, **a是 a[0][0]。
a是 二 维数组,经过 两 次 *操作,才能访问到数组元素:
*a是 a[0]的内容,**a才 是 a[0][0]。
a[0]是 a[0][0]的地址,*a[0]是 a[0][0]的 内容。
综上所述,对于一般的二维数组 a,有以下关系:
*(a+i)+j=&a[i][j] a[i][j]=*(*(a+i)+j)
C++程序设计课件 设计制作:徐龙琴 30
例,int a[3][2]={11,12,13,14,15,16},i,j;
int *p=a[0];
则,
a[2][1]
内存
a[0][0]
16
a[0][1]
a[1][0]
a[1]1]
a[2][0]15
14
13
12
113000H
3002H
3004H
3006H
3008H
300AH
3000H
a[0]
3004H
a[1]
3000H
p
3000H
a
3004H
a+ 1
a= 3000H
a+1=3004H
*a= =3000H
**a= =11
a[0]
a[0][0]
a[1]= =&a[1][0]3004H
a[1]+1= =&a[1][1]3006H
p= =&a[0][0]3000H
p+1= =&a[0]1]3002H
*(p+2)= 13
*p+8= 19
*p++= 11
C++程序设计课件 设计制作:徐龙琴 31
总之若,int a[2][2]={1,2,3,4},i,j;
int *p=a[0];
a[i][j]=
=(*(a+i))[j]
*(a[i]+j)
=*(*(a+i)+j)
=*(&a[0][0]+2*i+j)
&a[i][j]=a[i]+j
=*(a+i)+j
=&a[0][0]+2*i+j
=a[0] +2*i+j
=*(p+2*i+j)
= p+2*i+j
则:
C++程序设计课件 设计制作:徐龙琴 32
例,通过数组元素的地址来引用二维数组元素
#include <iostream.h>
#include <iomanip.h>
void main()
{ int a[3] [4]={{1,3,5,7},{9,11,13,15},{17,19,21,23}};
for(int i=0;i<3;i++)
{ for (int j=0; j<4; j++)
cout<<setw(8)<<*(*(a+i)+j)<<,”; //也可写成 *(a[i]+j)或 (*(a+i))[j]
cout<<endl;
}
}
运行结果是:
1 3 5 7
9 11 13 15
17 19 21 23
C++程序设计课件 设计制作:徐龙琴 33
⒊ 数组指针:
是 一个存放二维数组行地址的指针变量,常用于 处理二
维数组,数组指针的 定义格式为,
数据类型 ( *变量名) [常量表达式 ];
? ◆ 数据类型,表示一维数组元素的数据类型
◆ *:表示变量是指针
◆ []:表示是数组
◆ 常量表达式,表示二维数组的每行元数的个数
注意,因为运算符 [ ]的优先级高于 *,所以必需用圆括号()
将 *与指针变量名括起来
例,int b[2][2]={12,36,62,14};
int (*p)[2]=b; //表示 p是指向数组 b的行的指针变量
int *p[5]; //表示数组 p含 5个元素,每个元素均是一个指针变量
C++程序设计课件 设计制作:徐龙琴 34
例,通过数组元素的地址来引用二维数组元素
#include <stdio.h>
void main()
{int a[3][4]={1,3,5,7,9,11,13,15,17,19,21,23};
int (*p)[4];
p=a;
printf("%d",*(*(p+2)+3));
}
运行结果是:
23
由上可得:
&a[i][0] =a[i] =p[i] =*(p+i) = p+i
&a[i][j] =&p[i][j] = *(p+i)+j= p[i]+j
a[i][j] =p[i][j] = *(*(p+i)+j) =*(p[i]+j)
C++程序设计课件 设计制作:徐龙琴 35
⒋ 指针数组:
指针数组,就是 其元素为指针的数组。它是指针的集合,它的
每一个元素都是指针变量,并且它们具有相同的存
储类型和指向相同的数据类型。 主要用于字符串的
操作,其 定义格式 为:
数据类型 *指针数组名 [常量表达式 ];
? ◆ 数据类型,指数组中 各元素指针所指向的类型,
◆ 指针数组名,也即 数组的首地址, 是 一个 标识符 ;
◆ 常量表达式,指出这个 数组中 的 元素个数 。
例,int *p1[6]; float *p2[3][4];
static char *name[3]= {“Tom”,”John”,”Mary”};
C++程序设计课件 设计制作:徐龙琴 36
例,输入月份( 1~ 12),输出该月份所在季节的英文名称。
#include <iostream.h>
void main()
{char *pseason[4]={"Spring","Summer","Autumn","Winter"};
int month;
cin>>month;
switch(month)
{ case 12:case 1:case 2,cout<<pseason[0]<<endl; break;
case 3:case 4:case 5,cout<<pseason[1]<<endl; break;
case 6:case 7:case 8,cout<<pseason[2]<<endl; break;
case 9:case 10:case 11,cout<<pseason[3]<<endl; break;
default,cout<<"input data error!";
}
}
C++程序设计课件 设计制作:徐龙琴 37
⒌ 指向指针的指针变量,
指向指针的指针变量, 指 该针变量中存放的是另一个指针的地
址。其 也称为 二级指针 。多用于访问二
维数组。 其 语法格式为:
数据类型 **变量名
例,int x=32;
int *p=&x;
int **pp=&p;
则 x,p和 pp三者之间的关系:
3000H
pp
3004H
p
32
x
p是一级指针; pp是二级指针。
*pp= p= &x
**pp= *p=x。
C++程序设计课件 设计制作:徐龙琴 38
例, 阅读下列程序,写出运行结果。
#include <iostream.h>
void main()
{int b[3][4]={12,36,62,56,98,63,56,99,88,32,66,22};
int *p[3]={b[0],b[1],b[2]},**pp=p,i,j;
cout<<"输出 b数组每行的首地址,\n";
for(i=0;i<3;i++) cout<<*pp++<<" ";
cout<<endl;
pp=&p[0];
cout<<"输出 b数组每个元素的地址,\n";
for(i=0;i<3;i++)
{for(j=0;j<4;j++) cout<<*(pp+i)+j<<" ";
cout<<endl; }
cout<<endl;
pp=&p[0];
cout<<"输出 b数组每个元素的值,\n";
for(i=0;i<3;i++)
{for(j=0;j<4;j++) cout<<*(*(pp+i)+j)<<" ";
cout<<endl; }
}
p[i ]
p[i][j]
p[i]+j程序运行的结果为:
输出 b数组每行的首地址,
0x0065FDC8 0x0065FDD8 0x0065FDE8
输出 b数组每个元素的地址,
0x0065FDC8 0x0065FDCC 0x0065FDD0 0x0065FDD4
0x0065FDD8 0x0065FDDC 0x0065FDE0 0x0065FDE4
0x0065FDE8 0x0065FDEC 0x0065FDF0 0x0065FDF4
输出 b数组每个元素的值,
12 36 62 56
98 63 56 99
88 32 66 22
C++程序设计课件 设计制作:徐龙琴 39
§ 8.4指针与字符串
在 C++语言中,可以定义一个 字符数组, 将字符串存放在
该数组中,通过数组下标来访问所需的字符;也可以定义一个
字符指针, 通过指针的指向来访问所需的字符 。
如果要通过 指针访问一个字符串, 可以 将这个 指针指向
此字符串,并利用指针的 加 1,减 1操作实现对各个字符的 访问 。
例,利用字符指针访问字符串 。
#include<iostream.h>
void main()
{char *str="hello";
cout<<str<<endl;
}
C++程序设计课件 设计制作:徐龙琴 40
例,阅读下列程序,写出运行结果。
#include <iostream.h>
void main()
{char s[]="C++ program";
char *ps1="computer";
char *ps2,*ps3=s;
ps2="mouse"; //使指针变量 ps2指向字符串 "mouse"的首地址
cout<<s<<" "<<ps1<<" "<<ps2<<" "<<ps3<<endl;
ps1++;ps2+=2;ps3+=4; //移动指针
cout<<s+4<<" "<<ps1<<" "<<ps2<<" "<<ps3<<endl;
cout<<*s<<" "<<*ps1<<" "<<*ps2<<" "<<*ps3<<endl;
ps1=s;
}
程序的运行结果为:
C++ program computer mouse C++ program
program omputer use program
o u p
C++程序设计课件 设计制作:徐龙琴 41
§ 8.5指针与函数
在 C++中,指针和函数可以配合使用,指针 可以作 函数的
参数,函数的 返回值 可以是指针类型,还可以有 指向函数 的指针
及其指针数组。
⒈ 指针作函数的参数,
指针作函数的参数,能将 一个对象的 地址传送到被调函数
中,在该被调函数中可以通过指针参数操作主调函数中的对象。
C++程序设计课件 设计制作:徐龙琴 42
例,输入两个整数,将它们按由大到小的顺序输出,连续进行上
述操作 3次,即对 3对整数重复操作。
#include <iostream.h>
void swap(int *,int *);
void main( )
{ int a,b,*pa,*pb;
pa=&a;
pb=&b;
for (int i=0;i<3;i++)
{ cout<< " Input,"; cin>>a>>b;
if(a<b) swap (pa,pb);
cout<< " Output," <<a<<" "<<b<<endl; }
}
void swap(int *p1,int *p2)
{ int temp;
temp=*p1; *p1=*p2; *p2=temp; }
程序运行结果是:
Input,5 7
Output,7 5
Input,8 6
Output,8 6
Input,5 5
Output,5 5
C++程序设计课件 设计制作:徐龙琴 43
⒉ 指针型函数,
除 void型的 函数之外, 函数 在调用结束后 都 会 有返回
值, 指针 同样 也可以作为函数的返回值 。当一个函数的返回
值是指针类型时,这个函数就 是 指针型函数 。指针型函数 定
义方式为,类型 *函数名称 (变量类型 变量名称 )
int *functionA( )
{ int var=100;
int *ptr=&var;
cout<<*ptr<<endl;
return ptr; }
例,定义一个返回 int型指针值的函数 functionA
stadic int var=100;
C++程序设计课件 设计制作:徐龙琴 44
⒊ 函数指针,
⑴ 函数指针,就是 指向函数的指针 。 其 定义格式为:
类型 ( *指针名)(参数表);
?◆ 类型, 是指函数指针所指向 函数的返回值的类型
◆ 参数表,指明了该函数指针所指向函数的 形参类型 和 个数
例,int (*p)(int,int);
就定义了一个函数指针 p,它指向一个返回值为整
型且有两个整型参数的函数。 用函数指针前,必须先赋
值,使它指向一个函数的入口地址 (函数名 )。
C++程序设计课件 设计制作:徐龙琴 45
⑵ 函数指针的初始化格式为:
类型 (*指针名 ) (参数表 )=函数名;
或为,类型 (*指针名 ) (参数表 );
指针名=函数名;
⑶ 函数指针作用:
① 调用被指向的函数, 其调用的 格式是:
(*指针变量名 ) (实参表); 等价于,函数名 (实参表 )
② 作参数,函数不能直接作参数,所以当需要用函数作参
数时必须借助 于指向函数的指针来完成。
C++程序设计课件 设计制作:徐龙琴 46
例,通过函数指针作函数参数求三角函数的值。
#include <iostream.h>
#include <math.h>
double func(double (*)(double),double );
void main()
{double x,a,s1,s2;
cout<< "请输入一个角度值,";
cin>>x;
a=3.14159/180.0*x;
s1=func(sin,a);
s2=func(cos,a);
cout<<"x的正弦值,"<<s1<<endl;
cout<<"x的余弦值,"<<s2<<endl; }
double func(double (*fp)(double),double y)
{ return (*fp)(y); }
程序运行结果是:
请输入一个角度值,60
x的正弦值,0.866025
x的余弦值,0.500001
C++程序设计课件 设计制作:徐龙琴 47
⒋ 函数指针数组:
与定义变量指针数组一样,C++中也可以 定义 具有特定
返回类型 和 特定参数类型 的函数指针数组 。函数指针数组 也
可以是多维的,但常用到的是一维函数指针数组。其 定义格
式为:
数据类型 ( *函数指针名 [常量表达式 ]) ( 参数表 ) ;
例, int (*p[5])(int,int);
函数指针数组 p含有 5个元素,其每个元素都是一个指向函
数的指针,且指向的函数都是返回值类型为整型,带两个整型
参数的函数。
C++程序设计课件 设计制作:徐龙琴 48
§ 8.6动态内存分配
动态内存分配,是指 在程序运行期间根据实际需要随时申请内
存 (new),并在不需要时释放 (delete)。
应用程序数据所占内存可以分为 4类:
1) 全局数据区,存放程序的全局数据和静态数据。
2) 代码区,存放程序的代码,即程序中各个函数代码块。
3) 堆区,也称为 自由存储单元 。 存放程序中的 动态数据 。 new
与 delete运算符一起使用,就可进行动态内存的申请
和释放(也称为创建和删除)。
4) 栈区,保存每个函数的局部数据(函数的形参及局部变量)。
C++程序设计课件 设计制作:徐龙琴 49
⒈ 申请分配内存的方法有两种:
⑴ 利用 malloc函数
注意, ①该函数如 分配内存成功,则 返回其起始地址,
否则 返回 NULL。
②要在程序用该函数时,应写出其所在的文件:
#include<stdlib.h>或 #include < malloc.h >
格式是, void * malloc(字节数 )
C++程序设计课件 设计制作:徐龙琴 50
#include <stdlib.h>
#include <stdio.h>
void main()
{ int *ip;
ip=(int *)malloc(sizeof(int));
scanf("%d",ip);
printf("*ip=%d\n",*ip);
}
例,用 C语言 提供 的库函数 malloc( ), free( )来 动态分配释放内存,
free (ip);
内存申请的字节数,
这里只申请一个 int
返回的指针强制转换为
int*类型才能与 ip相容
C++程序设计课件 设计制作:徐龙琴 51
⑵ 利用 new运算符:
注意,格式 1和格式 2都是 给单个对象申请分配 内存空间;而
格式 3和格式 4可 同时给多个对象(数组)申请分配内存
格式 1:指针变量名 =new 类型标识符;
格式 2:指针变量名 =new 类型标识符 (初始值) ;
格式 3,指针变量名 =new 类型标识符 [内存单元个数 ];
格式 4,指针 =new 数据类型 [常量表达式 1][常量表达式 2];
功能,如果分配内存成功,则返回其起始地址,否则返回 0
C++程序设计课件 设计制作:徐龙琴 52
例如, int *ip,*p,*q;
ip=new int; //ip指向 1个未初始化的 int型对象
p=new int(68); //ip指向 1个表示为 68的 int型对象
q=new int [5]; //ip指向 5个未初始化 int型对象首地址
int (*p1)[3];
p1=new int[2][3]; //p1将指向 系统分配二维数组的第一行 。
malloc函数 和 new的 区别, 使用 malloc函数 分配内存时,其返
回值 要 经过 类型转换后 才可 赋给一
个指针变量,而利用 new分配内存
时则 不需要 类型转换 。
C++程序设计课件 设计制作:徐龙琴 53
⒉ 释放内存的方式,
⑴ 利用 free函数
注意, 使用时应嵌入相应的头文件,#include <stdlib.h>
或 #include < malloc.h >
格式是, free(起始内存地址 );
⑵ 利用 delete运算符:
说明, 格式 1可释放 某 一个内存单元 ;而格式 2可释放 若干
个内存单元的空间
格式 1,delete 指针变量名;
格式 2,delete [ ] 指针变量名;
C++程序设计课件 设计制作:徐龙琴 54
#include <iostream.h>
#include <stdlib.h>
void main()
{ int *number,*p,*q;
number=new int[100]; //申请分配 100个 int类型所占内存空间
p=new int; //申请分配一个 int类型所占内存空间 ( 2个字节 )
q=(int *)malloc(10*sizeof(int)); //申请分配 10个 int类型所占内存空间
if (number==NULL || p==NULL || q==NULL)
cout<<"内存分配失败 "<<endl;
else
cout<<"内存分配成功 "<<endl ; //程序的其它部分
delete []number; //释放 number所指向的所有内存空间
delete p; //释放 p所指向的所有内存空间
free (q); //释放 q所指向的所有内存空间
}
C++程序设计课件 设计制作:徐龙琴 55
§ 8.7 引用
⒈ 引用,就是 某个变量或对象的 另一个名字,所以 又 被 称,别
名”。 它的 值和地址 都与被引用的变量 或 对象 的 值和
地址值相同 。 当声明一个引用型变量时,需要用 另一
个变量对其初始化 。其 典型用法 是用作函数的形
参和
返回值。⒉ 声明一个引用型变量的语法格式为:
类型 &引用变量名 =变量名 ;
其中,类型,是被引用变量的的类型,
&:是引用运算符。
C++程序设计课件 设计制作:徐龙琴 56
例,int x;
int &refx=x; //定义引用 refx,它是变量 x的引用,即别名
说明,
( 1) refx就 称为 对 x的引用, x称为 refx的 引用对象 。
( 2) &在此不是求地址运算,而是 起标识作用 。
( 3) 类型标识符 是 指 目标变量 的 类型 。
( 4) 声明引用时, 必须 同时对其进行 初始化 。
( 5) 引用声明 完毕 后,相当于 目标变量 名 有两 个 名称,即该
目标原名称和引用名。
( 6)声明一个引用,不是新定义了一个变量,它只表示该引
用名是目标变量名的一个别名,所以 系统并不给引用分
配存储单元。
C++程序设计课件 设计制作:徐龙琴 57
例,引用的使用
#include <iostream.h>
void main()
{ int x,y=36;
int &refx=x,&refy=y;
refx=12;
cout<<"x="<<x<<" refx="<<refx<<endl;
cout<<"y="<<y<<" refy="<<refy<<endl;
refx=y;
cout<<"x="<<x<<" refx="<<refx<<endl;
}
运行的结果为:
x=12 refx=12
y=36 refy=36
x=36 refx=36从该例可以看出:
① 引用 是 被引用 变量的另一个名字 ;
② 引用 一旦初始化后,它就 与初始化它的变量 绑定 在一起 了。即使在
程序中修改了它,也不会绑定到另一个变量上。
③引用与指针不同。指针变量可不进行初始化,并且在程序中可以指
向不同的变量。 引用必须在声明的同时 用一个已经声明的变量 初
始化,并且一旦初始化后就不会再绑定到其他变量上了。
C++程序设计课件 设计制作:徐龙琴 58
⒊ 引用的作用,⑴作为 另一个变量 (变量名很长)的 别名 。
引用可以作为函数的参数,建立函数参数的引用传
递方式。 引用传递实际上传递的是变量的地址,而不是变量
本身。 这种传递方式 避免了 传递大量 数据带来的额外空间开
销,从而 节省 大量 存储空间, 减少 了程序 运行 的 时间 。
⑴ 引用作为函数的参数
⑵ 引用 作为函数的参数
⑶引用 作为函数的返回值
C++程序设计课件 设计制作:徐龙琴 59
例, 使用引用参数,实现两个数据的交换。
#include <iostream.h>
void swap(int &refx,int &refy)
{ int temp;
temp=refx;
refx=refy;
refy=temp;}
void main()
{ int x=63,y=36;
cout<<"front swap:\nx="<<x<<" y="<<y<<endl;
swap(x,y);
cout<<"back swap:\nx="<<x<<" y="<<y<<endl;
}
运行的结果为:
front swap,
x=63 y=36
back swap,
x=36 y=63
引用作为函数参数具有两个优点:
①参数传递方式类似于指针,但 可读性 却比指针传递 强 ;
② 调用 函数语法 简单,与简单传值调用一样,但 其 功能 却比传
值方式 强。
C++程序设计课件 设计制作:徐龙琴 60
⑵ 引用作为函数的返回值
引用既可以作为函数的参数,也可以作为函数的返回值。
一般函数可以用 return返回 一个 值,当函数返回值时 要生成
一个值的副本并保存在临时变量中 。 用引用返回值时,不生
成值的副本。
C++程序设计课件 设计制作:徐龙琴 61
例, 阅读程序,给出运行结果。
#include <iostream.h>int sum1(int a[],int n);
int &sum2(int a[],int n);void main()
{ int a[10]={1,2,3,4,5,6,7,8,9,10};int total1,total2;
total1=sum1(a,10);total2=sum2(a,10);
int &total3=sum2(a,10);cout<<"total1="<<total1<<endl;
cout<<"total2="<<total2<<endl;cout<<"total3="<<total3<<endl; }
int sum1(int a[],int n){ int sum=0;
for(int i=0;i<n;i++)sum+=a[i];
return sum; }int &sum2(int a[],int n)
{ int sum=0;for(int i=0;i<n;i++)
sum+=a[i];return sum;}
运行的结果为:
total1=55
total2=55
total3=-858993460
说明:
①语句 total1=sum1(a,10);在 sum1函数在返回 sum值时产生一个 sum值的
副本,并保存在临时变量中,total1再从临时变量中 取得返回值;
②语句 total2=sum2(a,10);是引用调用,sum2函数在返回 sum值时不产生
sum值的副本,total2直接从变量 sum中取得返回值;
③与 total2=sum2(a,10);语句类似 total3=sum2(a,10);也是引用调用,但 total3
本身也是一个引用,即 total3是 sum2函数的返回值 sum的别名。局部变
量 sum的作用域为 sum2函数,当 sum2结束后 sum也不复存在,因此,
total3的值不确定。
C++程序设计课件 设计制作:徐龙琴 62
引用总结:
① 引用的 目的 主要用于在函数参数传递中,提高传递的效率,
使程序的可读性好。
② 利用引用可以 使被调函数 返回多个值 。
③ 不能建立数组的引用 但 可以建立指针的引用
④ 声明引用时,必须同时对其进行初始化。
⑤ 引用 声明完毕后,相当于目标变量名有 两个名称, 不能再
把该引用名作为其他变量名的别名,
C++程序设计课件 设计制作:徐龙琴 63
例, 使用引用使函数返回多个值。以下定义了可以同时返回 10
个数中的最大值和最小值的函数 max_min。
#include <iostream.h>
void max_min(int *p,int n,int &max,int &min);
void main( )
{ int a[10];
int ma,mi,i;
for(i=0;i<10;i++) cin>>a[i];
max_min(a,10,ma,mi);
cout<<ma<<mi;}
void max_min(int *p,int n,int &max,int &min)
{ int i=0;
max=*(p+i);
min=*(p+i);
for(i=1;i<n;i++)
{if (max<*(p+i)) max=*(p+i);
if (min>*(p+i)) min=*(p+i); } }
C++程序设计课件 设计制作:徐龙琴 64
§ 程序举例
例,编程实现将 从键盘上输入两个字符先按由小到大排序,再
合并,并删去相同的字符,然后将合并后的字符串也按由小
到大排序并输出。
算法:
第一步 是从键盘上输入两个字符串;
第二步 是将两个字符串分别排序;
第三步 是将字符串合并;
第四步 是显示处理结果。
排序算法很多,这里使用
简单的 冒泡排序法,即将
字符串中的每一个字符一
个个进行比较,找出最小
的字符,然后,再在剩下
的字符中找最小的字符 …
C++程序设计课件 设计制作:徐龙琴 65
第二步排序,排序算法很多,这里使用简单的冒泡排序法:即
将字符串中的每一个字符一个个进行比较,找出最小的字符,
然后,再在剩下的字符中找最小的字符 …
void strsort(char *s)
{ int i,j,n;
char t,*w;
w=s;
for(n=0;*w!= ' \0 ';n++) //求串长 n
w++;
for(i=0;i<n-1;i++) //对串由小到大排序
for(j=i+1;j<n;j++)
if(s[i]>s[j])
{ t=s[i];
s[i]=s[j];
s[j]=t;}
}
C++程序设计课件 设计制作:徐龙琴 66
第三步合并字符串,假定两个排好序的字符串分别为 A和 B,
合并后的字符串为 C,要使待合并后的字符串仍然由小到大排
序,可采取下述 步骤:
依次从前往后分别取 A中的字符,B中的字符比 较:
① 若 A中字符小,则将该字符存入 C,并取 A的下个字符与 B中
的字符比较。
② 若 A中的字符较大,则将 B中字符存入 C,并取 B的下个字符
与 A中的字符比较。
③ 若 A与 B中字符相等,则将 A或 B中的字符存入 C,并取 A和 B
下一个字符比较
重复上面的比较直到 A或 B字符串到达末尾,则将 B或 A的剩余部
分加入字符串 C
C++程序设计课件 设计制作:徐龙琴 67
void strmerge(char *a,char *b,char *c)
{char t,*w;
w=c;
while((*a!='\0')&&(*b!='\0'))
{ if(*a<*b) { t=*a; a++;} //找到 a,b当前字符中较小的字符
else if(*a>*b) { t=*b;b++;}
else { t=*a;a++; b++;}
if (*w=='\0') *w=t; //开始,可直接赋值
else if(t!=*w) *(++w)=t; } //若当前字符与 c中当前字符不等,才赋值
if(*a!='\0') //如果字符串 a还没有结束,则将 a的剩余部分赋给 c
while(*a!='\0')
if(*a!=*w)
{*(++w)=*a; a++;}
else a++;
if(*b!='\0') //如果字符串 b还没有结束,则将 b的剩余部分赋给 c
while(*b!='\0')
if(*b!=*w)
{*(++w)=*b; b++; }
else b++;
*(++w)='\0'; }
C++程序设计课件 设计制作:徐龙琴 68
#include <stdio.h>
void main()
{ char s1[100],s2[100],s3[100];
printf("\nPlease input the first string:");
scanf("%s",s1);
printf("\nPlease input the second string:");
scanf("%s",s2);
strsort(s1);
strsort(s2);
printf("%s\n",s1);
printf("%s\n",s2);
s3[0]='\0';
strmerge(s1,s2,s3);
printf("%s\n",s3);}
其主程序为: