繁体   English   中英

单个malloc调用中的二维数组

[英]2-D array in single malloc call

int **arrayPtr; 
arrayPtr = malloc(sizeof(int) * rows *cols + sizeof(int *) * rows);

在上面的代码中,我们尝试在单个malloc调用中分配2D数组。 malloc需要多个字节并为那么多字节分配内存,但在上面的例子中, malloc如何知道首先它必须分配一个指针数组,每个指针都指向一维数组?

在这种特殊情况下, malloc如何在内部工作?

2D数组与指向数组的指针数组不同。

int **arrayPtr没有定义2D数组。 2D数组看起来像这样:

int array[2][3]

并且指向此数组的第一个元素的指针如下所示:

int (*array)[3]

你可以指向一块内存:

int (*array)[3] = malloc(sizeof(int)*5*3);


请注意它是如何编入索引的:

  • array[x]将扩展为*(array+x) ,因此“x int of 3 ints forward”。
  • array[x][y]会扩展为*( *(array+x) + y) ,所以“然后y ints forward”。

这里没有直接的指针数组,只有一个连续的内存块。

如果你有一个数组数组(与2D数组不同,通常使用int** ptr和一系列每行mallocs),它会像:

  • ptr[x]会扩展为*(array+x) ,所以“x指针向前”
  • ptr[x][y]将扩展为*( *(array+x) + y) =“y ints forward”。

注意区别。 两者都用[x] [y]索引,但它们在内存中以不同的方式表示,索引以不同的方式发生。

malloc如何知道首先必须分配一个指针数组,每个指针都指向一维数组?

它没有; malloc只是分配你指定的字节数,它不知道这些字节是如何构造成聚合数据类型的。

如果您尝试动态分配多维数组,则有多种选择。

如果您使用的是支持可变长度数组的C99或C2011编译器,则只需将数组声明为

int rows;
int cols;
...
rows = ...;
cols = ...;
...
int array[rows][cols];

但是,VLA存在许多问题; 它们不适用于非常大的数组,它们不能在文件范围内声明等。

第二种方法是执行以下操作:

int rows;
int cols;
...
rows = ...;
cols = ...;
...
int (*arrayPtr)[cols] = malloc(sizeof *arrayPtr * rows);

在这种情况下, arrayPtr被声明为指向带有cols元素的int数组的指针,因此我们分别为每个cols元素分配rows数组。 请注意,只需编写arrayPtr[i][j]即可访问每个元素; 指针算法的规则与常规2D数组的工作方式相同。

如果您不使用支持VLA的C编译器,则必须采用不同的方法。

您可以将所有内容分配为一个块,但是您必须以一维数组的形式访问它,计算偏移量,如下所示:

int *arrayPtr = malloc(sizeof *arrayPtr * rows * cols);
...
arrayPtr[i * rows + j] = ...;

或者您可以分两步分配它:

int **arrayPtr = malloc(sizeof *arrayPtr * rows);
if (arrayPtr)
{
  int i;
  for (i = 0; i < rows; i++)
  {
    arrayPtr[i] = malloc(sizeof *arrayPtr[i] * cols);
    if (arrayPtr[i])
    {
      int j;
      for (j = 0; j < cols; j++)
      {
        arrayPtr[i][j] = some_initial_value();
      }
    }
  }
}

malloc()不知道它需要为数组分配一个指针数组。 它只返回一个请求大小的内存块。 您当然可以通过这种方式进行分配,但是您需要初始化第一个“行”(或者最后一个,甚至是一个列而不是一行 - 但是您想要这样做),它们将被用作指针,以便他们指向该块内的适当区域。

这样做会更好,更有效:

int *arrayPtr = malloc(sizeof(int)*rows*cols);

这样做的缺点是你必须在每次使用时计算正确的索引,但你可以写一个简单的辅助函数来做到这一点。 你不会使用[]引用元素的“方便”,但你可以有例如element(arrayPtr, x, y)

我会重新引起你的注意,而不是“操作员做什么?”的问题。

如果您计划通过[]运算符访问数组中的元素,那么您需要意识到它只能根据元素的大小进行偏移设置,除非提供了一些数组几何信息。

malloc没有维度信息,calloc - 明确1D。 另一方面,声明的数组(arr [3] [4])显式指定编译器的维度。

因此,为了以时尚arr [i] [j]访问动态分配的多D数组,实际上您分配了目标维度大小的一系列1D阵列。 你需要循环才能做到这一点。

malloc返回指向堆内存的普通指针,没有关于几何或数据类型的信息。 因此[] []不起作用,您需要手动补偿。

因此,您的电话是指[] - 索引是您的优先级还是批量分配。

int **arrayPtr; 不指向2D数组。 它指向一个指向int的指针数组。 如果要创建2D数组,请使用:

int (*arrayPtr)[cols] = calloc(rows, sizeof *arrayPtr);

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM