【问题标题】:Malloc a 2D array in C [duplicate]在C中Malloc一个二维数组[重复]
【发布时间】:2016-08-21 19:09:50
【问题描述】:

每次我首先为二维数组分配内存时,我都会创建一个 int** 数组,然后使用 for 为每个元素分配内存。

例如:

int ** arr = malloc(N*sizeof(int *));
for(i=0; i< N; i++) arr[i] = malloc(M*sizeof(int));

不可能像这样分配内存:

int ** arr = malloc(N*sizeof(int[M]));

int ** arr = malloc(sizeof(int[N][M]));

为了避免for?

【问题讨论】:

  • 您使用的是 C 还是 C++?
  • 您可以编写自己的函数,其中包含执行此操作所需的一切。除此之外,没有任何语法技巧可以使它成为可能。
  • 另见this answer

标签: arrays c multidimensional-array malloc


【解决方案1】:

int ** arr = malloc(N*sizeof(int[M])); 只是不正确的 C 代码,如果您通过像这样分配一次来模拟它:

int *arr = malloc(N*M*sizeof(int));

添加通过arr[i*M + j] 访问它,这类似于在您的第一种情况下访问arr[I][j]

【讨论】:

  • @Olaf 冷静点,C 没有二维数组,OP 想要分配一次缓冲区来保存 NxM 个整数。
  • 另外,它一点也不“过时”,它是你今天看到的东西。这完全取决于您的用例。奇怪的是,您毕竟可以将某种代码声明为“过时”。
  • 我只是问有没有办法那样,我从来没有说过那样就是这样。
  • @fluter:你可以!看我的回答。是的,它已经过时了。只是有太多的程序员认为 C 中没有多维数组。但仅仅因为“我们一直都是这样做的”并不意味着它是正确的方法。事实上,你的版本并没有一个优点,而是很多缺点,例如:容易出错,更难理解,你必须自己追踪内部长度。
  • 哦,对不起,对于强烈的反应。数组和指针太混乱了。还有太多的程序员害怕使用复杂的数组,尽管一旦你理解了这个概念,它就会变得非常简单(不过,使用限定符会变得更糟)。
【解决方案2】:

像这样:int (*arr)[M] = malloc(sizeof(int[N][M]));

arr 是指向int[M] 的指针。

arr[0][M-1];一样使用

free(arr);

【讨论】:

  • 更好 - int (*arr)[M] = malloc( sizeof *arr * N );。这样,如果 arr 的类型发生变化,您就不必修改 sizeof 表达式。
  • @JohnBode 见this answer
  • @JohnBode 在那篇文章中,我的观点与你相似。但是,应该避免它,因为它在标准中找不到此类操作的任何保证。
  • 然后是 5.1.2.3/4 中的这种语言:“在抽象机器中,所有表达式都按照语义指定的方式进行评估。实际实现不需要评估表达式的一部分,如果它可以推断出它的值没有被使用并且没有产生任何需要的副作用(包括由调用函数或访问易失性对象引起的任何副作用)。”我认为这让我们可以在指向 VLA 的指针上使用 sizeof
  • @BLUEPIXY 所以当 M 是变量时这不起作用?
【解决方案3】:

你有一个“指向指针的指针”。这不能表示二维数组。

指向二维数组的指针的正确声明是

// number of elements in one row
#define COLS 10

// number of rows
#define ROWS 20

int (*array)[COLS];   // mind the parenthesis!

这使得array 成为一个指向COLSints 数组的指针。类型是`int(*)[COLS],顺便说一句。但你不需要类型,见下文。

要分配数组,您应该使用一维数组的标准分配:

array = malloc(sizeof(*array) * ROWS);   // COLS is in the `sizeof`

array = malloc(sizeof(int[ROWS][COLS])); // explicit 2D array notation

使用哪种变体是个人风格。虽然第一个不包含冗余(考虑将array 的声明更改为使用INNER 而不是COLS 或将元素类型更改为float)。第二种一目了然,但修改array的声明时更容易出错。

free

free(array);

【讨论】:

  • 我很想知道反对者的反对意见是什么。
  • @MichaelPetch:我也是。但是你不能与 争论。
  • array = int (*)[COLS] malloc(ROWS*COLS*sizeof(int)) 可能更直观
  • @rfabbri 这不如我建议的第二个变体直观。此外,第一个提议的版本还保证内部索引始终与指针类型一致。对于第二个和您的变体,情况并非如此。最后:永远不要在 C 中强制转换 'void *'!这是某些编码风格的愚蠢之处之一。请注意,这在 C++ 中有所不同,但这是一种不同的语言,此处不涉及。
猜你喜欢
  • 2018-03-20
  • 2011-01-19
  • 1970-01-01
  • 2016-12-03
  • 1970-01-01
  • 2013-05-25
  • 2011-10-30
  • 1970-01-01
  • 2019-06-23
相关资源
最近更新 更多