一种不同的方式来动态分配二维数组吗?

8
我想使用malloc声明一个二维数组。在网上搜索后,所有的网站都说要先声明一个int **指针,然后使用malloc为每个一维数组分配内存,并再次使用malloc为每个整数分配空间。 我的疑问是,这种方式声明的数组没有将其元素保存在连续的内存地址中。而下面的方法只使用一个malloc语句动态分配二维数组,并且所有地址都是连续的,符合要求。所以,下面的方式难道不是动态分配二维数组的正确方式吗?
#include <stdio.h>

int main(){
    int (*p)[2] = malloc(3 * sizeof *p);
    int i;
    int j;

        //All addresses printed here are contiguous
    for(i=0; i<3; i++){
        for(j=0; j<2; j++){
            printf("%d\t", &p[i][j]);
        }
        printf("\n");
    }
}

7
这是正确分配二维数组的方法;你之前所描述的是一种嵌套数组,但如果不存储各个子数组的长度,则几乎没有用处。将魔数24更改为3 * sizeof *p,就可以开始使用了。 - Christoph
4
不应该使用 %d 打印指针,应该使用 %p,为了完全的可移植性,你还需要将其转换为 void* - Christoph
当引用数组元素时,为什么要使用&p?这是为了检查地址而不是值吗? - v_2e
3个回答

5
那么动态分配二维数组的正确方法不应该是下面这样吗?因为这种方法相当于声明一个多维的“静态分配”数组。原因在于,使用这种方式可以获得连续的内存块,这很方便(你无法对指向指针的指针使用memset(),对吧?),同时你仍然可以让编译器为你执行指针算术和数组下标计算(这也很方便)。顺便说一下,如果你需要一个大小动态的数组,其作用域仅限于一个函数内部,即你不需要将其返回,请考虑使用具有自动存储期限的VLA(变长数组)。

2
你的二维数组并不是完全动态的,因为其中一个维度被固定为两个元素。(在你的特定示例中,你可以使用可变长度数组,但通常情况下,你可能希望能够从函数返回分配的数组。)
如果你想要一个在语法上像2D M×N数组、完全动态分配,并且使用连续内存的东西,你可以分配一个M * N元素的内存块,然后分配一个M指针的数组,每个元素指向M * N块的一行。 comp.lang.c FAQ中的Q6.16有一个很好的图表和更详细的解释。
(好吧,它不是完全连续的,因为指针数组和项块是分开的。你可以将它们一起分配,但这会更棘手,因为它需要一些额外的工作来保证正确的对齐。)

1
维度不是固定的,问题中代码中显示的2不一定是一个常量。自1999年以来,C标准已经支持可变长度数组。任何正值的整数表达式都可以使用,即使它的值只在运行时可用。 - Eric Postpischil
@EricPostpischil 是的,我知道可变长度数组,但函数无法返回它,所以它不是很通用。我已经更新了我的答案来解释这一点。 - jamesdlin
如果调用者不知道维度,你需要2或3个输出,因此不能只返回指针。你可以通过引用返回行长度(如果非正方形还有行数),并让调用者转换返回的指针。你可能需要将它保存在void*中,以便调用者可以在声明指向数组的指针返回值类型之前获取维度,但是可以传递指向2D数组及其维度的指针,并类似地接收它们。 - Peter Cordes

-4

换句话说:

include < stdio.h>
include < stdlib.h>
const int **MAXX** = 10 ;
const int **MAXY** = 10 ;
int main () {
 int *p = ( int * ) malloc ( **MAXX * MAXY** ) ;
 int x=3 ;
 int y=4 ;
 ***( p + MAXX * x + y )** = 12 ;
 printf ( "\n%d ",***( p + MAXX * x + y )** );
 return 0 ;
}

这是分配和使用二维数组的最简单方法。


4
我强烈建议你从答案中删除那些额外的 * 符号。它们只会使代码难以理解和无法编译。 - Hong Ooi
4
(1) 自 1999 年起,C 标准已经支持变长数组,并且应该使用它们来代替显式表达的算术运算。 (2) malloc(MAXX*MAXY) 不会为 MAXX*MAXYint 对象分配空间。 - Eric Postpischil

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