C - 动态矩阵分配:对我来说没有意义



我想知道,为什么这能工作

// read n as matrix dimension, then:
int* M;
M = (int*)malloc(n * n * sizeof(int));
// cycle through each "cell" in the matrix and read a number with
scanf("%d", &M[i * n + j]);

这不行吗?

// read n as matrix dimension, then:
int** M;
M = malloc(n * n * sizeof(int));
// cycle through each "cell" in the matrix and read a number with
scanf ("%d", &M[i][j]);

我只是不明白。在这两种情况下,它们都应该是双指针,对吗?

int **应该指向一个int*。在这里,您分配了一些内存 - 准确地说是sizeof(int)*rows*cols字节,然后使用M[i]等。这里基本上M[i]*(M+i)我们将访问malloc返回的一个地址的偏移量i*sizeof(int*)但您分配给rows*colsint而不是int*-s - 因此您最终将访问您不应该访问的内存(通常在sizeof(int*) > sizeof(int)的系统上),这将导致您出现未定义的行为。

那么解决方案是什么呢?很好地分配int*-s。

int ** M = malloc(sizeof *M * rows);
if(!M){
perror("malloc");
exit(EXIT_FAILURE);
}
for(size_t i = 0; i < rows; i++){
M[i] = malloc(sizeof *M[i] * cols);
if(!M[i]){
perror("malloc");
exit(EXIT_FAILURE);
}
}

对于您的情况rows = Ncols = N.

这将给你一个锯齿状的数组,你可以像以前一样访问它。malloc随之而来的是检查它的返回类型并在完成使用它时释放内存的责任。这样做。

在第一种情况下,您正在访问分配的内存块,并且您已经使用索引ij实现了内存访问,以使自己能够像在 2D 数组中那样访问内存。所以在这里使用双指针是没有意义的。你的所作所为是合法的。

在这两种情况下,它们都应该是双指针

不,他们不应该是。第一个与第二个不同。无论如何,它们都没有表示同样的事情。

案例 1 :-

int* M;
M = (int*)malloc(n * n * sizeof(int));

这里为单指针M分配内存。假设您要将5整数存储到该内存中。所以它看起来像

-------------------------------
|  10  |  20  | 30  | 40  | 50  |
-------------------------------
M  M[0]   M[1]   M[2]  m[3]  M[4] <--- Its a 1D array, only one row of 5 int

案例 2 :-

int **M;
M = malloc(n * n * sizeof(int));

M[0][0]  M[0][1] 
|         |     |    |   .......    |       |    <---- If below one is not done then how will you store the numbers into these  
-----------      -----              --------- 
|            |         |          |
M[0]         M[1]      M[2] ....  M[4]      <---  didn't allocated memory for these rows or 1D array
|            |         |          |
-----------------------------------   
|  
M                          <----  allocated memory for this 

它不起作用,因为M是双指针,并且您仅为M分配了内存,您没有为M[row]分配内存。 这就是为什么下面的语句不起作用的原因。

scanf ("%d", &M[i][j]);

所以要先让它工作 像你一样为M分配内存

M = malloc(row*sizeof(*M)); /* row indicates no of rows */

然后为每一行分配

for(int index = 0 ;index < row;index++) {
M[index] = malloc(col * sizeof(*M[index])); /* col indicates number of columns */
}

并扫描矩阵输入

for(int index = 0 ;index < row;index++) {
for(int sub_index = 0 ;sub_index < col; sub_index++)
scanf("%d",&M[index][sub_index]);
}

一旦完成矩阵的工作,就会使用每行的free()释放动态分配的内存,以避免内存泄漏

其他答案(建议一个malloc用于Mnmallocs表示行)是正确的,但不是分配矩阵的最有效方法。但是,您可以只用一个malloc调用来分配矩阵,同时仍然允许您使用M[i][j]按行和列对其进行索引,如下所示:

int (*M)[cols] = malloc(rows * sizeof *M);

这将M声明为指向长度为colsint数组的指针,并请求malloc分配此类数组的数量rows这意味着您将获得一个rows * colsints (sizeof *M == sizeof(int) * cols的单个块)。

malloc成功时,您可以使用M,就好像它被声明为int M[rows][cols]一样,以便您可以使用

scanf("%d", &M[i][j]);

它看起来更复杂,但M分配为一个连续的内存块,这允许处理器优化对它的访问。

作为额外的奖励,您还可以通过一次通话将其释放:

free(M);

这确实需要 C99 支持,或者至少支持可变长度数组,但矩阵本身不是适当的可变长度数组。它仍然由malloc分配,但M的声明允许您像使用它一样使用它。

最新更新