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

C - dynamic matrix allocation: something doesn't make sense to me

我想知道,为什么这样做有效

// 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]);

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

案例 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() 释放动态分配的内存,以 避免内存泄漏 .

int ** 应该指向 int*。在这里你已经分配了一些内存 - 准确地说是 sizeof(int)*rows*cols 字节,然后你使用 M[i] 等。这里 M[i] 基本上是 *(M+i) 我们将访问 i*sizeof(int*) 偏移量来自 malloc 编辑的一个地址 return 但你分配给 rows*cols int 而不是 int*-s - 所以你最终会访问你应该访问的内存't(通常在 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 负责检查它的 return 类型,并在您使用完它后释放内存。这样做。

在第一种情况下,您正在访问分配的内存块,并且您已经使用索引 ij 实现了内存访问,让您自己体验访问内存的感觉,以防万一二维数组。所以在这里使用双指针是没有意义的。你所做的是合法的。

In both cases they should be double pointers

不,他们不应该。第一个与第二个不同。无论如何,它们并不表示同一件事。

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

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

这将 M 声明为 指向长度为 colsint 数组的指针,并请求 malloc 分配 rows 这样的数组的数量,这意味着你得到一个 rows * cols ints (sizeof *M == sizeof(int) * cols).

的单个块

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

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

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

作为额外的奖励,您还可以通过一个电话免费使用它:

free(M);

这确实需要 C99 支持,或者至少支持 variable-length 数组,但矩阵本身不是合适的 variable-length 数组。它仍然是由 malloc 分配的,但是 M 的声明允许你像一个一样使用它。