如何用单个索引访问C语言二维数组?相关内存地址疑问解答
二维数组访问与地址疑问解答
问题背景
代码1及运行结果
#include <stdio.h> int main() { int a[2][2] = { 0,1,2,3}; printf("\n%d %d \n%d %d\n",a[0][0],a[0][1],a[1][0],a[1][1]); printf("%d %d %d %d\n",*a[0],*a[1],*a[2],*a[3]); return 0; }
运行输出:
0 1 2 3 0 2 0 1491303602
代码2及运行结果
printf("\n%d %d \n%d %d\n",&a[0][0],&a[0][1],&a[1][0],&a[1][1]); printf("%d %d %d %d\n",a[0],a[1],a[2],a[3]);
运行输出:
1137924528 1137924532 1137924536 1137924540 1137924528 1137924536 1137924544 1137924552
疑问
- 由于二维数组在内存中是连续存储的,是否可以通过单个索引来访问二维数组?
- 为什么前两个元素的内存地址
&a[0][0]等于a[0]、&a[0][1]等于a[1],但后两个却不匹配?
解答
1. 单个索引访问二维数组的可行性
可以。二维数组在内存中是连续线性存储的,对于int a[m][n],完全可以当作长度为m*n的一维数组访问,常用两种方式:
- 强制类型转换:将数组名转为一维数组指针,例如
*(int*)a + i,其中i取值范围是0到m*n-1,对应一维数组的第i个元素; - 地址偏移:通过
*(&a[0][0] + i)直接访问,本质和第一种方式一致,也可以用下标计算a[i/n][i%n](前提是i不越界)。
注意:代码中a[2]、a[3]属于越界访问,原数组仅2行,超出范围的行指针指向数组内存外的未知区域,这就是输出出现随机值的原因,属于未定义行为,严禁这么写。
2. 地址匹配问题的原因
首先明确二维数组的类型逻辑:
a是int[2][2]类型,a[0]、a[1]本身是int[2]类型的一维数组,在表达式中会隐式转换为指向自身首元素的指针;a[0]转换后指向a[0][0],所以a[0]的值等于&a[0][0];a[1]转换后指向a[1][0],所以a[1]的值等于&a[1][0]——你误以为a[1]等于&a[0][1]是完全错误的,二者地址差了一个int的大小(看输出:a[1]是1137924536,&a[0][1]是1137924532)。
而a[2]、a[3]属于越界访问,原数组只有2行,这两个指针指向数组内存范围外的“虚拟行”首地址,自然和&a[1][0]、&a[1][1]不匹配,这类访问属于未定义行为,结果不可预测。
内容的提问来源于stack exchange,提问作者DCR
相关产品推荐
相关产品推荐

