在C语言中动态分配一个二维数组

19

每次我为2D数组分配内存时,首先创建一个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

3
你在使用C还是C++? - NathanOliver
你可以编写自己的函数,其中包含完成该操作所需的所有内容。除此之外,没有任何语法技巧可以实现这一点。 - Shady Programmer
1
参见这个回答 - John Bode
3个回答

30

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

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

使用时可以这样: arr[0][M-1];

释放内存时可以这样:free(arr);


5
更好的写法是:int (*arr)[M] = malloc(sizeof(*arr) * N);。这样,如果arr的类型发生变化,您就不必修改sizeof表达式了。 - John Bode
@JohnBode 请查看此答案 - BLUEPIXY
1
@JohnBode 在那篇帖子中,我和你持有相似的观点。然而,应该避免这样做,因为标准中没有对这种操作的任何保证。 - BLUEPIXY
3
5.1.2.3/4中有这样的语言:“在抽象机器中,所有表达式都按照语义规定进行评估。如果实际实现可以推断出一个表达式的一部分未被使用并且不产生任何必要的副作用(包括通过调用函数或访问易失对象引起的任何副作用),则不需要对其进行评估。”我认为这使我们可以在指向VLA的指针上使用sizeof - John Bode
1
@BLUEPIXY 当M是一个变量时,这个方法不起作用吗? - Anchith Acharya
显示剩余2条评论

24

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

这段代码是不正确的C代码。如果你想模拟它,可以使用一次性分配内存的方式
int *arr = malloc(N*M*sizeof(int));
并通过
arr[i*M + j]
来访问它,这相当于第一个示例中的 arr[I][j]


6
冷静点,C语言中没有二维数组,原帖作者想要做的是为一个能够容纳NxM个整数的缓冲区分配一次内存。 - fluter
2
此外,它并不完全是“过时的”,它是你今天看到的东西。这完全取决于你的用例。毕竟,你不能声明某种代码方式为“过时的”,这有点奇怪。 - fluter
1
我只是问是否有类似的方法,我从未说过那就是方法。 - ninazzo
2
@fluter:你完全可以!看看我的回答。是的,它已经过时了。只是因为有太多的程序员认为C语言中没有多维数组。但仅仅因为“我们一直这样做”并不意味着这是正确的方式。事实上,在你的版本中没有任何优势,但有很多缺点,例如:容易出错,难以理解,你必须自己跟踪内部长度。 - too honest for this site
哦,对于那个沉重的反应我很抱歉。关于数组和指针有太多的混淆了。而且有太多的程序员害怕使用复杂的数组,尽管一旦你理解了概念,它变得非常简单(不过限定符会让事情变得更糟)。 - too honest for this site
显示剩余2条评论

11

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

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

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

// number of rows
#define ROWS 20

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

那么array就是一个指向包含COLSint元素的数组的指针。类型是`int (*)[COLS]`,但您不需要类型,请参见下文。
要分配数组,您应该使用标准的1D数组分配方法:
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);

3
我很想知道下投票者反对的原因。 - Michael Petch
2
@MichaelPetch:我也是。但你不能反驳<(好吧,你可能知道我会在这里写什么)>. - too honest for this site
1
数组 = int ()[COLS] malloc(ROWSCOLS*sizeof(int)) 可能更直观 - rfabbri
1
@rfabbri 我提出的第二个变体比较不直观。此外,第一个提议版本还保证内部索引始终与指针类型一致。这对于第二种和你的变体来说并非如此。最后:在 C 语言中永远不要对 void * 进行强制转换!这是某些编码风格的愚蠢之一。请注意,C++ 中情况不同,但那是另一门语言,不在此讨论范围之内。 - too honest for this site

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接