【问题标题】:How does C allocate space for a 2D (3D...) array when using malloc?使用 malloc 时,C 如何为 2D (3D ...) 数组分配空间?
【发布时间】:2013-07-09 04:25:04
【问题描述】:

我在理解 C 如何为 2D(或更多维)数组分配空间时遇到问题,尤其是当我们使用 malloc 等时。以this question中的程序为例。

首先定义一维指针数组,然后将指向一维数据数组(在本例中为字符串)的指针放入第一个一维数组的每个框中。所以不能保证整个二维数组是连续的(前一行的最后一个单元格后面跟着下一行的第一个单元格)。每个一维数据数组可以很远,只有它们的指针是连续的。我是正确的还是我错过了什么?如果您能帮助我澄清这一点,我将不胜感激。

【问题讨论】:

  • 另一种分配二维数组的方法是使用单个缓冲区,然后根据二维坐标对其进行索引。 8 * 8 = 64。分配单个 64 字节缓冲区和索引 = x + y * 8
  • 所以像上面的问题那样定义一个二维数组确实是不连续的。谢谢。我了解如何关联 8x8=64 空间,你能给我举个例子,我如何根据 2D 坐标对其进行索引吗?谢谢。

标签: c malloc


【解决方案1】:

有多种方法可以做到这一点,具体取决于您将如何访问它。您可以确保数组的主体是连续的,或者您可以避免这种情况。对于字符串数组,您通常不必费心使数组的主体连续。对于整数或双精度数的二维(等)数组,您通常确实使数组的主体是连续的。

在示例中,数组的数据类型是泛型类型T,假定为数字,因此可以为数组元素分配0。这些示例不会错误检查内存分配;他们应该在生产代码中。

使用计算索引的数组访问——连续的数组主体

int n1 = 5;
int n2 = 6;

T *a = malloc(n1 * n2 * sizeof(T));

for (int i = 0; i < n1; i++)
    for (int j = 0; j < n2; j++)
        a[i * n2 + j] = 0;

free(a);

双下标数组访问——连续数组主体

int n1 = 5;
int n2 = 6;

T **a = malloc(n1 * sizeof(T*));
T  *b = malloc(n1 * n2 * sizeof(T));

for (int i = 0; i < n1; i++)
    a[i] = &b[i * n2];

for (int i = 0; i < n1; i++)
    for (int j = 0; j < n2; j++)
        a[i][j] = 0;

free(b);
free(a);

双下标数组访问——不连续的数组体

int n1 = 5;
int n2 = 6;

T **a = malloc(n1 * sizeof(T*));

for (int i = 0; i < n1; i++)
    a[i] = malloc(n2 * sizeof(T));

for (int i = 0; i < n1; i++)
    for (int j = 0; j < n2; j++)
        a[i][j] = 0;

for (int i = 0; i < n1; i++)
    free(a[i]);
free(a);

【讨论】:

  • 非常感谢您提供完整的示例。我现在完全明白了。
  • 只有一个问题:“使用计算索引的数组访问——连续的数组主体”似乎比“使用双下标的数组访问——连续的数组主体”更简单(因此更快),对吗?
  • 这是一个乘法和加法速度与内存访问速度的问题。如今,计算速度可能比内存访问快,但双下标的符号便利性也不容忽视。这是一个秋千和环形交叉路口的游戏。选择适合你的;衡量绩效(如果重要)。
【解决方案2】:

方法1(指向缓冲区的指针,不连续)

您是对的,不能保证数据会连续,实际上很可能不会。顶级数组(行)只是一个一维指针数组(每个元素都是它自己的指针)。这些指针每个都指向它们自己的实际对象的一维数组。这些缓冲区仅通过指针连接。

/* allocation */
int** array = malloc(sizeof(int*) * height)
for (int y = 0; y < height; y ++)
{
   array[i] = malloc(sizeof(int) * width);
}
/* indexing */
int item = array[y][x];

方法2(单缓冲区,连续)

另一种分配二维数组的方法是使用单个缓冲区,然后根据二维坐标对其进行索引。例如8 * 8 = 64。分配一个64字节的缓冲区,索引= x + y * 8。这种方法连续存储数据,比方法1更容易分配和释放。

/* allocation */
int* array = malloc(sizeof(int) * width * height)
/* indexing */
int item = array[x + y * width];

【讨论】:

  • 我认为连续数组更容易(因此更快)让计算机分析,这种理解是否正确?我知道对于一个小数据集它没有太大的区别,但我认为它对于一个大数据集(例如一个大图像)。我说的对吗?
  • @astroboy 连续数据布局对于小到大数据集的迭代和随机访问更加缓存友好。我想它对于除了最小的数据集之外的任何东西都明显更快。 malloc 和 free 也更容易。
【解决方案3】:

我认为你是对的。但是如果你真的希望数组是连续的,你可以malloc 一个一维数组并像使用二维数组一样使用它,比如

int* oneDArray = (int*)malloc(sizeof(int)*10*10);
int a = oneDArray[i*10+j];     //which equals to twoDArray[i][j]

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-11-10
    • 2011-05-14
    • 2015-08-04
    • 1970-01-01
    • 2015-11-30
    • 1970-01-01
    相关资源
    最近更新 更多