指向多维数组的指针变量
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
指向多维数组的指针变量
1 多维数组的指针
多维数组可以看作是一维数组的延伸,多维数组的内存单元也是连续的内存单元。换句话说,C语言实际上是把多维数组当成一维数组来处理的。下面以二维数组为例说明这个概念。
比如,现在有一个int型的二维数组a[3][4],计算机认为这是一个一维的数组a[3],数组的三个元素分别是a[0],a[1]和a[2]。其中每个元素又是一个一维数组,例如a[0]又是一个包含a[0][0],a[0][1],a[0][2]和a[0][3]共4个元素的数组。如果我们要引用数组元素a[1][2],可以首先根据下标1找到a[1],然后在a[1]中找到第3个元素a[1][2]。假设数组a的起始地址为FF10,对应的内存情况如图:
DS:FF10 a[0][0] DS:FF12 a[0][1] DS:FF14 a[0][2] DS:FF16 a[0][3]
DS:FF18 a[1][0] DS:FF1A a[1][1] DS:FF1C a[1][2] DS:FF1E a[1][3]
DS:FF20 a[2][0] DS:FF22 a[2][1] DS:FF24 a[2][2] DS:FF26 a[2][3]
可以看到,二维数组a[3][4]的12个元素在内存中是顺序排列的,因此&a[0][0]是数组第一个元素的地址,为FF10。
a[0][0],a[0][1]这些数组元素都有具体的内存单元值。但是,a[0],a[1]和a[2]这三个数组元素不占用内存单元,它们只是代号(其实就是一个指针常量),是虚拟的东西。a[0]本身又是一个数组,包含a[0][0],a[0][1],a[0][2]和a[0][3],那么a[0]作为数组名称,按照C语言的语法,a[0]就是数组首地址,也就是数组第一个元素的地址,即a[0][0]的地址FF10。同理,a[1]是第一个元素a[1][0]的地址,即FF18;a[2]是第一个元素a[2][0]的地址,即FF20。
相对于a[0],a[1]和a[2]来说,a也是数组的名称,是数组的首地址,即FF10。a是指向数组首地址的指针,a+1代表什么?a是数组名称,a[0],a[1]和a[2]是元素,那么a+1就是&a[1](如果一个一维数组int b[3],那么b+1是不是&b[1]?),即第二行元素的首地址,指针值为FF18。同理,a+2就是&a[2],指针值为FF20。
也可以换个角度去理解。a是数组首地址,指向二维数组第一行的首地址;计算a+1时,指针a跳过的是整个a[0],a+1指向二维数组第二行的首地址。指针a在做加法时,跳过的是一行元素。
a[1]+1代表什么?指针a[1]是一维数组a[1]中第一个元素a[1][0]的地址FF18。对于一维数组a[1]来说,指针a[1]+1指向了a[1]中第二个元素a[1][1]的地址,即FF1A。这里指针加法的单位是一列,每次跳过a[1]中的一个数组元素。
*a代表什么?*a也就是*(a+0),数组第一个元素的值,即a[0]。前面讲过,a[0]是一个代号,它不是一个具体元素的值,而是内嵌的一维数组a[0]的名字,a[0]本身也是一个指针值。同理,*(a+1)就是a[1],*(a+2)就是a[2]。
如果要访问二维数组里第i行第j列的某个元素,可以直接引用a[i-1][j-1],也可以使用指针的方法。指向第i行第j列元素的指针为a[i]+j,或者*(a+i)+j,因此,间接用指针引用二维数组里第i行第j列的某个元素,可以表示为*(a[i]+j)或者*(*(a+i)+j)。特别需要指出的是,a[i]不是一个具体的数组元素,它是一个代号,实际上是一个指针值,代表i+1行里中第一个元素的首地址。
因此&a[i]不能直接理解为a[i]的物理地址,a[i]不是变量,不存在物理地址;&a[i]代表第i+1行的行指针值,和a+i等价。同样,*a[i]也不能理解为对一个数组元素进行指针运算符操作。a[i]是一个指针值,是i+1行中第一个元素的首地址,那么*a[i]就是i+1行里中第一个元素的值,即a[i][0]。
总之,二维数组a[i][j]的指针由于出现了虚拟的a[i]这个概念,所以对于初学者很不好理解,请读者仔细消化理解。下表是上述概念的综合:
main()
{
int a[3][4]={1,2,3,4,5,6,7,8,9,10,11,12},i,j;
/*打印a*/
printf("\na=%X", a);
/*打印a+i, &a[i]*/
for(i=0;i<3;i++)
printf("\na+%d=%X, &a[%d]=%X", i,a+i,i,&a[i]);
/*打印a[i], *(a+i)*/
for(i=0;i<3;i++)
printf("\na[%d]=%X, *(a+%d)=%X", i,a[i],i,*(a+i));
/*打印a[i]+j, *(a+i)+j, &a[i][j]*/
for(i=0;i<3;i++)
for(j=0;j<4;j++)
printf("\na[%d]+%d=%X, *(a+%d)+%d=%X, &a[%d][%d]=%X",
i,j,a[i]+j, i,j,*(a+i)+j, i,j,&a[i][j]);
/*打印**(a+i), *a[i]*/
for(i=0;i<3;i++)
printf("\n**(a+%d)=%X, *a[%d]=%X", i, **(a+i),i, *a[i]);
/*打印*(a[i]+j), *(*(a+i)+j), a[i][j]*/
for(i=0;i<3;i++)
for(j=0;j<4;j++)
printf("\na[%d]+%d=%d, *(a+%d)+%d=%d, &a[%d][%d]=%d",
i,j,*(a[i]+j), i,j,*(*(a+i)+j), i,j,a[i][j]);
}
程序运行的结果为(打印的地址值是动态分配的,不同环境下可能不同;但数组的地址偏移量是相同的):
a=FFBE
a+0=FFBE, &a[0]=FFBE
a+1=FFC6, &a[1]=FFC6
a+2=FFCE, &a[2]=FFCE
a[0]=FFBE, *(a+0)=FFBE
a[1]=FFC6, *(a+1)=FFC6
a[2]=FFCE, *(a+2)=FFCE