从一维数组到二维数据,解析数组名a, &a[0], &a 的区别与联系

对于一个一维数组,如下:

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));

结果为:

 

  • 2
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值