如何在C语言中使用动态二维数组

4

我尝试创建一个动态的5x5整数数组

int **data=malloc(5*5);

但是当我尝试访问它时,出现了分段错误。

那只会分配25个字节。如果你想让你的数组容纳25个整数,就要乘以sizeof int。 - bruceg
5个回答

7

您需要为要创建的二维数组分配内存(我认为您已经理解了)。但首先,您需要为指针分配空间,以便存储二维数组的行。

int **data=(int**)malloc(sizeof(*data)*5); //Here 5 is the number of rows

现在,您可以为每一行分配空间。
for(int r=0;r<5;r++){
  data[r]=(int*)malloc(sizeof(**data)*5);//here 5 is the width of the array
}

如果你想要整个数组的连续内存块,可以分配一个大小为25的单一维度数组,并像这样访问它:data[r*5+c]
提示:可以使用sizeof(int*)sizeof(int)代替sizeof(*data)sizeof(**data),以避免与*混淆。
提示:如果你不使用C++,则最好从malloc的返回值中删除转换(请参阅注释)。

5
不建议并且也不必要将malloc的结果强制转换,应该保持原样。 - Manos Nikolaidis
为什么不推荐这样做? - user5582674
@MeghanRagroe 不建议不转换malloc的结果,也不需要这样做。 - this
这变得有些混乱了...不过链接的问题对此很有帮助...我想我可能会使用一些C++特性,所以保持转换看起来还不错。 - user5582674
1
通常,显式转换是一种对类型系统进行X光检查并重新解释位和字节含义的方法。虽然即使在隐式情况下也必须发生这种情况,但这是一种笨重且危险的武器。如果要执行比必要更多的操作,则存在某人会受伤的风险。如果编译器可以为您安全、明确和高效地执行操作,则无需尝试用人手替换其工作。当然,如果您计划移植到C ++,那么这是一个完全不同的故事,因为那里需要转换(但可能不应该在此处使用malloc)。 - user4842163

4

如果你想要一个单一的连续内存块来存储 5x5=25 个整数:

int *data = malloc(5*5*sizeof(*data));

如果您想要一个大小为5x5的二维数组。
int **data = malloc(5*sizeof(*data));
for (int i=0; i<5; ++i)
    data[i] = malloc(5*sizeof(**data));

3

有两种可能性。第一种是确实分配一个二维数组:

int ( *data )[5] = malloc( 5 * 5 * sizeof( int ) );

在这种情况下,数组被分配了一个连续的范围。
第二种方法是首先分配一个指针的一维数组,然后分配已分配指针所指向的一维数组。
例如:
int **data = malloc( 5 * sizeof( int * ) );
for ( size_t i = 0; i < 5; i++ )
{
    data[i] = malloc( 5 * sizeof( int ) );
}

在这种情况下,实际上分配了6个内存范围:一个用于指针数组,另外5个用于整数数组。
要释放第一个示例中分配的内存,只需编写以下内容即可。
free( data );

在第二个例子中,您需要编写以下内容:

for ( size_t i = 0; i < 5; i++ ) free( data[i] );
free( data );

0
如果您想将数组视为二维数组(a[i][j]并且希望所有数组元素在内存中是连续的,请执行以下操作:
int (*data)[5] = malloc( sizeof *data * 5 );

如果你也想在运行时确定数组的大小并且你的编译器支持可变长度数组1

size_t rows, cols;
...    
int (*data)[rows] = malloc( sizeof *data * cols );<sup>2</sup>

如果你的编译器不支持可变长度数组(VLA),但你仍想在运行时确定数组大小,你可以这样做:

size_t rows, cols;
...
int **data = malloc( sizeof *data * rows );
if ( data )
{
   for ( size_t i = 0; i < rows; i++ )
   {
     data[i] = malloc( sizeof *data[i] * cols );
   }
}

这种方法的缺点是数组的行在内存中不保证是连续的(它们很可能不是)。单个行内的元素将是连续的,但是行与行之间不会连续。

如果您想在运行时确定数组大小,并且希望所有数组元素在内存中是连续的,但是您的编译器不支持可变长度数组,则需要分配一个一维数组并手动计算索引(a[i * rows + j]):

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


1. VLAs是在C99中引入的,但在C2011中变成了可选项。如果一个后C99的编译器没有定义宏__STDC_NO_VLA__,则应该支持VLAs。

2. 注意 - 在这个例子中,sizeof *data是否被很好地定义存在一些问题;sizeof表达式通常在编译时计算,但当操作数是VLA时,表达式在运行时计算。data还没有指向任何东西,尝试解引用无效指针会导致未定义的行为。我只能说我经常使用这个习惯用法,从来没有遇到过问题,但这可能更多是由于运气不好而不是设计问题。


-1

这里是答案:

int ** squaredMatrix;
int szMatrix=10;
squaredMatrix= (int**)malloc(szMatrix*sizeof(int*));

如果要创建二维数组,您应该将它们视为一个数组,其中每个块再次是一个数组。 enter image description here

例如,在上面的图片中,蓝色块组成一个数组,每个蓝色块指向一个数组(每行的4个绿色块是一个数组,列中的蓝色块是主数组)。


你的代码没有按照图片所示分配内存。 - this
@this,我并没有说图片与代码有关系,图片的描述在下面。 - S.A.Parkhid
我想说的是你的代码不正确。 - this
@this,我已经标记了你的第一条评论,因为你的理由和你的反对票,哪里出了问题?如果你是指szMatrix,那么它是一个可选参数,他可以将其设置为5或任何其他数字。 - S.A.Parkhid
代码明确地只为指针分配内存,没有其他的。这不是 OP 请求的交错的二维数组。 - this
请再读一些C/C++书籍,它们可以正确地工作。在这个问题中,@Yash Gupta的第一个答案以及'Vlad from Moscow'的答案使用了我提到的相同方法。 - S.A.Parkhid

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