C语言 单个 malloc 调用中的 2-D 数组


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数组的3个整数向前"。
  • array[x][y]会扩展到*( *(array+x) + y),所以"然后y整数向前"。

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

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

  • 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数组的指针,因此我们为每个数组分配rows个包含cols元素的数组。 请注意,您只需编写 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] 的方式访问动态分配的多维数组,您实际上分配了目标维度大小的一维数组系列。您需要循环才能做到这一点。

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

因此,[] 索引是您的优先级还是批量分配,都是您的决定。

int **arrayPtr;

指向 2D 数组。它指向指向 int 的指针数组。如果要创建 2D 阵列,请使用:

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

相关内容

  • 没有找到相关文章

最新更新