C语言二维数组array[i]与&array[i]地址输出相同问题咨询
测试代码与运行结果
测试代码
#include <stdio.h> #include <stdlib.h> int main(void) { int array[3][4]={{1,2,3,4},{5,6,7,8},{9,10,11,12}}, i; printf("array address:\n"); for(i=0;i<=2;i++){ printf("array[%d]=%p, address of array[%d]=%p, deference *array[%d]=%d\n", i, array[i], i, &array[i], i, *array[i]); printf("*(array+%d)=%2p, value of array+i=%p \n\n", i, *(array+i), array+i); } system("PAUSE"); return 0; }
运行结果
array address: array[0]=000000af1bfffc70, address of array[0]=000000af1bfffc70, dereference *array[0]=1 *(array+0)=af1bfffc70, value of array+i=000000af1bfffc70 array[1]=000000af1bfffc80, address of array[1]=000000af1bfffc80, dereference *array[1]=5 *(array+1)=af1bfffc80, value of array+i=000000af1bfffc80 array[2]=000000af1bfffc90, address of array[2]=000000af1bfffc90, dereference *array[2]=9 *(array+2)=af1bfffc90, value of array+i=000000af1bfffc90
疑问解答
疑问1:为什么array[i]和&array[i]地址值相同,但*array[i]能取到行首元素值?
首先纠正一个核心认知偏差:C语言里的二维数组本质是数组的数组,不是“存储了一组指针的数组”。array[i]不是一个单独占内存的指针变量,它就是第i行那个长度为4的一维数组本身的标识,不存在“array[i]这个变量的内存里存了一个地址值”的情况。
- 数组名在绝大多数表达式场景下会隐式转换成指向自身首元素的指针:
array[i]作为第i行一维数组的名字,转换后得到的是int*类型的指针,指向该行第一个int元素,值就是1/5/9所在的内存位置,所以对它做解引用*array[i],自然能拿到对应行首的int值。 &array[i]取的是整个第i行一维数组的地址,类型是int (*)[4](指向长度为4的int数组的指针)。整行数组的起始内存位置,和该行第一个元素的起始内存位置完全重合,所以打印出来的地址数值和array[i]一模一样。二者的核心区别是指针类型不同,做指针运算时步长不一样:array[i]+1会往后偏移1个int的长度(通常是4字节),&array[i]+1会往后偏移整整1行也就是4个int的长度(通常是16字节)。
认知冲突的本质是把数组名错当成了独立存储的指针变量。实际上数组名只是对应连续内存块的别名,本身不占用额外的存储空间,自然不存在“起始地址位置存了地址本身”的情况。
疑问2:为什么*(array+i)和array+i地址值一致,只有前导零显示差异?
先解释值相同的原因:array作为二维数组名,参与表达式运算时会隐式转换为指向第一行一维数组的指针,类型是int (*)[4],array+i自然就是指向第i行一维数组的指针。对这个指针解引用*(array+i),得到的是第i行的一维数组本身,而这个一维数组在表达式里又会隐式转换为指向自身首元素的int*指针——和array[i]是完全等价的。
这两个指针一个是“指向整行数组的指针”,一个是“指向行首int元素的指针”,指向的内存起始位置完全重合,所以地址数值一致,类型差异和第一个疑问里的情况完全相同。
至于显示上的前导零差异,和指针本身的值没有任何关系,纯粹是printf的格式符导致的:你写的%2p里的2是指定最小输出宽度为2,但指针实际打印长度远大于2,这个宽度限制根本不生效。不同C标准库实现对%p格式的前导补零规则有细微处理差异,才会出现一个带全前导零、一个不带的显示效果,二者指向的地址完全没有区别。
内容的提问来源于stack exchange,提问作者Mars Aries
相关产品推荐
相关产品推荐

