C中二维数组的内存映射
您认为关于2Darrays的内存映射的讨论是正确的吗? 特别是这张照片? 你能解释一下这个理论吗?
假设我们在C中声明一个2D数组,如下所示:
int arr[3][3]={10, 20, 30, 40, 50, 60, 70, 80, 90};
现在,根据这个讨论,内存将按如下方式排列:
现在,我编写了以下代码来测试这个理论:
#include main() { int arr[3][3]={10, 20, 30, 40, 50, 60, 70, 80, 90}; printf(" arr==%d\n", arr); printf(" &arr[0]==%d\n", &arr[0]); printf(" arr[0]==%d\n", arr[0]); printf("&arr[0][0]=%d\n", &arr[0][0]); printf(" arr[0][0]=%d\n", arr[0][0]); } /* Output: ======== arr ==1245028 &arr[0] ==1245028 arr[0] ==1245028 &arr[0][0]==1245028 arr[0][0]==10 Press any key to continue... */
为什么前4个输出相同?
你的代码只使用一个简单的多维数组,但是图像描述了一个指针数组,就像你在编写事物时通常所做的那样。
多维数组基本上只是一个普通的,扁平的数组(在内存中),带有一些额外的合成糖用于访问。 因此虽然可以从arr [i]获取指针,但是没有额外的“变量”来存储它,就像在图像中发生的那样。
要校正图像,请使用arr[0], arr[1]...
删除部件,并将arr[0], arr[1]...
的值更改为1245039
(与&arr [0] [0]相同)。
在这里看到我的问题。
这不是您访问有关二维数组的信息的方式。 实际上,您可以将它们视为1-d,在这里您可以乘以并以特殊方式添加索引。
例如
int x[10] = {0,1,2,3,4,5,6,7,8,9}; int y[2][5] = {{0,1,2,3,4},{5,6,7,8,9}};
它们在内存中的格式完全相同,它们看起来像这样:
|0|1|2|3|4|5|6|7|8|9|
因此,要获得8
元素,您可以要求x[8]
或y[1][3]
。
对于第二种方式,您可以将其视为(1 * 5) + 3
。
这就是为什么你的前4个是相同的。 你有:
-
arr
:这是数组开头的地址 -
arr[0]
:这是第一个子数组的起始地址,与整个数组的起始地址相同 -
&arr[0][0]
:这是第一个子数组的第一个元素的地址,也是整个数组的开头 -
arr[0][0]
:这是存储在第一个子数组的第一个元素中的值。
前四个输出与获取数组中第一个元素的地址的原因相同,即&arr [0] [0]。 最后一个输出是它的内容。
好吧,据我所知,在C ++中(我认为C,虽然这不是我的强项)一个声明为Values[][]
的二维数组通常(不知道是否总是)实现为C风格的数组arrays。 但是,当你在堆栈上声明它们(例如一个局部变量)时,我相信内存格式是不同的。
所以,当你声明一个局部变量时,所有东西都被布局好像它只是一个1d数组,并且你得到了一些东西,你可以实际投射到一个指针,然后作为一维数组访问。(!)然而,它仍然以与声明范围内的普通2D数组相同的方式识别,并且可能传递给使用[]
表示法声明的参数。
但是,如果你在堆上分配其中一个(例如全局或静态或通过新),故事就不同了。 现在,内存被布置为一个实际的数组数组,因此如果你转换为一维数组而索引的内存位置的实际结果现在将成为指针。
我通过以下方式validation了我的回忆:我创建了int HeapArray[3][3];
作为全局和int StackArray[3][3];
作为一个本地(两者都有{ { 10, 20, 30 }, {40, 50, 60}, {70, 80, 90 } }
初始化者。 在我的函数中,我将它们都转换为int指针, int* ptrHeapArray = (int*)HeapArray;
和int* ptrStackArray = (int*)StackArray;
然后查看每个元素的第0个元素的返回值。
[编辑:哎呀,我让他们逆转; 现在修复]
ptrStackArray[0]
等于10
ptrHeapArray[0]
等于指向int [3]的指针;
所以我认为我的有限回忆是准确的。 :) 希望这可以帮助!