资源描述
单击此处编辑母版标题样式,单击此处编辑母版文本样式,第二级,第三级,第四级,第五级,*,QTECH,第,9,章 指针和数组,数组中地址的概念,数组的指针变量,指针数组,多级指针变量,在进行数据处理时,指针和数组都可以处理内存中连续存放的一系列数据,在访问内存时采用统一的地址计算方法。,C,中规定数组名是地址常量,该常量值等于数组首元素的地址(简称数组首地址),它的类型是指向数组元素的指针类型,即数组名是指向该数组首元素的指针常量。,9.1,数组中地址的概念,一维数组中的地址,二维数组中的地址,多维数组中的地址,9.1.1,一维数组中的地址,对于一维数组,数组名就是该数组的起始地址,称之为一维地址。从这个意义上讲,一维数组的元素可以看成是,0,维地址。,例,:,一维数组,a,:,int,a5;,则数组元素为,a0,a4,,即:,a=(a0,a1,a2,a3,a4),数组名是存放地址值的,指针常量名,,定义数组时的类型即是此指针常量的基类型;,其地址值是数组所占一串连续存储单元的起始地址,即地址值是第一个元素的地址;,其值不可改变。,例如,:,int,a10,*p,x;,a=,p=,p=a;,数组名与指针,9.1.2,二维数组中的地址,二维数组名也是该数组的起始地址,称之为二维地址。一个,M,行,N,列的二维数组,a,如下:,一个二维数组是由若干行构成的,每个行是一个一维数组,也就是说,一个二维数组可以看成是由若干个元素构成,只不过这些元素又都是一维数组。例如,可将,a,看成:,a=(a0,a1,aN-1),而:,a,i,=(a,i,0,a,i,1,a,i,N-1),,其中,0,i,M-1,这样,,a,是一个,2,维地址,每个,a,i,(,0,i,M-1,)是,1,维地址,每个,a,i,j,(,0,i,M-1,,,0,j,N-1,)是,0,维地址。,例如,对于以下二维数组,a,:,int,a34=1,2,3,4,5,6,7,8,9,10,11,12;,其中地址关系如下图所示,说明如下:,数组名,a,是二维数组的起始地址,,a0,是它们的第一个,1,维元素(也表示该一维数组的起始地址),所以,a,、,a0,、,&a0,、,&a00,的地址值相等。但,a,是,2,维地址,,a0,是,1,维地址,,&a0,是,2,维地址(,1,维地址的地址为,2,维地址,)、,&a00,是,1,维地址。,二维数组元素的地址的五种表示方法,&aij,ai+j,*(a+i)+j,&a00+3*i+j,a0+3*i+j,通过地址引用二维数组元素,aij,*(ai+j),*(*(a+i)+j),*(&a00+3*i+j),(*(a+i)j,int,a23;,a+i,表示,i,号元素(,1,维数组)的地址,,ai,是数组,a,的,i,号元素(也是其首地址),所以,a+i,、,ai,、,&,ai,、,&ai0,的地址值相等。但,a+i,是,2,维地址,,ai,是,1,维地址,,&,ai,是,2,维地址、,&ai0,是,1,维地址。,ai+j,表示,aij,元素的地址,所以,ai+j,与,&aij,的地址值相等。也可以通过地址值推算得到这个关系,,ai+j,=(,a+i,*,sizeof(type)+j,是一个,1,维地址表达式,有:,*,(,ai+j,)=*(,a+i,*,sizeof(type)+j,)=*(,a+i,*,sizeof(type)+j,*,sizeof(type,)=*(,a+(i+j,)*,sizeof(type,)=,aij,。,&ai+j,不是,aij,元素的地址,因为,&ai,是,2,维地址,,&ai+j,为,a,的一维元素,ai+j,的地址。也就是说,尽管,ai,与,&ai,的地址值相等,但它们表示不同的地址含义,所以,ai+j,与,&ai+j,是不同的。,9.1.3,多维数组中的地址,以三维数组为例加以讨论。三维数组名称之为,3,维地址。例如:,int,a232=1,2,3,4,5,6,7,8,9,10,11,12;,可将,a,看成两个,2,维数组元素组成的:,a=(a0,a1),/*a,为,3,维地址*,/,每个二维数组元素看成是由,3,个一维数组元素组成的:,a0=(a00,a01,a02)/*a0,为,2,维地址*,/,a1=(a10,a11,a12)/*a1,为,2,维地址*,/,而每个一维数组元素又可以看成是由,3,个,0,维元素组成的:,a00=(a000,a001)/*a00,为,1,维地址*,/,a01=(a010,a011)/*a01,为,1,维地址*,/,a02=(a020,a021)/*a02,为,1,维地址*,/,a10=(a100,a101)/*a10,为,1,维地址*,/,a11=(a110,a111)/*a11,为,1,维地址*,/,a12=(a120,a121)/*a12,为,1,维地址*,/,从中看到,,a,为,3,维地址,,a0,a1,为,2,维地址,,a00,a12,为,1,维地址,,a000,a121,为,0,维地址元素。,其中地址关系如下图所示,说明如下:,a,、,a0,、,&a0,、,a00,、,&a00,、,&a000,都为数组,a,的起始地址,它们的地址值相等。但,a,是,3,维地址,,a0,是,2,维地址,,&a0,是,3,维地址,,a00,是,1,维地址,,&a00,是,2,维地址,,&a000,是,1,维地址。,a+i,表示,i,号元素(,2,维数组)的地址,,ai,是数组,a,的,i,号元素(也是其首地址),所以,a+i,、,ai,、,&,ai,、,&ai0,的地址值相等。但,a+i,是,3,维地址,,ai,是,2,维地址,,&,ai,是,3,维地址、,&ai0,是,2,维地址。,ai+j,表示,aij,元素的地址(,2,维地址),所以,ai+j,与,&,aij,的地址值相等。,aij+k,表示,aijk,元素的地址(,1,维地址),所以,aij+k,表示,aijk,的地址值相等。,9.2,数组的指针变量,9.2.1,一维数组的指针变量,1.,一维数组指针变量的定义格式,一维数组指针变量的定义格式如下:,基类型*指针变量,;,例如,有如下定义:,int,a5,*pa=a;,/*a,为一维数组,,pa,为数组,a,的指针变量*,/,其中,,pa=a,不是把,a,的所有元素赋给,pa,,而是让,pa,指向,a,数组的,0,号元素,一个指针变量任一时刻只能指向一个元素。,2.,通过数组指针变量引用数组元素,一旦定义了一维数组的指针变量,该数组指针变量可以像数组名一样使用,且可以在数组元素中移动。,例如:,int,a10,*p=a;,则 可通过以下方式给数组赋值。,for(k,=0;k10;k+),p=,a+k,;,scanf(“%d”,p,);,for(k=0;k10;k+),scanf(“%d”,a+k,);,for(,p,=,a,k,=0;k10;k+),scanf(“%d”,p,);p+;,for(,p=a,k=0;k10;k+),scanf(“%d”,p,+);,for(,p=a,k=0;p-a10;p+),scanf(“%d”,p,);,p+,a+k,的含义?等价于,a+k*j,,,j,是基类型所占存储单元。,int,*p,s10,i;,p=s;,数组元素,si,si,*(s+i),*(p+i),pi,s+;,s=p;,p=,p+;,p=s;,p=,1.,已知指针,p,的指向,则执行语句,*,p+,;,后,*p,的值是,A 20 B 30 C21 D31,10,20,30,40,50,a0,a1,a2,a3,a4,p,2.,已知指针,p,的指向,则表达式,*,+p,的值是,A 20 B 30 C21 D31,3.,已知指针,p,的指向,则表达式,+*p,的值是,A 20 B 30 C21 D31,B,B,C,单目运算符,:,自右向左,的结合顺序,注意:,+*pa,,,(*pa)+,,*,pa+,和*,+pa,四者之间的差别:,+*pa,相当于,+(*pa),,先给,pa,指向的变量值加,1,,然后返回该变量的值(*,pa,)。,(*pa)+,,先返回,pa,指向的变量值(*,pa,),然后该变量值加,1,。,*,pa+,相当于*,(pa+),,表示返回,pa,所指向变量的值(*,pa,),然后,pa,增,1,。,*,+pa,相当于*,(+pa),,表示,pa,增,1,,然后返回,pa,所指向变量的值(*,pa,)。,【,例,9.2】,分析以下程序的执行结果。,/*FileName:exam9_2.cpp*/,#include,void main(),int,a=10,20,30;,int,*pa=a;,printf(+*pa:%d,+*pa);,printf(*pa:%dn,*pa);,pa=a;/*pa,重新指向数组,a,的,0,号元素*,/,printf(*pa)+:%d,(*pa)+);,printf(*pa:%dn,*pa);,pa=a;/*pa,重新指向数组,a,的,0,号元素*,/,printf(*pa+:%d,*pa+);,printf(*pa:%dn,*pa);,pa=a;/*pa,重新指向数组,a,的,0,号元素*,/,printf,(*+,pa:%d,*+pa);,printf,(*,pa:%dn,*pa);,解,:程序执行结果如下:,+*pa:11,*pa:11,(*pa)+:11,*pa:12,*pa+:12,*pa:20,+pa:20,*pa:20,3.,地址越界问题,指针变量重新赋值后,其中的地址值发生了变化,新的地址值是否指向所需要的变量,新的地址值是否有实际意义,系统对此都不做检查,需要由程序员自己检查。如果新的地址值超出了正确范围称为地址越界。有时新的地址值已经指向存放程序的指令区,如果还把它当作变量给它赋值,将引起意想不到的结果,会导致执行混乱或死机。因此,使用指针对一定要细心,应注意以下几点:,(,1,)不要引用没有赋值的指针变量,使用指针变量前一定要对它正确赋值。在选择结构的程序中,每一个分支路径都应在引用指针变量之前对它正确赋值。,(,2,)用指针变量访问数组元素,随时要检查指针的变化范围,始终不能超越上下界。,(,3,)指针运算中注意各运算符的优先级和结合顺序,多使用括号会使程序容易理解。,9.2.2,二维数组的指针变量,1.,二维数组指针变量的定义格式,二维数组指针变量的一般的定义格式如下:,基类型,(*,指针变量,),整型表达式,其中,“整型表达式”指出二维数组中的列大小,即对应数组定义中的“下标表达式,2”,。,例如,有如下定义:,int,a34,(*pa)4=a;,在,(*pa)4,中,由于存在一对圆括号,所以“*”首先与,pa,结合,表示,pa,是一个指针变量,然后再与“,”,结合,表示指针变量,pa,的基类型是一个包含有,4,个,int,元素的数组,也就是说,,pa,为一个二维数组的指针变量,该数组中每列有,4,个元素。这样,,a,数组是一个,2,维地址,,pa,是一个,2,级指针。,2.,通过数组指针变量引用数组元素,一旦定义了二维数组的指针变量,该数组指针变量可以像数组名一样使用,且可以在数组元素中移动。在前面定义二维数组指针变量,pa,并初始化后,有:,pai,:引用,a,的第,i-1,个,1,维元素。,pa+,:让,pa,指向数组,a,的后一个,1,维元素。,pa-,:让,pa,指向数组,a,的前一个,1,维元素。,pa+1,等价于,a+1,、等价于,a1,,如右图所示。当,pa,指向,a,数组的开头时,可以通过以下形式来引用,aij,:,*,(,pai+j,),对应于*,(,ai+j,),*,(*(,pa+i)+j,),对应于*,(*(,a+i)+j,),(*(,pa+i)j,对应于,(*(,a+i)j,paij,对应于,aij,void main(),int,a34=1,2,3,4,5,6,7,8,9,10,11,12;,int,(*p)4;,int,i,j,;,p=a;,for(i,=0;i3;i+),for(j,=0;j4;j+),printf(“%2d “,*(*(,p+i)+j,),);,printf(“n,”);,p=,p=,p=a0;,9.2.3,多维数组的指针变量,1.,二维数组指针变量的定义格式,以三维数组为例加以讨论。三维数组指针变量的一般的定义格式如下:,基类型,(*,指针变量,),整型表达式,1),整型表达式,2,其中,“整型表达式,1”,对应数组定义中的“下标表达式,2”,,“整型表达式,2”,对应数组定义中的“下标表达式,3”,。,例如,有如下定义:,int,a232=1,2,3,4,5,6,7,8,9,10,11,12,(*pa)3)2=a;,pa,即为三维数组,a,的指针变量。其定义是分两步考虑的,先定义二维数组,a23,的指针变量,为,(*pa)3,,再定义三维数组,a,的指针变量为,(*pa)3)2,。这样,,a,数组是一个,3,维地址,,pa,是一个,3,级指针。,2.,通过数组指针变量引用数组元素,同样,一旦定义了三维数组的指针变量,该数组指针变量可以像数组名一样使用,且可以在数组元素中移动。在前面定义三维数组指针变量,pa,并初始化后,有:,pai,:引用,a,的第,i-1,个,2,维元素。,pa+,:让,pa,指向数组,a,的后一个,2,维元素。,pa-,:让,pa,指向数组,a,的前一个,2,维元素。,9.3,指针数组,1.,定义指针数组的语法格式,定义指针数组一般格式如下:,基类型*指针数组名,元素个数,;,int,*p4;,char*cp4=“,spring”,”summer”,”autumn”,”winter,”;,通过建立一个指针数组来引用二维数组元素,例如,:,int,*p3,a32,i,j;,for(i=0;i3;i+),pi=ai;,*,(pi+j)*(ai+j),*(*(p+i)+j)*(*(a+i)+j),(*(p+i)j (*(a+i)j,pij aij,p0,p1,p2,a00,a01,a10,a11,a20,a21,【,例,9.6】,分析以下程序的执行结果。,/*FileName:exam9_6.cpp*/,#include,void main(),int,a=1,2,3,b=4,5,c=6,7,8,9,*p3=,a,b,c,;,int i;,for(i=0;i3;i+),printf(%3d,*p0+);,printf(n);,for(i=0;i2;i+),printf(%3d,*p1+);,printf(n);,for(i=0;i4;i+),printf(%3d,*p2+);,printf(n);,解:程序执行结果如下:,1 2 3,4 5,6 7 8 9,9.4,多级指针变量,1.,多级指针定义的语法格式,以二级指针变量为例,其定义的一般格式如下:,基类型*指针名,;,通常情况下,对于,k,级指针,在定义时指针名前有,k,个“*”号。,2.,说明,(,1,)当一个指针变量指向普通变量时,这样的指针变量称为,1,级指针变量。指向,1,级指针变量的指针变量称为,2,级指针变量。指向,2,级指针变量的指针变量称为,3,级指针变量,依次类推。在引入多级指针变量的概念后,需要注意的是,访问一个指针变量的内容时,只有一级指针变量的内容才是要处理的数据,而多级指针的内容仍是一个指针变量。,例如,对于以下语句:,char*name3=,Smith,Mary,John,*pp=name;,其内存空间分配如下图所示。,(,2,)根据地址计算规则,多级指针变量访问内容的“*”运算也可采用数组形式,即采用访问数组元素运算符“,”,来表示。例如,使用二级指针变量,pp,计算出的某个目标变量(即,1,级指针变量)*,(,pp+i,),可以表示成,ppi,。由这个,1,级指针变量计算出某个目标变量*,(*(,pp+i)+j,),可以表示成,ppij,等。,【,例,9.8】,分析以下程序的执行结果。,/*FileName:exam9_8.cpp*/,#include,void,disp(char,*,p,int,n);,void main(),char*name3=,Smith,Mary,John,;,disp(name,3);,void,disp(char,*,pp,int,n),int i;,for(i=0;in;i+),printf(%sn,*pp+);,解:程序执行结果如下:,Smith,Mary,John,
展开阅读全文