【问题标题】:Memory map for a 2D array in CC中二维数组的内存映射
【发布时间】:2011-10-04 03:52:55
【问题描述】:

你认为this discussion 关于二维数组的内存映射是正确的吗? Especially this photo?你能解释一下理论吗?

假设我们在 C 中声明一个二维数组,如下所示:

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 个输出相同?

【问题讨论】:

  • 我认为真正的问题是int **arrint arr[][] 之间是否有区别——没有一个答案能解决这个问题。

标签: c multidimensional-array


【解决方案1】:

See my question here.

这不是您访问二维数组信息的方式。实际上,您可以将它们视为 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]:这是第一个子数组的起始地址,与整个数组的起始地址相同
  • &amp;arr[0][0]:这是第一个子数组的第一个元素的地址,也是整个数组的开始
  • arr[0][0]:这是存储在第一个子数组的第一个元素中的值。

【讨论】:

  • 你的数学有点不对劲。要获得8 元素,您需要x[8],而不是x[9]。此外,使用y[1][3] 计算的元素是(1*5) + 3
  • 谢谢@Hitesh,我已经修好了。具有讽刺意味的是,对于我的示例,我是在考虑与想象中的“数组开始”相关的术语。
【解决方案2】:

您的代码只使用了一个普通的多维数组,但图像描述了一个指针数组,就像您在 malloc-ing 事物时通常所做的那样。

多维数组基本上只是一个普通的、扁平化的数组(在内存中),带有一些额外的语法糖用于访问。因此,虽然可以从 arr[i] 获取指针,但没有额外的“变量”来存储它,就像在您的图像中发生的那样。

要修正图像,请移除带有arr[0], arr[1]... 的部分并将arr 的值更改为1245039(与&arr[0][0] 相同)。

【讨论】:

    【解决方案3】:

    前四个输出与获取数组中第一个元素的地址的原因相同,即&arr[0][0]。最后的输出是它的内容。

    【讨论】:

      【解决方案4】:

      好吧,据我回忆,在 C++(我认为 C,虽然这不是我的强项)中,声明为 Values[][] 的二维数组通常(不知道是否总是)实现为 C- 数组样式数组。但是,当您在堆栈上声明它们(例如局部变量)时,我相信内存格式是不同的。

      所以,当你声明一个局部变量时,所有的东西都被布置成好像它只是一个一维数组,你得到的东西被布置成这样你就可以真正地转换为一个指针,然后访问为一维数组。(!)但是,在声明的范围内,它仍然以与普通二维数组相同的方式被识别,并且可能如果您传递给使用[] 表示法声明的参数。

      但是,如果您在堆上分配其中之一(例如全局或静态或通过新),情况就不同了。现在,内存被布置为一个实际的数组数组,因此如果您转换为一维数组和索引,您索引的内存位置的实际结果现在将是指针。

      我通过执行以下操作验证了我的回忆:我将 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] 的指针;

      所以我认为我有限的回忆是准确的。 :) 希望这会有所帮助!

      【讨论】:

        猜你喜欢
        • 2015-10-02
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2016-11-22
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多