您认为关于2D阵列的内存映射的this discussion是正确的吗? Especially this photo?你能解释一下这个理论吗?
假设我们在C中声明一个2D数组:
int arr[3][3]={10, 20, 30, 40, 50, 60, 70, 80, 90};
现在,根据这个讨论,内存将按如下方式排列:
现在,我编写了以下代码来测试这个理论:
#include <stdio.h>
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个输出相同?
答案 0 :(得分:13)
<强> See my question here. 强>
这不是您访问有关二维数组的信息的方式。实际上,您可以将它们视为1-d,在这里您可以以特殊方式乘以和添加索引。
e.g。
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]
:这是存储在第一个子数组的第一个元素中的值。 答案 1 :(得分:8)
你的代码只使用一个简单的多维数组,但是图像描述了一个指针数组,就像你在编写事物时通常所做的那样。
多维数组基本上只是一个普通的,扁平的数组(在内存中),有一些额外的合成糖可供访问。因此,虽然可以从arr [i]获取指针,但是没有额外的“变量”来存储它,就像在图像中一样。
要更正图像,请使用arr[0], arr[1]...
删除部分,并将arr
的值更改为1245039
(与&amp; arr [0] [0]相同)。< / p>
答案 2 :(得分:0)
前四个输出与获得数组中第一个元素的地址的原因相同,即&amp; arr [0] [0]。最后一个输出是它的内容。
答案 3 :(得分:0)
好吧,据我所知,在C ++中(我认为C,虽然这不是我的强项)一个声明为Values[][]
的二维数组通常(不知道是否总是)实现为一个数组C风格的数组。但是,当你在堆栈上声明它们(例如一个局部变量)时,我相信内存格式是不同的。
所以,当你声明一个局部变量时,所有的内容都是,好像它只是一个1d数组,并且你得到了一些东西,你可以实际投射到一个指针,然后访问为一个数组。(!)然而,它仍然被认为与声明范围内的普通2D数组相同,并且可能传递给使用[]
表示法声明的参数。
但是,如果你在堆上分配其中一个(例如全局或静态或通过新),故事就不同了。现在,内存被布局为一个实际的数组数组,因此如果你转换为一维数组,索引的内存位置的实际结果现在将成为指针。
我通过执行以下操作验证了我的回忆:我创建了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];
所以我认为我的有限回忆是准确的。 :)希望这有帮助!