1、110.1地址和指针的概念地址和指针的概念一、指针概述:一、指针概述:1、地址的概念与取地址运算地址的概念与取地址运算:内存以字节编码,每个编码都是一个地址。我们原先学过的变内存以字节编码,每个编码都是一个地址。我们原先学过的变量、数组、函数等都放在内存中,我们只需知道它们是以怎样的量、数组、函数等都放在内存中,我们只需知道它们是以怎样的顺序放在内存中的,以便一一按顺序引用。我们怎样知道机器将顺序放在内存中的,以便一一按顺序引用。我们怎样知道机器将某种数据放在内存的什么地方呢?可用求地址运算符某种数据放在内存的什么地方呢?可用求地址运算符&如:如:int a=3;&a 就是变量在内存中的地址。
2、就是变量在内存中的地址。可以用可以用printf(“%x n”,&a);看出其地址。看出其地址。注意,这个地址并不注意,这个地址并不是始终不变的,这是由机器和操作系统来安排的,我们无法预先是始终不变的,这是由机器和操作系统来安排的,我们无法预先知道。知道。在数组中,数组名代表数组的首地址在数组中,数组名代表数组的首地址 故故a表示的地址和表示的地址和&a 0的地址相同。的地址相同。但但&不能施加在常数、常量或表达式上,也不能施加在寄存器不能施加在常数、常量或表达式上,也不能施加在寄存器变量上(因为寄存器变量在变量上(因为寄存器变量在cpu中,不在内存中)。中,不在内存中)。二、指针变量:二、指
3、针变量:既然存储在内存中的各种变量都有一个地址,我们能否这样设既然存储在内存中的各种变量都有一个地址,我们能否这样设想:定义某种变量,让这个变量的值等于某个变量的地址,如同想:定义某种变量,让这个变量的值等于某个变量的地址,如同某个房间号、门牌号一样?回答是肯定的。我们把某个房间号、门牌号一样?回答是肯定的。我们把这种存放某种这种存放某种变量地址的变量称为指针变量。变量地址的变量称为指针变量。1035.ab20102012p2010q2012因此,在因此,在C语言中,将地语言中,将地址形象化地称为址形象化地称为指针指针4说明说明(系统对变量的访问形式分为两种系统对变量的访问形式分为两种)一个变
4、量的访问(访问是指取出其值或向它赋值)方式一个变量的访问(访问是指取出其值或向它赋值)方式有两种:有两种:(1)直接访问,通过变量名访问,如通过变量名)直接访问,通过变量名访问,如通过变量名i直接访直接访问。问。(2)间接访问,通过该变量的指针来访问,如通过)间接访问,通过该变量的指针来访问,如通过指针指针p访问变量访问变量i。5基类型,即该指针变基类型,即该指针变量所指向的变量的类量所指向的变量的类型型10.2变量的指针和指向变量的指针变量变量的指针和指向变量的指针变量10.2.1、定义指针变量:、定义指针变量:存储类型存储类型 数据类型数据类型 *指针变量名指针变量名1,*指针变量指针变量
5、名名2,;如:如:int *p,a=10;int *q,b=35;如何使一个指针变量指向另如何使一个指针变量指向另外一个变量呢?外一个变量呢?P=&a;q=&b;1035.ab20102012p2010q20126 为什么要为指针变量定义类型:为什么要为指针变量定义类型:由于不同的数据有不同的数据类型,如由于不同的数据有不同的数据类型,如 char仅占一个字节、仅占一个字节、int 占两个字节、占两个字节、float型占三型占三个字节,而内存又是以字节为单位进行地址编个字节,而内存又是以字节为单位进行地址编号,因而对号,因而对char型,只要地址数加减型,只要地址数加减1,取出,取出里面的数据
6、就是里面的数据就是char型的完整数据。对型的完整数据。对int型就型就不同了,要取出其中的数据需不同了,要取出其中的数据需2字节,就不能字节,就不能对地址进行简单的加减对地址进行简单的加减1了。怎样取出一个完了。怎样取出一个完整的整的int型数据或型数据或float型数据呢?如果能够将指型数据呢?如果能够将指针变量也定义为具有同样的数据类型,那么对针变量也定义为具有同样的数据类型,那么对指针进行加指针进行加1或减或减1运算,就是让指针移动相应运算,就是让指针移动相应基类型对应的字节数。基类型对应的字节数。10.2.2、指针变量赋值和引用(要用到取地址运算符、指针变量赋值和引用(要用到取地址运
7、算符“&”)一、指针变量的赋值:例、一、指针变量的赋值:例、pointer_1=&i;pointer_2=&j;注意注意,指针变量中只能存放地址,不能将一个非地址类型的数据(如,指针变量中只能存放地址,不能将一个非地址类型的数据(如常数等)赋给一个指针变量,如:常数等)赋给一个指针变量,如:pointer_1=100;3.14 2.12pP+14bytepP+1P+2P+312342byte8也可以在定义指针变量的同时指定其初值,如、也可以在定义指针变量的同时指定其初值,如、int a;int*p=&a;二、指针变量的引用二、指针变量的引用1、取地址运算:如:、取地址运算:如:int *p,i
8、=3,j=5;p=&i;/*让让p其指向变量其指向变量i */2、对指针变量施加、对指针变量施加*运算,则代表取指针所指向的单元的内容。运算,则代表取指针所指向的单元的内容。这里,这里,*p与变量与变量i是等价的。是等价的。区分:区分:*运算符在不同场合的作用,编译器能够根据上下文环境判别运算符在不同场合的作用,编译器能够根据上下文环境判别*的作用。的作用。int a,b,c;int*p;(*表示定义指针)表示定义指针)p=&a;*p=100;(*表示指针运算符)表示指针运算符)c=a*b;(*表示乘法运算符)表示乘法运算符)int *p,i=3,j=5;p=&i;printf(“%d n”,
9、*p);p=&j;printf(“%d n”,*p);但不能但不能 int *p;char c=A;p=&c;(类型不匹配)(类型不匹配)区分区分*运算符的以下用法:运算符的以下用法:int a;int*p=&a;/*定义指针变量时指定初值,是为定义指针变量时指定初值,是为p指定初值指定初值*/*p=100;/*给指针给指针p所指向的变量赋值,这里是给变量所指向的变量赋值,这里是给变量a赋值赋值*/10例例main()int *p1,*p2,a1,a2;scanf(“%d%d”,&a1,&a2);p1=&a1;p2=&a2;printf(“%d,%d n”,*p1,*p2);p2=p1;pri
10、ntf(“%d,%d n”,*p1,*p2);这里有一个运算符这里有一个运算符*,其作用是:加在指针变,其作用是:加在指针变量的前面,取出该指针变量所指变量的内容。量的前面,取出该指针变量所指变量的内容。例例 使两个指针变量交换指向。使两个指针变量交换指向。main()int *p1,*p2,*p,a1=3,a2=5;p1=&a1;p2=&a2;printf(“%d,%d n”,*p1,*p2);p=p1;p1=p2;p2=p;printf(“%d,%d n”,*p1,*p2);交换前交换前下面表示下面表示p1和和p1交换所指内容交换所指内容35a1a2P1&a1P2&a235a1a2交换后交
11、换后P1&a2P2&a153a1*p1a2*p2交换后交换后P1&a1P2&a235a1*p1a2*p2交换前交换前P1&a1P2&a2a=*p1;*p1=*p2;*p2=aP=p1;p1=p2;p2=p例例 交换两个指针变量所指向的变量的值。交换两个指针变量所指向的变量的值。main()int *p1,*p2,a1,a2,a;a1=3;a2=5;p1=&a1;p2=&a2;a=*p1;*p1=*p2;*p2=a;printf(“a1=%d,a2=%d n”,a1,a2);1410.2.3 指针变量作为函数参数n 变量可以作为函数参数,指针变量同样可以作为函数参数。n指针变量作为函数参数时,同
12、样是从实参单向传递指针变量的内容给形参,只是传递的内容是一个地址值。可以通过这个地址值间接改变实参、形参所共同指向的变量。也就是通过改变地址所指向的变量。15通过函数调用,交换通过函数调用,交换a,b数据后输出数据后输出 试分析以下程序:试分析以下程序:程序程序1:函数参数使用一般变量的情况函数参数使用一般变量的情况。void swap(int i,int j)int temp;temp=i;i=j;j=temp;/*exchange i,j*/main()int a=5,b=10;swap(a,b);printf(swaped:n);printf(a=%d,b=%dn,a,b);16程序程序
13、2:函数参数使用指针变量,在函数中交:函数参数使用指针变量,在函数中交换指针变量值的情况换指针变量值的情况。void swap(int *p1,int*p2)int*ptemp;ptemp=p1;p1=p2;p2=ptemp;/*exchange pi,pj*/main()int a=5,b=10;int*pa,*pb;pa=&a;pb=&b;swap(pa,pb);printf(swaped:n);printf(a=%d,b=%dn,*pa,*pb);17程序程序3:函数参数使用指针变量,在函数中交:函数参数使用指针变量,在函数中交换指针变量所指向的变量的值情况。换指针变量所指向的变量的值情
14、况。void swap(int *p1,int*p2)int temp;temp=*p1;*p1=*p2;*p2=ptemp;main()int a=5,b=10;int*pa,*pb;pa=&a;pb=&b;swap(pa,pb);printf(swaped:n);printf(a=%d,b=%dn,*pa,*pb);1810.3 数组的指针和指向数组的指针变量数组的指针和指向数组的指针变量数组:数组:相同类型元素构成的有序序列。相同类型元素构成的有序序列。数组元素的指针数组元素的指针:数组元素在内存中占据了:数组元素在内存中占据了一组连续的存储单元,每个数组元素都有一一组连续的存储单元,每
15、个数组元素都有一个地址,数组元素的地址就是数组元素的指个地址,数组元素的地址就是数组元素的指针。针。数组的指针:数组的指针:就是数组的地址。数组的地址就是数组的地址。数组的地址指的是数组的起始地址(首地址),也就是指的是数组的起始地址(首地址),也就是第一个数组元素的地址。第一个数组元素的地址。C语言还规定数组名代表数组的首地址。语言还规定数组名代表数组的首地址。1910.3.1 指向数组元素的指针指向数组元素的指针定义一个指向数组元素的指针变量的方法,与定义一个指向数组元素的指针变量的方法,与以前介绍的定义指向变量的指针变量相同。以前介绍的定义指向变量的指针变量相同。格式:格式:数组基类型数
16、组基类型*指针变量名指针变量名;指针变量名指针变量名=数组名;数组名;/*指针变量名指针变量名=&数组名数组名0*/或:或:数组基类型数组基类型*p=数组名数组名;例如:例如:int a10;int*p;下面是对定义的指针变量赋值,下面是对定义的指针变量赋值,p=&a0;或者或者 p=a;int*p=&a0;或者或者 int*p=a;2010.3.2 通过指针引用数组元素通过指针引用数组元素1.指针指针p+i的含义:不是地址值的含义:不是地址值p增加增加i个个字节后的地址值,而是指字节后的地址值,而是指p向后移动向后移动i个个基类型元素后的地址值。基类型元素后的地址值。p-i,p+,p-都都有
17、类似的含义。有类似的含义。212.指针与数组的关系指针与数组的关系22数组元素在内存中连续存放,如果指针数组元素在内存中连续存放,如果指针p指向指向数组数组a,那么,那么,p+i指向数组指向数组a的第的第i个元素个元素ai。也就是也就是p+i=&ai,此时对,此时对ai的访问完全可以的访问完全可以转化为对转化为对*(p+i)的访问。的访问。数组与指针的关系:数组元素可以用下标访问数组与指针的关系:数组元素可以用下标访问也可以使用指针访问也可以使用指针访问。233.通过指针引用数组元素通过指针引用数组元素 n 数组元素的地址表示。数组元素的地址表示。假如:假如:p定义为指向数组定义为指向数组a的
18、指针。数组元素的指针。数组元素ai的地址可以表示为:的地址可以表示为:&ai,p+i,a+i。n 数组元素的访问数组元素的访问例如:数组元素例如:数组元素ai的访问可以是:的访问可以是:ai,*(p+i),*(a+i)。n 数组指针变量,数组名在许多场合甚至数组指针变量,数组名在许多场合甚至可以交换使用。可以交换使用。假如:假如:p=a,那么那么ai甚至可以表示为甚至可以表示为pi(指(指针变量带下标)针变量带下标)24注意:注意:数组名,数组指针变量使用时的区别:数组名,数组指针变量使用时的区别:数组名数组名是常量指针,它指向数组首地址,数组指针变量是常量指针,它指向数组首地址,数组指针变量
19、是变量,它的值可以改变。是变量,它的值可以改变。在不至于混淆的场合,在不至于混淆的场合,数组名,数组指针变量可以统称数组指针。数组名,数组指针变量可以统称数组指针。例如:例如:假设假设a、b是数组名,是数组名,p是同类型的数组是同类型的数组指针变量。指针变量。a+;*(a+);a=a+i;a=b;错误错误而而p+;*(p+);p=p+i;p=a;都是可以的。都是可以的。25小结:小结:引用数组元素可以采用两种方法:引用数组元素可以采用两种方法:(假设假设p=a)下标法:下标法:通过数组元素的序号(索引)来访问数组元素。通过数组元素的序号(索引)来访问数组元素。如如ai或或pi。指针法:指针法:
20、通过数组元素的地址访问数组元素。通过数组元素的地址访问数组元素。如如*(a+i),*(p+i)例:输出数组中的全部元素(参见书中例:输出数组中的全部元素(参见书中P212页)页)26注意:使用数组的指针变量,如果改变了其值,那么应当关注其当前指向的位置。必要时可以重置指针。参见书中(P214页)例10.6 仔细分析-转下页27输出数组输出数组a的的10个元素。个元素。程序:程序:main()int*p,i,a10;p=a;for(i=0;i10;i+)scanf(%d,p+);printf(n);for(i=0;i10;i+,p+)(p的值不对)的值不对)printf(%d,*p);28mai
21、n()int*p,i,a10;p=a;for(i=0;i10;i+)scanf(%d,p+);printf(n);p=a;for(i=0;i10;i+,p+)printf(%d,*p);此程序正确2910.3.3数组名作函数参数数组名作函数参数数组元素作函数参数与变量作函数参数一样,数组元素作函数参数与变量作函数参数一样,传递的是数组元素的值,改变形参的值,不传递的是数组元素的值,改变形参的值,不会更改数组元素的值。会更改数组元素的值。数组名作函数参数时,由于数组名代表数组首数组名作函数参数时,由于数组名代表数组首地址,因此,在函数调用时,是把数组首地地址,因此,在函数调用时,是把数组首地址传
22、送给形参。这样,实参数组和形参数组址传送给形参。这样,实参数组和形参数组共占同一段内存区域。从而在函数调用后,共占同一段内存区域。从而在函数调用后,实参数组的元素值可能会发生变化。实参数组的元素值可能会发生变化。30有种等价形式(本质上是一种,即指针有种等价形式(本质上是一种,即指针数据作函数参数):数据作函数参数):(1)形参、实参都用数组名)形参、实参都用数组名(2)形参、实参都用指针变量)形参、实参都用指针变量(3)形参用指针变量、实参用数组名)形参用指针变量、实参用数组名(4)形参用数组名、实参用指针变量)形参用数组名、实参用指针变量数组名作函数的参数,数组名作函数的参数,实参和形参之
23、间传实参和形参之间传送数组的首地址送数组的首地址,首地址可以用指针表示,首地址可以用指针表示,也可以用数组名表示。也可以用数组名表示。10.3.4 多维数组的指针多维数组的指针1.二维数组的指针二维数组的指针 假设有如下数组定义语句:假设有如下数组定义语句:int s34;(1)从)从2维数组角度看,数组名维数组角度看,数组名s代表数组的起始地址,代表数组的起始地址,是一个以行为单位进行控制的行指针:是一个以行为单位进行控制的行指针:s+i:行指针值,指向:行指针值,指向2维数组的第维数组的第i行。行。*(s+i):(列)指针值,指向第:(列)指针值,指向第i行第列(控制行第列(控制由行转为列
24、,但仍为指针)。由行转为列,但仍为指针)。*(*(s+i):数组元素:数组元素si0的值。的值。用用s作指针访问数组元素作指针访问数组元素sij的格式:的格式:*(*(s+i)j)(2)从)从1维数组角度看,数组名维数组角度看,数组名s和第和第1维下标的每一个维下标的每一个值,值,共同构成一组新的共同构成一组新的1维数组名维数组名s0、s1、s2,它们均由它们均由4个元素组成。个元素组成。32main()int a 3 5=1,2,3,4,5,6,7,8,9,10,11,12,13,14,15;int j,k,(*p)5;p=a;for(j=0;j3;j+)for(k=0;k5;k+)prin
25、tf(“%d”,*(*(p+j)+k);printf(“n”);2.二维数组的指针表示法二维数组的指针表示法P实际上是一个二级指针,必须对它施加两次实际上是一个二级指针,必须对它施加两次*运算,才能得运算,才能得到相应的数组元素值。到相应的数组元素值。3410.4 字符串字符串与与指针指针10.4.1、字符串的表、字符串的表示示形式形式 C语言中,有两种方式可以实现字符串:字符语言中,有两种方式可以实现字符串:字符数组、字符指针。数组、字符指针。参见书中P232页程序10.16和10.173536 从以上两个例子中,可以看到:从以上两个例子中,可以看到:1、字符数组和字符指针的概念不同。、字符
26、数组和字符指针的概念不同。2、字符指针指向字符串,而、字符指针指向字符串,而C语言中,字符串按数组方式处语言中,字符串按数组方式处理,因此,字符数组和字符指针的访问方式相同。例如,理,因此,字符数组和字符指针的访问方式相同。例如,均可以使用均可以使用%s格式控制符进行整体输入输出。但应注意,格式控制符进行整体输入输出。但应注意,如果不是字符数组,而是整型、实型等数字型数组,不能如果不是字符数组,而是整型、实型等数字型数组,不能用用%s,只能逐个元素处理。,只能逐个元素处理。37例例 将字符串将字符串a复制到字符串复制到字符串b。main()char a=I am a boy.“;char b2
27、0;int i;for(i=0;*(a+i)!=0;i+)*(b+i)=*(a+i);*(b+i)=0;printf(string a is:%sn,a);printf(string b is:%sn,b);38for(i=0;bi!=0;i+)printf(%c,bi);printf(n);例例 将字符串将字符串a复制到字符串复制到字符串b。(用指针处理用指针处理)main()char a=I am a boy.,b20,*p1,*p2;int i;p1=a;p2=b;for(;*p1!=0;p1+,p2+)39 *p2=*p1;*p2=0;printf(string a is:%sn,a)
28、;printf(string b is:%sn,b);for(i=0;bi!=0;i+)printf(%c,bi);printf(n);40二、字符串指针作函数参数二、字符串指针作函数参数将一个字符串从一个函数传递到另一个函数,将一个字符串从一个函数传递到另一个函数,可以使用传地址的方式,即用字符数组名或可以使用传地址的方式,即用字符数组名或字符指针变量作参数。有以下四种情况:字符指针变量作参数。有以下四种情况:实参实参 形参形参 数组名数组名 数组名数组名 数组名数组名 字符指针变量字符指针变量 字符指针变量字符指针变量 字符指针变量字符指针变量 字符指针变量字符指针变量 数组名数组名例例1
29、0.20 用函数调用实现字符串的复制。用函数调用实现字符串的复制。(1)用字符数组作参数。)用字符数组作参数。41Void copy_string(char from,char to)int i=0;while(fromi!=0)toi=fromi;i+;toi=0;main()char a=I am a teacher.;char b=you are a student.;printf(string_a=%sn string_b=%sn,a,b);copy_string(a,b);printf(string_a=%sn string_b=%sn,a,b);42main()函数可以改写为(使用
30、字符指针):函数可以改写为(使用字符指针):main()char*a=I am a teacher.;char*b=you are a student.;printf(string_a=%sn string_b=%sn,a,b);copy_string(a,b);printf(string_a=%sn string_b=%sn,a,b);(2)形参用字符指针)形参用字符指针。43Void copy_string(char*from,char*to)for(;*form!=0;from+,to+)*to=*from;*to=0;main()char*a=I am a teacher.;char*
31、b=you are a student.;printf(string_a=%snstring_b=%sn,a,b);copy_string(a,b);printf(string_a=%sn string_b=%sn,a,b);44字符数组字符数组 字符指针变量字符指针变量由若干元素组成,每个元素中放一个字符。由若干元素组成,每个元素中放一个字符。存放字符串的首地址。存放字符串的首地址。static char str=I love China!;char*a=I love China!;char str14;char*a;str=I love China!a=I love China!;字符数组
32、一个元素占一字节内存,且在编译时分配字符数组一个元素占一字节内存,且在编译时分配。指针变量中只可以放一个地址值(近指针指针变量中只可以放一个地址值(近指针=2字节,远指针字节,远指针=4 字节)。且编译时未指定字节)。且编译时未指定char str10;char*a;scanf(“%s”,str);scanf(“%s”,a);尚未指向任何尚未指向任何 变量变量字符数组名是地址常量字符数组名是地址常量 指针变量可以进行、等指针变量可以进行、等 运算运算不允许进行、等运算不允许进行、等运算 指针的变量的值允许改变指针的变量的值允许改变10.4.3、字符串指针变量与字符数组的区别、字符串指针变量与字
33、符数组的区别4510.510.5指向函数的指针变量指向函数的指针变量10.5.1 10.5.1 用函数指针变量调用函数用函数指针变量调用函数函数的指针:函数的入口地址(函数的首地址)。函数的指针:函数的入口地址(函数的首地址)。C C语语言规定函数的首地址就是函数名,所以函数名就是函言规定函数的首地址就是函数名,所以函数名就是函数的指针。数的指针。指向函数的指针变量:存放函数入口地址(函数指针)指向函数的指针变量:存放函数入口地址(函数指针)的变量,称为指向函数的指针变量。简称函数的指针的变量,称为指向函数的指针变量。简称函数的指针变量。变量。函数可以通过函数名调用,也可以通过函数指针调用。函
34、数可以通过函数名调用,也可以通过函数指针调用。通过函数指针实现函数调用的步骤:通过函数指针实现函数调用的步骤:1 1、指向函数的指针变量的定义:、指向函数的指针变量的定义:类型类型 (*函数指针变量名)函数指针变量名)()();例如例如 intint(*p)();p)();注意注意:两组括号()都不能少。:两组括号()都不能少。intint表示被指向的函数的类型,即被指向的函数的返表示被指向的函数的类型,即被指向的函数的返回值的类型。回值的类型。462 2、指向函数的指针变量的赋值,指向某个函数:、指向函数的指针变量的赋值,指向某个函数:函数指针变量名函数指针变量名=函数名;函数名;3 3、利
35、用指向函数的指针变量调用函数:、利用指向函数的指针变量调用函数:(*函数指针变量名)(实参表)函数指针变量名)(实参表)例:输入例:输入1010个数,求其中的最大值。个数,求其中的最大值。/*使用函数名调用函数使用函数名调用函数 */main()main()intint i,m,a10;i,m,a10;for(i=0;i10;i+)for(i=0;i10;i+)scanf scanf(%d,&ai);(%d,&ai);m=max(a);/m=max(a);/*函数调用格式:函数名函数调用格式:函数名(实参表实参表)*/printf printf(max=%dn,m);(max=%dn,m);4
36、7 int max(intint max(int *p)/p)/*max max在在1010个整数中选择最大个整数中选择最大值值 */int int i,t=i,t=*p;p;for(i=1;i10;i+)for(i=1;it)t=(p+i)t)t=*(p+i);(p+i);return t;return t;结果:结果:-52 87 29 79-32 94 23-112 46 67-52 87 29 79-32 94 23-112 46 67max=94max=94声明函数声明函数/*使用函数指针变量调用函数使用函数指针变量调用函数 */48 main()int i,m,a10,max(in
37、t*);/*declare func*/int(*pf)();/*define func pointer*/for(i=0;imax()*/m=(*pf)(a);/*call max*/printf(max=%dn,m);声 明声 明函数函数指针的定义:指针的定义:定义函数指针变量定义函数指针变量pfpf(返回整型数返回整型数)指针的初始化指针的初始化:函数指针函数指针pfpf指指向向maxmax指针的引用:指针的引用:调用函数指针调用函数指针pfpf指向的函数指向的函数maxmax49 int max(intint max(int *p)p)int int i,t=i,t=*p;p;for(
38、i=1;i10;i+)for(i=1;it)t=(p+i)t)t=*(p+i);(p+i);return t;return t;说明:说明:(1 1)定义函数指针变量时,两组括号()都不能少。如果)定义函数指针变量时,两组括号()都不能少。如果少了前面的一组括号少了前面的一组括号=返回值类型返回值类型 *函数名函数名()();-返回值为返回值为地址值(指针)的函数。地址值(指针)的函数。(2 2)函数指针变量的类型是被指向的函数的类型,即返回)函数指针变量的类型是被指向的函数的类型,即返回值类型。值类型。(3 3)函数指针的赋值,只要给出函数名,不必给出参数。)函数指针的赋值,只要给出函数名,
39、不必给出参数。(不要给出实参或形参)。(不要给出实参或形参)。(4 4)用指针变量调用函数时,)用指针变量调用函数时,(*函数指针函数指针)代替函数名。代替函数名。参数表与使用函数名调用函数一样。参数表与使用函数名调用函数一样。50(5 5)可以看出,定义的函数指针变量可以用于一类函数,)可以看出,定义的函数指针变量可以用于一类函数,只要这些函数返回值类型(函数类型)相同。只要这些函数返回值类型(函数类型)相同。函数可以通过函数名调用,也可以通过函数指针调用。函数函数可以通过函数名调用,也可以通过函数指针调用。函数指针常常用在函数需要作为函数参数的情况。指针常常用在函数需要作为函数参数的情况。
40、1010、5 5、2 2 用指向函数的指针作为函数的参数(常用于编制用指向函数的指针作为函数的参数(常用于编制“通用通用”的函数)的函数)函数的参数除了可以是变量、指向变量的指针,数组(实际函数的参数除了可以是变量、指向变量的指针,数组(实际是指向数组的指针)、指向数组的指针以外,还可以是函数是指向数组的指针)、指向数组的指针以外,还可以是函数的指针。的指针。函数的指针可以作为函数参数,在函数调用时可以将某个函函数的指针可以作为函数参数,在函数调用时可以将某个函数的首地址传递给被调用的函数,使这个被传递的函数在被数的首地址传递给被调用的函数,使这个被传递的函数在被调用的函数中调用调用的函数中调
41、用(看上去好象是将函数传递给一个函数)。(看上去好象是将函数传递给一个函数)。函数指针的使用在有些情况下可以增加函数的通用性,特别函数指针的使用在有些情况下可以增加函数的通用性,特别是在可能调用的函数可变的情况下。是在可能调用的函数可变的情况下。51 例:编制一个对两个整数例:编制一个对两个整数a,ba,b的通用处理函数的通用处理函数processprocess,要求根据调用,要求根据调用processprocess时指出的处时指出的处理方法计算理方法计算a a,b b两数中的大数、小数、和。两数中的大数、小数、和。解:解:int max(int,intint max(int,int););i
42、nt min(int,int int min(int,int););int add(int,int int add(int,int););int int add1(int);add1(int);main()main()intint a,b;a,b;printf printf(“enter two num to a,b:”);(“enter two num to a,b:”);scanf(%d%d,&a,&b);声明几个处理函数声明几个处理函数(只需要形参类型只需要形参类型)52printfprintf(max=%dn,process(a,b,max);/(max=%dn,process(a,b
43、,max);/*调用调用通用处理函数通用处理函数 */printf printf(min=%dn,process(a,b,min);(min=%dn,process(a,b,min);printfprintf(add=%dn,process(a,b,add);(add=%dn,process(a,b,add);printf(add1=%dn,process(a,b,add1);printf(add1=%dn,process(a,b,add1);int max(int x,intint max(int x,int y)return xy?x:y;/y)return xy?x:y;/*返回两数之中
44、较大的数返回两数之中较大的数 */int min(int x,intint min(int x,int y)return xy?x:y;/y)return xy)z=&x;else z=&y;if(xy)z=&x;else z=&y;return z;return z;结果:结果:enter two num to i,j:12 38enter two num to i,j:12 38 max=38max=3859 说明:说明:(1 1)mainmain函数从键盘获得两个整数函数从键盘获得两个整数i,ji,j(本例(本例1212,3838)。将)。将i,ji,j作为实参调用作为实参调用funfu
45、n。(2 2)通过虚实结合,)通过虚实结合,funfun函数的形参函数的形参x,yx,y获得了这获得了这两个整数(本例两个整数(本例1212,3838),将大数的地址返回(本),将大数的地址返回(本例是例是&y&y)。)。(3 3)返回的地址值赋值给)返回的地址值赋值给mainmain函数的指针变量函数的指针变量p,mainp,main函数打印函数打印p p指向的整型数,即指向的整型数,即y y的值。的值。1010、7 7 指针数组与指向指针的指针指针数组与指向指针的指针 1010、7 7、1 1指针数组指针数组 数组的指针:指向数组元素的指针。数组元素可以数组的指针:指向数组元素的指针。数组
46、元素可以是一般数据类型,也可以是数组、结构体等数据类是一般数据类型,也可以是数组、结构体等数据类型。数组指针的定义与数组元素指针的定义相同。型。数组指针的定义与数组元素指针的定义相同。60 指针数组:一个数组,如果其数组元素均为指针,指针数组:一个数组,如果其数组元素均为指针,那么此数组为指针数组。那么此数组为指针数组。一维指针数组的定义:类型名一维指针数组的定义:类型名 *数组名数组名 数组长度数组长度;例如:例如:intint *p4;p4;定义一个定义一个4 4个元素的数组个元素的数组p p,其中每个元素是一个整,其中每个元素是一个整型指针,也即数组型指针,也即数组p p是一个是一个4
47、4元素整型指针数组。元素整型指针数组。又如:又如:char char*p4;p4;定义一个定义一个4 4个元素的字符指针数组个元素的字符指针数组p p,其中每个数组,其中每个数组元素是一个字符指针,可以指向一个字符串。也就元素是一个字符指针,可以指向一个字符串。也就是说利用此字符指针数组可以指向是说利用此字符指针数组可以指向4 4个字符串。个字符串。指针数组用得最多的是指针数组用得最多的是“字符型指针数组字符型指针数组”,利用,利用字符指针数组可以指向多个长度不等的字符串,使字符指针数组可以指向多个长度不等的字符串,使字符串处理更加方便、灵活,节省内存空间。字符串处理更加方便、灵活,节省内存空
48、间。61 Name 使用二维字符数组存储多个字符串使用二维字符数组存储多个字符串(上图上图)指针数组指针数组name name 字符串字符串CProgram 0B ASIC 0C om puterEng lish 0W ordname0name1name2name3C ProgramBASICComputer EnglishWord62 使用字符型指针数组指向多个字符串使用字符型指针数组指向多个字符串(上页下图)(上页下图)使用字符型指针数组指向多个字符串与使用两维字符数组存使用字符型指针数组指向多个字符串与使用两维字符数组存储多个字符串的比较:储多个字符串的比较:(1 1)节省存储空间)节省
49、存储空间(二维数组要按最长的串开辟存储空间二维数组要按最长的串开辟存储空间)(2 2)便于对多个字符串进行处理,节省处理时间。(使用指)便于对多个字符串进行处理,节省处理时间。(使用指针数组排序各个串不必移动字符数据,只要改变指针指向的针数组排序各个串不必移动字符数据,只要改变指针指向的地址)地址)例例10-2710-27:将若干字符串按字母顺序由小到大输出。:将若干字符串按字母顺序由小到大输出。P249.P249.说明:说明:(1 1)main()main()中定义了指针数组中定义了指针数组namename,它有,它有4 4个元素,其个元素,其初 值 分 别 是初 值 分 别 是 C P r
50、 o g r a m ,B A S I C ,C o m p u t e r C P r o g r a m ,B A S I C ,C o m p u t e r English,WordEnglish,Word四个字符串常量的首地址。四个字符串常量的首地址。(2 2)函数函数sortsort使用选择排序法对指针数组指向的字符串使用选择排序法对指针数组指向的字符串进行排序(按字母顺序),在排序过程中不交换字符串本身,进行排序(按字母顺序),在排序过程中不交换字符串本身,只交换指向字符串的指针(只交换指向字符串的指针(nameknameinameknamei)。)。63(3 3)排序前后指针数