C语言二维数组解引用问题:为何*(b+1)和b+1输出的地址一致?
问题原理说明
首先明确C语言中二维数组的本质是数组的数组,你定义的int b[3][4],实际是一个长度为3的数组,数组的每个元素都是「长度为4的int数组」。
各表达式的含义解析
b是二维数组名,作为右值使用时会自动退化为「指向第一行数组的指针」,类型为int (*)[4](指向长度为4的int数组的指针),值为整个二维数组的起始地址,也就是你输出的0x7ffeecee6730。b+1是基于b的指针运算:指针偏移的步长由指向的类型长度决定,b指向的是4个int组成的数组(假设单个int占4字节,总长度为16字节),因此b+1会向后偏移16字节,指向第二行数组的起始地址,值为0x7ffeecee6740,类型仍为int (*)[4]。*(b+1)是对b+1的解引用操作,得到的是第二行的数组本身,类型为int [4]。当数组作为printf参数传入时,会自动退化为「指向数组首元素的指针」,类型为int *,值就是第二行第一个元素的起始地址。
为什么两者输出地址相同?
b+1是指向第二行整个数组的指针,*(b+1)退化后是指向第二行第一个int元素的指针,两者指向的内存起始位置完全一致,所以用%p打印出来的地址值完全相同,仅指针的类型不同。
为什么用%d打印*(b+1)得到垃圾值?
*(b+1)最终退化为int *类型的指针,你用%d格式符去打印指针的地址值:
- 64位系统下指针长度为8字节,int长度为4字节,格式符和参数类型不匹配,会触发未定义行为
- 就算长度匹配,你打印的本质是内存地址的数值,不是你预期的元素值,自然是无意义的结果
如何正确拿到第二行第一个元素的值?
需要对退化后的int *指针再做一次解引用,两种写法等价:
// 写法1 printf("%d\n", *(*(b+1))); // 写法2 更直观的数组下标写法 printf("%d\n", b[1][0]);
以上两种写法都会输出你预期的第二行第一个元素值4。
内容的提问来源于stack exchange,提问作者Hayato Koyama
相关产品推荐
相关产品推荐

