为 2D 阵列 C 分配内存



我一直在阅读很多关于分配内存的文章,我认为我理解这个概念,但我被告知我必须使用如下所示的方法:

double ** malloc_array2d(size_t m, size_t n)
{
    double **A;
    size_t i;
    A = malloc(m * sizeof(double *));      
    if (A == NULL) 
        return NULL;
    A[0] = (double *) malloc(m * n * sizeof(double));   
    if (A[0] == NULL) 
    {
        free(A); 
        return NULL;
    }
    for (i = 1 ; i < m ; i++) 
        A[i] = A[0] + i  *n; 
    return A;
}

然后当然,我稍后将不得不释放内存 - 但我只是不太理解这种方法,更具体地说,我无法真正看到最后一行会发生什么,其中剩余的指针被设置到内存块中(我被告知。而且我不确定完成分配后如何在矩阵/数组中插入元素。

double ** malloc_array2d(size_t m, size_t n){
    double **A;
    size_t i;
    A = malloc(m*sizeof(double *));      
    if (A == NULL) return NULL;
    A[0]=(double *)malloc(m*n*sizeof(double));   
    if ( A[0] == NULL) {free(A); return NULL;}
    for(i=1; i<m; i++) A[i]=A[0]+i*n; 
    return A;
}
让我们一行

一行地进行:

A = malloc(m*sizeof(double *));

此行为 m 双指针分配空间。

A[0] = (double *) malloc(m*n*sizeof(double));

A[0] 现在是 m*n 双精度的内存块,这是我们 2d 数组所需的所有双精度。

for (int i = 1; i < m; i++) {A[i] = A[0] + i * n;}

因为每个 A[i] 都是 n 个双精度的块,我们希望 A[i] 从 A[0] 开始 i*n 双精度。

因为所有这些都在一个坚实的内存块中,我们可以做一些有趣的事情。例如,A[0][n] 与 A[1][0] 完全相同。

此外,因为所有内容都在一个大块内存中,要访问 A[i][j] 对于任何 i <m、j>

内存管理是一个难以理解的话题,需要一些时间。希望这更有意义,我希望我没有让你更加困惑:)

使用这种分配形式,首先将指针数组分配给其他数组,如下所示:

T **a = malloc( sizeof *a * N ); // N is the number of rows

sizeof *a等价于sizeof (T *);数组的每个元素都是指向T的指针。 完成后,我们的内存中将出现类似以下内容的内容:

   +---+
a: |   | a[0]
   +---+
   |   | a[1]
   +---+
   |   | a[2]
   +---+
    ...
   +---+
   |   | a[N-1]
   +---+

现在,对于这些元素中的每一个,我们分配另一个内存块来保存每个类型为 T 的元素:

a[i] = malloc( sizeof *a[i] * M ); // M is the number of columns

每个a[i]都有类型 T *,所以sizeof *a[i]等价于 sizeof (T)

完成后,我们在内存中可以看到如下所示的内容:

   +---+           +---------+---------+   +-----------+
a: |   | a[0] ---> | a[0][0] | a[0][1] |...| a[0][M-1] |
   +---+           +---------+---------+   +-----------+
   |   | a[1] ---> | a[1][0] | a[1][1] |...| a[1][M-1] |
   +---+           +---------+---------+   +-----------+
   |   | a[2] ---> | a[2][0] | a[2][1] |...| a[2][M-1] |
   +---+           +---------+---------+   +-----------+
    ... 
   +---+           +-----------+-----------+   +-------------+
   |   | a[N-1]--> | a[N-1][0] | a[N-1][1] |...| a[N-1][M-1] |
   +---+           +-----------+-----------+   +-------------+

所以基本上你在这里所做的是分配A[0] + i*j + j0单独的M元素数组T,然后你在一个N元素数组中收集指向这些数组的指针T *

你可以像任何普通的2D数组一样a[i][j]访问每个元素;请记住,表达式a[i]被定义为*(a + i);我们从a中的地址偏移i元素(不是字节!(,然后取消引用结果。 所以a[i][j]被评估为*(*(a + i) + j ).

因此,使用这种分配形式要记住几件事:

  1. 数组的"行"在内存中不会是连续的;内存中的对象跟随a[i][M-1](很可能(不会a[i+1][0]

  2. 由于每个"行"a[i]都分配了对malloc的调用,因此在释放a之前,还必须使用相应的free调用显式解除分配(始终以与您malloc相反的顺序free(。

  3. 尽管我们可以将a视为 2D 数组,但它没有数组类型,因此您无法使用 sizeof a 技巧确定数组的大小;您只会获得指针类型的大小,而不是数组的总大小。 因此,您需要自己跟踪数组大小。

您必须使 poitners 指针的每个指针指向有效的 malloc() ed 数据。

for (int i = 0 ; i < n ; ++i)
    A[i] = (double *) malloc(m * sizeof(double)); 

您也可以一次分配所有内容,但随后符号A[i][j]将不起作用。

相关内容

  • 没有找到相关文章