为二维数组 c 分配内存

allocate memory for 2d array 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;
}

然后当然我以后必须释放内存 - 但我只是不太理解这种方法,更具体地说,我真的看不到最后一行剩下的指针是什么设置到内存块中(有人告诉过我吗?我不确定完成分配后如何在 matrix/array 中插入元素。

你必须让指针指针的每个指针都指向有效的malloc()ed数据。

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

你也可以一次性全部分配,但那样的话 A[i][j] 就不行了。

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个双指针分配space。

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

A[0]现在是m*n个double的内存块,也就是我们需要的二维数组的所有double。

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].

完全相同

此外,因为所有内容都在一个大内存块中,要访问任何 i < m、j < n 的 A[i][j],我们只需访问 A[0] + i*j + j 处的双精度数。这比转到指向 double* B 的 A[i] 并找到 B[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] |
   +---+           +-----------+-----------+   +-------------+

所以基本上你在这里所做的是分配 N 单独的 M 元素数组 T,然后你在 [=22] 中收集指向这些数组的指针=]-T *的元素数组。

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

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

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

  2. 由于每个 "row" a[i] 都是通过调用 malloc 分配的,因此还必须通过相应的调用 free 显式释放它 之前,您释放 a(总是 free 的顺序与您 malloc 的顺序相反)。

  3. 尽管我们可以将 a 视为二维数组,但它没有数组类型,因此您无法使用 [=43 确定数组的大小=] 把戏;你只会得到指针类型的大小,而不是数组的总大小。所以你会想要自己跟踪数组大小。