1、第第6章章 指针指针2 第第6 6章章 指针指针本章内容本章内容 6.2 变量的指针和指针变量变量的指针和指针变量 6.3 指针运算指针运算 6.4 一维数组与指针一维数组与指针 6.1 地址与指针地址与指针 6.5 二维数组与指针二维数组与指针3第第6 6章章 指针指针本章内容本章内容 6.7 指针变量作函数的参数指针变量作函数的参数 6.8 函数与指针函数与指针 6.9 指向指针的指针变量指向指针的指针变量 6.6 字符数组与指针字符数组与指针 6.10 指针应用举例指针应用举例46.1 6.1 地址与指针地址与指针v内存就是内部存储器,是由存储单元组成的。我内存就是内部存储器,是由存储单
2、元组成的。我们需要对它编号,这个编号就是内存地址。们需要对它编号,这个编号就是内存地址。v如果在程序中定义了一个变量,在对程序进行编如果在程序中定义了一个变量,在对程序进行编译时,系统就会给这个变量分配具体的物理内存译时,系统就会给这个变量分配具体的物理内存单元。单元。v虽然程序中是通过变量名来对内存单元进行存取虽然程序中是通过变量名来对内存单元进行存取操作的,其实程序经过编译以后已经将变量名转操作的,其实程序经过编译以后已经将变量名转换为变量的地址,对变量值的存取都是通过地址换为变量的地址,对变量值的存取都是通过地址进行的。这种按变量地址存取变量值的方式称为进行的。这种按变量地址存取变量值的
3、方式称为“直接访问直接访问”方式。方式。56.1 6.1 地址与指针地址与指针v对应对应“直接访问直接访问”还有另外一种称之为还有另外一种称之为“间接访间接访问问”的变量值存取方法,将变量的地址存放在另的变量值存取方法,将变量的地址存放在另一个变量中,通过存放变量地址的变量存取变量一个变量中,通过存放变量地址的变量存取变量的值。的值。v什么是指针呢?什么是指针呢?C C语言规定变量的地址就是变量的语言规定变量的地址就是变量的指针。对于变量指针。对于变量a a和存放变量地址的变量和存放变量地址的变量a_pointera_pointer来讲,一个用于存放变量的数值来讲,一个用于存放变量的数值258
4、258,一个用于存放变量的地址一个用于存放变量的地址20002000,在这里的,在这里的a_pointera_pointer就是指针变量。就是指针变量。66.1 6.1 地址与指针地址与指针v内存地址内存地址:内存中存储单元的编号:内存中存储单元的编号v变量地址变量地址 :系统分配给变量内存单元的起始地址:系统分配给变量内存单元的起始地址 变量地址起指向作用,因此形象称地址是变量的变量地址起指向作用,因此形象称地址是变量的指针指针,即即地址就是指针,指针就是地址地址就是指针,指针就是地址 变量地址,还隐含变量地址,还隐含变量类型信息变量类型信息v指针指针:一个变量的地址就是该变量的指针:一个变
5、量的地址就是该变量的指针v指针变量指针变量 :专门存放变量地址的变量:专门存放变量地址的变量76.1 6.1 地址与指针地址与指针200020042006200520012002200386.1 6.1 地址与指针地址与指针v变量的地址就是变量的指针。存放变量地址的变变量的地址就是变量的指针。存放变量地址的变量是指针变量,它用来指向另一个变量。量是指针变量,它用来指向另一个变量。v为了表示指针变量和它所指向的变量之间的联系,为了表示指针变量和它所指向的变量之间的联系,在程序中用在程序中用“*”符号表示指向,它实际执行的是符号表示指向,它实际执行的是“间接访问间接访问”运算,如果已定义运算,如果
6、已定义a_pointera_pointer为指针为指针变量且存放变量且存放a a变量的地址,则变量的地址,则*a_pointera_pointer是是a_pointera_pointer所指向的变量。所指向的变量。v若若a a变量存放的值为变量存放的值为3 3,则,则a a代表代表3 3,a_pointera_pointer代代表表a a的地址,的地址,*a_pointera_pointer代表代表a a即即3 3。9 6.2 6.2 变量的指针和指针变量变量的指针和指针变量本节内容本节内容 6.2.2 指针变量的引用指针变量的引用 6.2.1 指针变量的定义指针变量的定义106.2.1 6.
7、2.1 指针变量的定义指针变量的定义v定义指针变量的一般形式为定义指针变量的一般形式为v基类型基类型 *指针变量名指针变量名;v下面都是合法的定义:下面都是合法的定义:vfloat float*pfpf;vchar char*pcpc;v可以用赋值语句使一个指针变量得到另一个变量可以用赋值语句使一个指针变量得到另一个变量的地址,从而使它指向该变量。的地址,从而使它指向该变量。pointer_ipointer_i&i&i;pointer_jpointer_j&j&j;将变量将变量i i的地址存放到的地址存放到pointer_ipointer_i中,因此中,因此pointer_ipointer_i
8、就就“指向指向”了变量了变量i i。116.2.1 6.2.1 指针变量的定义指针变量的定义v在定义指针变量时要注意两点:在定义指针变量时要注意两点:在定义指针变量时,指针变量名前面加在定义指针变量时,指针变量名前面加“*”表示该表示该变量的类型为指针型变量。指针变量名是变量的类型为指针型变量。指针变量名是pointer_ipointer_i、pointer_jpointer_j,而不是,而不是*pointer_ipointer_i、*pointer_jpointer_j。但在但在使使用用指针变量时,指针变量名前面加指针变量时,指针变量名前面加“*”表示进行间接表示进行间接寻址操作。寻址操作。
9、如有:如有:i=3;i=3;j=j=*pointer_ipointer_i;则则j j的值为的值为3 3。一个指针变量只能指向同一个类型的变量,不能忽而指一个指针变量只能指向同一个类型的变量,不能忽而指向一个整型变量,忽而指向一个实型变量。向一个整型变量,忽而指向一个实型变量。126.2.2 6.2.2 指针变量的引用指针变量的引用v指针变量同普通变量一样,在使用之前要先定义,指针变量同普通变量一样,在使用之前要先定义,但需注意的是指针变量定义后,变量值不确定,但需注意的是指针变量定义后,变量值不确定,应用前还必须先赋予具体的值。未经赋值的指针应用前还必须先赋予具体的值。未经赋值的指针变量是不
10、能使用的。变量是不能使用的。v未经赋值的指针变量叫做未经赋值的指针变量叫做“野指针野指针”,它的初始,它的初始值是随机的。如果未经赋值而对它随机指向的内值是随机的。如果未经赋值而对它随机指向的内存单元进行操作,可能产生存单元进行操作,可能产生严重后果严重后果。v指针变量只能赋予地址,绝不能赋予任何其他数指针变量只能赋予地址,绝不能赋予任何其他数据,否则将引起错误。据,否则将引起错误。136.2.2 6.2.2 指针变量的引用指针变量的引用v6.2.2.1 6.2.2.1 指针变量的初始化指针变量的初始化v指针变量初始化的一般形式为:指针变量初始化的一般形式为:v基类型基类型 *指针名指针名=初
11、始地址值;初始地址值;v在在C C语言中,变量的地址是由编译系统分配的,对语言中,变量的地址是由编译系统分配的,对用户完全透明,用户不知道变量的具体地址。下用户完全透明,用户不知道变量的具体地址。下面是两个有关指针变量的运算符。面是两个有关指针变量的运算符。v&:取地址运算符:取地址运算符v*:指针运算符:指针运算符(或称间接访问运算符或称间接访问运算符)intint a;a;intint *p=&a;p=&a;/p/p指向指向a a*p=10;p=10;/相当于相当于 a=10;a=10;146.2.2 6.2.2 指针变量的引用指针变量的引用#include main()char x,y;
12、char*p1,*p2;x=a;y=b;p1=&x;/把变量x的地址赋给p1p2=&y;/把变量y的地址赋给p2printf(%c,%cn,x,y);printf(%c,%cn,*p1,*p2);156.2.2 6.2.2 指针变量的引用指针变量的引用v下面对下面对“&”&”和和“*”运算符再作些说明:运算符再作些说明:v如果已执行了语句如果已执行了语句plpl&x&x;&*plpl的含义是什么的含义是什么?先进行先进行*p1p1的运算,它就是变量的运算,它就是变量x x,再执行,再执行&运算。运算。因此,因此,&*plpl与与&x&x相同,即变量相同,即变量x x的地址。的地址。v*&x&x
13、的含义是什么的含义是什么?先进行先进行&x&x运算,得运算,得x x的地址,的地址,再进行再进行*运算,即运算,即&x&x所指向的变量,也就是变量所指向的变量,也就是变量x x。即即*&x&x和和*plpl的作用是一样的,它们都等价于变量的作用是一样的,它们都等价于变量x x,即即 *&x&x与与x x等价。等价。v如果如果p2p2&*p1p1;它的作用是将;它的作用是将&x(xx(x的地址的地址)赋给赋给p2p2,如果如果p2p2原来指向原来指向y y,经过重新赋值后它已不再指向,经过重新赋值后它已不再指向y y了,而指向了了,而指向了x x。166.2.2 6.2.2 指针变量的引用指针变
14、量的引用v(*p1)+p1)+相当于相当于x+x+。如果没有括号,就成为了。如果没有括号,就成为了*p1+p1+,它相当于,它相当于*(p1+)(p1+)。由于。由于+在在p1p1的右侧,的右侧,是是“后加后加”,因此先对,因此先对p1p1的原值进行的原值进行*运算,得到运算,得到x x的值,然后使的值,然后使p1p1的值改变,这样的值改变,这样p1p1不再指向不再指向x x了。了。176.2.2 6.2.2 指针变量的引用指针变量的引用#include main()int*p1,*p2,*p,x,y;scanf(%d,%d,&x,&y);p1=&x;p2=&y;if(xy)p=p1;p1=p
15、2;p2=p;printf(x=%d y=%dn,x,y);printf(min=%d max=%dn,*p1,*p2);186.2.2 6.2.2 指针变量的引用指针变量的引用v6.2.2.2 6.2.2.2 指针变量的赋值指针变量的赋值vint xint x;vint int*p p;v若需要通过指针变量若需要通过指针变量p p来操作来操作x x,那么可以先让,那么可以先让p p指指向向x x,这只要将,这只要将x x的地址赋予的地址赋予p p p=&x;p=&x;196.2.2 6.2.2 指针变量的引用指针变量的引用v在对指针变量赋值时,要注意以下问题:在对指针变量赋值时,要注意以下问
16、题:v在将一个普通变量的地址赋值给指针变量时,在将一个普通变量的地址赋值给指针变量时,要注意普通变量,必须先定义,再使用。要注意普通变量,必须先定义,再使用。v不能将一般的普通变量,例如整型变量赋给指不能将一般的普通变量,例如整型变量赋给指针变量,指针变量也不能赋给普通变量;针变量,指针变量也不能赋给普通变量;v可以将一个指针的值赋给另一个指针变量;可以将一个指针的值赋给另一个指针变量;v可以为一个指针赋值为可以为一个指针赋值为NULLNULL。intint *p=NULL;p=NULL;避免避免对对没有没有被初始化被初始化指针变量的非法指针变量的非法引用引用 voidvoid指针指针 例例
17、void void *p p 不指定不指定p p是指向哪一种类型数据是指向哪一种类型数据的指针变的指针变量量20 6.3 6.3 指针运算指针运算本节内容本节内容 6.3.2 指针的逻辑运算指针的逻辑运算 6.3.1 指针的算数运算指针的算数运算216.3.1 6.3.1 指针的算数运算指针的算数运算v指针除了可以参与赋值和间接访问之外,只能进指针除了可以参与赋值和间接访问之外,只能进行加减运算和比较运算。在这些运算中,基类型行加减运算和比较运算。在这些运算中,基类型起着决定性的作用。起着决定性的作用。v6.3.1.1 6.3.1.1 自加和自减运算自加和自减运算v指针变量可以进行自加和自减运
18、算。指针变量可以进行自加和自减运算。float xfloat x,*p p;p=&xp=&x;v假定变量假定变量x x的内存起始地址为的内存起始地址为20002000,现在进行如下,现在进行如下运算:运算:p+p+;但运算后但运算后p p的值并不是的值并不是20012001,而是,而是2004 2004 226.3.1 6.3.1 指针的算数运算指针的算数运算v6.3.1.2 6.3.1.2 与自加和自减相关的运算与自加和自减相关的运算 float xfloat x,y y,*p p;p=&xp=&x;假定假定x x,y y在内存中连续存储,且在内存中连续存储,且x x的内存起始地址为的内存起
19、始地址为20002000,借此我们讨论几种常见的指针运算。,借此我们讨论几种常见的指针运算。v*p+p+和和*(p+)(p+)由于由于+运算与运算与*运算优先级别相同,但结合次序都是由运算优先级别相同,但结合次序都是由右至左,故这二个表达式具有相同含义。又因为表达式右至左,故这二个表达式具有相同含义。又因为表达式p+p+的值为的值为p p加加1 1运算之前的值,因此,此表达式等同于运算之前的值,因此,此表达式等同于变量变量x x。不过,在计算完此表达是后,。不过,在计算完此表达是后,p p加加1 1,指向,指向y y。236.3.1 6.3.1 指针的算数运算指针的算数运算v*+p+p和和*(
20、+p)(+p)这是两个完全等同的表达式。因为表达式这是两个完全等同的表达式。因为表达式+p+p的值为的值为p p加加1 1运算后的值,等于运算后的值,等于&y&y,指向,指向y y,因此原表达式等同于变,因此原表达式等同于变量量y y。v(*p)+p)+由于变量由于变量*p p与变量与变量x x等价,此表达式相当于等价,此表达式相当于x+x+。v+(+(*p)p)此表达式与此表达式与+x+x等价,表达式计算后,等价,表达式计算后,p p的值不变。的值不变。246.3.1 6.3.1 指针的算数运算指针的算数运算v6.3.1.3 6.3.1.3 加减算术运算加减算术运算v指针只可以与指针和整数进
21、行部分加减算术运算。指针只可以与指针和整数进行部分加减算术运算。指针与整数的加减法指针与整数的加减法 指针可以与整数进行加减法运算,结果仍是指针。指针可以与整数进行加减法运算,结果仍是指针。p=p+1p=p+1;p+p+;两者作用相同,相当于指针移过一个两者作用相同,相当于指针移过一个由基类型所定义的位移量。由基类型所定义的位移量。整数与指针的加减法整数与指针的加减法 一个整数与指针的加减法结果仍是指针,但整数不能与一个整数与指针的加减法结果仍是指针,但整数不能与指针进行减法运算,即类似指针进行减法运算,即类似5-p5-p形式的表达式是错误的。形式的表达式是错误的。指针与指针的加减法指针与指针
22、的加减法 两个指针不能进行加法运算,结果没有意义。两个指针两个指针不能进行加法运算,结果没有意义。两个指针的减法是允许的,但结果不再是指针而是一个整数,表的减法是允许的,但结果不再是指针而是一个整数,表示两个地址之间的距离。示两个地址之间的距离。256.3.2 6.3.2 指针的逻辑运算指针的逻辑运算v指针的逻辑运算相对简单,可以使用关系运算符指针的逻辑运算相对简单,可以使用关系运算符比较两个指针的大小,但通常是在两个指针指向比较两个指针的大小,但通常是在两个指针指向同一目标,如一个数组或一内存块时才使用。特同一目标,如一个数组或一内存块时才使用。特别的,可以将一个指针与别的,可以将一个指针与
23、0 0或或NULLNULL进行比较,以测进行比较,以测试该指针是否已指向某一确定的内存地址。试该指针是否已指向某一确定的内存地址。26 6.4 6.4 一维数组与指针一维数组与指针本节内容本节内容 6.4.2 指向数组的指针变量的运算指向数组的指针变量的运算 6.4.1 通过指针引用一维数组元素通过指针引用一维数组元素276.4 6.4 一维数组与指针一维数组与指针1 1200020003 35 520042004 20082008a0a0 a1a1 a2a2=20002000a a数组代表类型相同、连续存放数组代表类型相同、连续存放连续连续数组名代表地址数组名代表地址地址地址数组名代表常量数
24、组名代表常量常量常量286.4.1 6.4.1 通过指针引用一维数组元素通过指针引用一维数组元素vintint a10 a10;*p p;v因为数组因为数组a a为为intint型,所以指向该数组的指针变量型,所以指向该数组的指针变量也应该为也应该为intint型的指针变量。下面两种对指针变量型的指针变量。下面两种对指针变量赋值的方法是一样的:赋值的方法是一样的:vp=&a0;p=&a0;或或 p=ap=a;v表示把表示把a0a0元素的地址赋给指针变量元素的地址赋给指针变量p p。或者说。或者说p p指向指向a a数组的第数组的第0 0号元素。号元素。vp p,a a,&a0&a0都指向同一单
25、元,它们都是数组都指向同一单元,它们都是数组a a的的首地址,也是数组首地址,也是数组a a的的0 0号元素号元素a0a0的首地址。但的首地址。但需要注意的是:需要注意的是:p p是变量,而是变量,而a a和和&a0&a0都是常量,都是常量,所以不能进行所以不能进行a+a+或或+a+a之类的操作。之类的操作。296.4.1 6.4.1 通过指针引用一维数组元素通过指针引用一维数组元素v在在C C语言中,如果指针变量语言中,如果指针变量p p已指向数组中的一个已指向数组中的一个元素,则元素,则p+1p+1指向同一个数组中的下一个元素。指向同一个数组中的下一个元素。v如果如果p p的初值为的初值为
26、a a,则,则p+ip+i和和a+ia+i就是就是aiai 的地址,的地址,即它们是指向即它们是指向a a数组的第数组的第i i个元素;个元素;v*(p+ip+i)和)和*(a+ia+i)就是)就是p+ip+i或或a+ia+i所指向的数组所指向的数组元素,即元素,即aiai;v指向数组的指针变量也可以带下标,例如指向数组的指针变量也可以带下标,例如pipi 与与*(p+ip+i)等价。)等价。306.4.1 6.4.1 通过指针引用一维数组元素通过指针引用一维数组元素v所以数组元素的引用可以有以下两种表示方法:所以数组元素的引用可以有以下两种表示方法:v下标法,即用下标法,即用aiai 形式访
27、问数组元素形式访问数组元素v指针法,即采用指针法,即采用*(a+ia+i)或)或*(p+ip+i)形式,用)形式,用间接访问的方法来访问数组元素,其中间接访问的方法来访问数组元素,其中a a是数组名,是数组名,p p是指向数组的指针变量,其初始值是指向数组的指针变量,其初始值p=ap=a。316.4.1 6.4.1 通过指针引用一维数组元素通过指针引用一维数组元素for(i=0;i 3;i+)for(i=0;i 3;i+)1 1200020003 35 52 20 01 1a a20042004 20082008 printf(%dnprintf(%dn,aiai););*(a+ia+i)=2
28、0002000数组恒等式:数组恒等式:aiai *(a+ia+i)326.4.1 6.4.1 通过指针引用一维数组元素通过指针引用一维数组元素for(i=0;i 3;i+)for(i=0;i 3;i+)1 1200020003 35 52 20 01 1a a20042004 20082008printf(%dnprintf(%dn=20002000p pp=a;p=a;,aiai););,pipi););*(p+ip+i)336.4.1 6.4.1 通过指针引用一维数组元素通过指针引用一维数组元素指针是数组名指针是数组名数组名是指针数组名是指针指针是地址指针是地址346.4.1 6.4.1
29、通过指针引用一维数组元素通过指针引用一维数组元素1 1200020003 35 52 20 01 1a a20042004 20082008printf(%dprintf(%d n,n,p0p0););=20002000p pp=a+1;p=a+1;printf(%dprintf(%d n,n,*(p+0)(p+0););printf(%d,%dprintf(%d,%d n,n,p1p1,p-1p-1););356.4.1 6.4.1 通过指针引用一维数组元素通过指针引用一维数组元素a0a0a1a1a2a2a a&a0,a&a0,a&a2,a+2&a2,a+2地址地址a0,a0,*a,a,*(
30、a+0)(a+0)a2,a2,*(a+2)(a+2)数值数值20002000 20042004 20082008366.4.2 6.4.2 指向数组的指针变量的运算指向数组的指针变量的运算v6.4.2.1 6.4.2.1 指向数组的指针变量的自加和自减指向数组的指针变量的自加和自减 intint a10 a10,*p p;p=ap=a;v进行如下运算:进行如下运算:p+p+;v则指向数组的指针变量则指向数组的指针变量p p指向了移过一个指向了移过一个intint类型类型所定义的位移量,即所定义的位移量,即p p指向变量指向变量a1a1的地址。我们的地址。我们可以得出这样一个结论:指向数组的指针
31、变量进可以得出这样一个结论:指向数组的指针变量进行的自加运算等同于使指针变量指向数组的下一行的自加运算等同于使指针变量指向数组的下一个数组元素。同样适用于个数组元素。同样适用于+p+p,p-p-和和-p-p。376.4.2 6.4.2 指向数组的指针变量的运算指向数组的指针变量的运算v6.4.2.2 6.4.2.2 指向数组的指针变量的加减算术运算指向数组的指针变量的加减算术运算 指向数组的指针变量与整数进行加减运算时,相当于指向数组的指针变量与整数进行加减运算时,相当于进行若干个自加或者自减预算,结果为指针变量指向相进行若干个自加或者自减预算,结果为指针变量指向相应的数组元素。应的数组元素。
32、一个整数与指向数组的指针变量相加的结果和前边讨一个整数与指向数组的指针变量相加的结果和前边讨论的指向数组的指针变量与整数相加效果一样,但是整论的指向数组的指针变量与整数相加效果一样,但是整数不能与指针进行减法运算。数不能与指针进行减法运算。两个指向同一数组的指针变量可以进行相减,但结果两个指向同一数组的指针变量可以进行相减,但结果是一个整数,为两个数组元素之间的距离(即两个地址是一个整数,为两个数组元素之间的距离(即两个地址之间的距离之间的距离,注意这个结果是以指针的基类型为单位注意这个结果是以指针的基类型为单位的)。的)。38数组与指针数组与指针v输出数组输出数组a9a9中的全部元素中的全部
33、元素#include void main()int a9=1,2,3,4,5,6,7,8,9;int*p=a,i;for(i=0;i9;i+)printf(%4d,*(a+i);printf(n);for(i=0;i9;i+)printf(%4d,*p+);printf(n);39 6.5 6.5 二维数组与指针二维数组与指针本节内容本节内容 6.5.2 通过指针引用二维数组元素通过指针引用二维数组元素 6.5.3 指针数组指针数组 6.5.1 二维数组元素的地址二维数组元素的地址406.5.1 6.5.1 二维数组元素的地址二维数组元素的地址v我们定义二维数组我们定义二维数组“intint
34、b34 b34;”v可以认为可以认为b0b0、b1b1、b2b2、b3b3是它的各个元是它的各个元素,采用指针的表示,就是素,采用指针的表示,就是*b b、*(b+1b+1)、)、*(b+2b+2)、)、*(b+3b+3);只不过这些);只不过这些“元素元素”都是一都是一维数组而已。维数组而已。v指针指针b b的基类型是一维数组类型,且指针的运算是的基类型是一维数组类型,且指针的运算是以基类型为单位的,以基类型为单位的,b+1b+1将第二行的一维数组。将第二行的一维数组。b+kb+k是指向第是指向第k+1k+1个一维数组类型的指针,故个一维数组类型的指针,故*(b+kb+k)表示第)表示第k+
35、1k+1行的一维数组。行的一维数组。vbkbk 和和*(b+kb+k)也是指针)也是指针。416.5.2 6.5.2 通过指针引用二维数组元素通过指针引用二维数组元素v由此可见,指针由此可见,指针b b、b0b0和和*b b都是指针且都指向数都是指针且都指向数组的首地址,但它们的基类型不同:组的首地址,但它们的基类型不同:v因为因为b b的的“元素元素”为一维数组,故为一维数组,故b b是指向一维是指向一维数组的指针而不是指向整数的指针。当然,一维数组的指针而不是指向整数的指针。当然,一维数组名也是指针,故数组名也是指针,故b b本质上是一种指向指针的指本质上是一种指向指针的指针。针。vb0b
36、0是利用数组是利用数组b b的下标引用得到的变量,的下标引用得到的变量,*b b是是指针指针b b间接引用得到的变量,间接引用得到的变量,b0b0和和*b b都是都是b b的第的第一个元素,都表示第一行的一维数组名,此刻它一个元素,都表示第一行的一维数组名,此刻它的元素为的元素为intint类型,故类型,故b0b0和和*b b是指向是指向intint类型的类型的指针。指针。426.5.2 6.5.2 通过指针引用二维数组元素通过指针引用二维数组元素vintint b34 b34,*p p;vp=bp=b;v语句语句“p=b”p=b”表示把二维数组中表示把二维数组中b00b00元素的地元素的地址
37、赋给指针变量址赋给指针变量p p。p p指向数组指向数组b b的第一行第的第一行第0 0号元号元素,即第一个元素。素,即第一个元素。v对于二维数组中第对于二维数组中第i+1i+1行第行第j+1j+1列的元素即列的元素即bijbij 我们可以看作是我们可以看作是b b数组中数组中“元素元素”bibi 的的j j号元素,号元素,bibi 是一个一维数组,可以看作是一个指针,指是一个一维数组,可以看作是一个指针,指向一维数组向一维数组bi0bi0的首地址,则元素的首地址,则元素bijbij 的的地址为地址为bi+jbi+j,其基类型为,其基类型为intint类型;类型;v再看数组再看数组b b,其,
38、其“元素元素”bibi 的的地址为的的地址为b+ib+i,但其但其基类型为数组类型。基类型为数组类型。436.5.2 6.5.2 通过指针引用二维数组元素通过指针引用二维数组元素v如果将二维数组名如果将二维数组名a a看成一个行地址看成一个行地址(第(第0 0行的地址),行的地址),则则a+ia+i代表二维数代表二维数组组a a的第的第i i行的地址,行的地址,aiai 可看成一个可看成一个列地址,即第列地址,即第i i行第行第0 0列的地址。列的地址。行地址行地址a a每次加每次加1 1,表示指向下一行,表示指向下一行 列地址列地址aiai 每次加每次加1 1,表示指向下一列,表示指向下一列
39、446.5.2 6.5.2 通过指针引用二维数组元素通过指针引用二维数组元素456.5.2 6.5.2 通过指针引用二维数组元素通过指针引用二维数组元素v对二维数组对二维数组 intint a34 a34,有有 a-a-二维数组的首地址,即第二维数组的首地址,即第0 0行的首地址行的首地址 a+ia+i-第第i i行的首地址行的首地址 aiai *(a+ia+i)-第第i i行第行第0 0列的元素地址列的元素地址 ai+jai+j *(a+i)+ja+i)+j-第第i i行第行第j j列的元素地址列的元素地址*(ai+jai+j)*(*(a+i)+ja+i)+j)aijaij 466.5.2
40、6.5.2 通过指针引用二维数组元素通过指针引用二维数组元素va+ia+i=&=&aiai=aiai=*(a+ia+i)=&ai0,)=&ai0,值相等,含义不同值相等,含义不同 a+ia+i&aiai,表示第表示第i i行首地址,指向行行首地址,指向行 aiai *(a+ia+i)&ai0&ai0,表示第表示第i i行第行第0 0列元素列元素地址,指向列地址,指向列476.5.2 6.5.2 通过指针引用二维数组元素通过指针引用二维数组元素二维数组两次取值是数值,二维数组两次取值是数值,其余情况是地址。其余情况是地址。*a或或a“*”与数组名紧密相连,与数组名紧密相连,表示第表示第0行。行。
41、*a*等价于等价于 ,都表示取,都表示取值。值。在一次取值之前加行在一次取值之前加行(a+i),一次取值之后加列一次取值之后加列(*a+j)。判断二维判断二维数组地址数组地址与值四项与值四项基本原则基本原则486.5.2 6.5.2 通过指针引用二维数组元素通过指针引用二维数组元素&a23,&a23,*(a+2)+3,a2+3(a+2)+3,a2+3 地址地址&a20,&a20,a+2,a+2,*(a+2),(a+2),*(a+2)+0,(a+2)+0,a2,a2+0a2,a2+0地址地址&a03,&a03,*a+3,a+3,*(a+0)+3,a0+3(a+0)+3,a0+3 地址地址&a00
42、,&a00,a,a+0,a,a+0,*a,a,*(a+0),(a+0),*a+0,a+0,*(a+0)+0,a0,a0+0(a+0)+0,a0,a0+0地址地址496.5.2 6.5.2 通过指针引用二维数组元素通过指针引用二维数组元素a23,a23,*(*(a+2)+3),(a+2)+3),*(a2+3)(a2+3)数值数值a20,a20,*(a+2),(a+2),*(*(a+2)+0),(a+2)+0),*a2,a2,*(a2+0)(a2+0)数值数值a03,a03,*(*a+3),a+3),*(*(a+0)+3),(a+0)+3),*(a0+3)(a0+3)数值数值a00,a00,*a,
43、a,*(*a+0),a+0),*(a+0),(a+0),*(*(a+0)+0),(a+0)+0),*a0,a0,*(a0+0)(a0+0)数值数值506.5.2 6.5.2 通过指针引用二维数组元素通过指针引用二维数组元素v输出数组输出数组a33a33中的全部元素中的全部元素#include void main()int a33=1,2,3,4,5,6,7,8,9;int *p;for(p=a0;pa0+9;p+)/当作一维数组当作一维数组 if(p-a0)%3=0)printf(n);printf(%4d,*p);516.5.3 6.5.3 指针数组指针数组v一个数组,若其元素均为指针类型数
44、据,称为指一个数组,若其元素均为指针类型数据,称为指针数组,也就是说,指针数组中的每一个元素都针数组,也就是说,指针数组中的每一个元素都相当于一个指针变量。一维指针数组的定义形式相当于一个指针变量。一维指针数组的定义形式为为v类型名类型名 *数组名数组名 数组长度数组长度;例如:例如:intint *p4p4;v由于由于 比比*优先级高,因此优先级高,因此p p先与先与44结合,形成结合,形成p4p4形式,这显然是数组形式,它有形式,这显然是数组形式,它有 4 4个元素。个元素。然后再与然后再与p p前面的前面的“*”结合,结合,“*”表示此数组是表示此数组是指针类型的,每个数组元素指针类型的
45、,每个数组元素(相当于一个指针变量相当于一个指针变量)都可指向一个整型变量。都可指向一个整型变量。526.5.3 6.5.3 指针数组指针数组v为什么要用到指针数组呢为什么要用到指针数组呢?这是因为它比较适合于这是因为它比较适合于用来指向若干个字符串,使字符串处理更加方便用来指向若干个字符串,使字符串处理更加方便灵活。灵活。v可以分别定义一些字符串,然后用指针数组中的可以分别定义一些字符串,然后用指针数组中的元素分别指向各字符串。如果想对字符串排序,元素分别指向各字符串。如果想对字符串排序,不必改动字符串的位置,只需改动指针数组中各不必改动字符串的位置,只需改动指针数组中各元素的指向元素的指向
46、(即改变各元素的值,这些值是各字符即改变各元素的值,这些值是各字符串的首地址串的首地址)。这样,各字符串的长度可以不同,。这样,各字符串的长度可以不同,而且移动指针变量的值而且移动指针变量的值(地址地址)要比移动字符串所要比移动字符串所花的时间少得多。花的时间少得多。536.5.3 6.5.3 指针数组指针数组v指针数组指针数组v数组元素为指针,数组元素为指针,用于处理二维数组或多个字符串用于处理二维数组或多个字符串数据类型数据类型 *数组名数组名 数组长度数组长度;char*a4=Fortran,Lisp,Basic,NULLL i s p 0F o r t r a n 0B a s i c
47、 0a0a1a2a3054数组与指针数组与指针v例例6.56.5:将:将5 5个英文人名按字母顺序排列后输出个英文人名按字母顺序排列后输出#include#include void sort(char*name,int n)char*p;int i,j,k;for(i=0;in-1;i+)/比较法排序比较法排序 k=i;for(j=i+1;j0)k=j;if(k!=i)/只进行一次交换只进行一次交换 p=namei;namei=namek;namek=p;void main()char*name=TOM,JHON,KATE,JACSON,MACEAL;int n=5,i;sort(name,n
48、);for(i=0;in;i+)printf(%sn,namei);556.6 6.6 字符数组与指针字符数组与指针v在在C C语言程序中,可以用两种方法访问一个字符串。语言程序中,可以用两种方法访问一个字符串。用字符数组存放一个字符串,然后输出该字符串。用字符数组存放一个字符串,然后输出该字符串。用字符指针指向一个字符串。可以不定义字符数组,用字符指针指向一个字符串。可以不定义字符数组,而定义一个字符指针。用字符指针指向字符串中的字符。而定义一个字符指针。用字符指针指向字符串中的字符。#includevoid main()char *string=I love China!;puts(str
49、ing);566.6 6.6 字符数组与指针字符数组与指针#include void main()char a=I am a boy.,b20;int i;for(i=0;ai!=0;i+)/用循环实现复制*(b+i)=*(a+i);*(b+i)=0;printf(string a is%sn,a);/输出两个字符串printf(string b is);for(i=0;bi!=0;i+)printf(%c,bi);printf(n);576.7 6.7 指针变量作函数的参数指针变量作函数的参数#include void max_min(int*x,int n,int*max,int*min)
50、;main()int i,a10=52,14,21,56,37,28,45,75,66,38,max,min;for(printf(The original array=),i=0;i10;i+)printf(%3d,ai);max_min(a,10,&max,&min);printf(nmax=%d min=%dn,max,min);void max_min(int*x,int n,int*max,int*min)int i;*max=*min=*x;for(i=1;in;i+,x+)if(*max*x)*min=*x;586.8 6.8 函数与指针函数与指针本节内容本节内容 6.8.2 函