对于一个一维数组,如下:
int a[3] = {1,2,3};
a,&a[0],&a分别表示什么?
printf("a = %x\n", a);
printf("&a[0] = %x\n", &a[0]);
printf("&a = %x\n", &a);
结果如下:
不难发现,其实它们的值都相同,难道它们就真的没有区别?然而并不是
int a[3] = { 1, 2, 3 };
printf("a = %x\n", a);
printf("&a[0] = %x\n", &a[0]);
printf("&a = %x\n", &a);
printf("\n");
printf("a+1 = %x\n", a+1);
printf("&a[0]+1 = %x\n", &a[0]+1);
printf("&a+1 = %x\n", &a+1);
从以上可以看出,a+1与&a[0]+1的值相同
对于a+1,与 a 的差值为4,即一个int型的长度
对于&a[0]+1,与 &a[0] 的差值为4,也为一个int型的长度
而对于&a+1,与 &a 的差值为12,显然为3个int型的长度
为什么是这样?
可以这样理解,对于数组的地址操作,它不应该只有地址值本身,还隐藏着所指向的存储单元的大小,至于是多大,编译器给你解释为多大就多大吧。在上面的例子中,a 或 &a[0]就隐藏着这样一个信息——所指向的存储单元的大小为4,而 &a 所指向的存储单元大小为12。所以,对它们加一的值为有所不同。
因此,对于一维数组,我们有理由相信,a 与 &a[0]相同,它们所指向的存储单元的大小为数组元素的大小;而 &a 所指向的存储单元的大小为整个数组的大小
有了以上的理解,接下来看看二维数组
int a[2][3];
声明以上二维数组,等价于下面的声明
typedef int row3_t[3];
row3_t a[2];
数据类型 row3_t 被定义为一个有三个整数的数组,数组 a 有2个这样类型的元素。
这样,对于数组int a[2][3] 来说,其实它就是一维数组 row3_t a[2],只不过这时的数组元素内容不是一个整型变量,而是三个整型变量。
所以,执行
int a[2][3] = {1,2,3,4,5,6};
printf("a = %x\n", a);
printf("&a[0] = %x\n", &a[0]);
printf("&a = %x\n", &a);
printf("\n");
printf("a+1 = %x\n", a + 1);
printf("&a[0]+1 = %x\n", &a[0] + 1);
printf("&a+1 = %x\n", &a + 1);
结果为:
a 、&a[0] 、&a 它们的值都相同,且不难发现
a 、&a[0] 所指向的存储单元的大小为12,为3个int型长度,即一维数组 row3_t a[2] 的元素的长度;
&a 所指向的存储单元大小为24,为三个row3_t型的长度,即一维数组 row3_t a[2]的总长度。
上面三种取值方式再加1时跨度大于1个int类型,那要如何访问任意一个元素呢?如a[1][1](第二行第二列)
a+1就是第2行第一列的地址,a+1所指向的存储单元的大小为12,假如再加一,它是要加12的,就直接跳过第二行了,不可能访问到第二行(除第一列)的元素。*(a+1)是第二行所有元素,它作为一个新的地址,其值与 a+1相同,不过它所指向的存储单元的大小应为4,这样,在此基础上,*(a+1)+1自然指向a[1][1].
由于 &a[0] 与 a 相同,那么,*(a+1)+1 可以替换为 *(&a[0]+1)+1.
又由于*(a+1)可以转换为a[1],那么,*(a+1)+1 可以替换为 a[1]+1.
是否是这样呢,看执行结果
int a[2][3] = {1,2,3,4,5,6};
printf("a = %x\n", a);
printf("&a[0] = %x\n", &a[0]);
printf("&a = %x\n", &a);
printf("\n");
//与上面对应地址求差值,为所指向的存储单元大小
printf("a+1 = %x\n", a + 1);
printf("&a[0]+1 = %x\n", &a[0] + 1);
printf("&a+1 = %x\n", &a + 1);
printf("\n");
//验证a+1与*(a+1)是否相等
printf("a+1 = %x\n", a+1);
printf("*(a+1) = %x\n", *(a+1));
printf("\n");
//访问a[1][1]
printf("%d\n", *(*(a+1)+1));
printf("%d\n", *(*(&a[0]+1)+1));
printf("%d\n", *(a[1]+1));
结果为: