为2d数组c

时间:2015-10-18 15:41:57

标签: c arrays malloc

我一直在阅读很多关于分配内存的帖子,我认为我理解这个概念,但我被告知我必须使用类似这样的方法:

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;
}

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

3 个答案:

答案 0 :(得分:2)

使用这种形式的分配,首先要为其他数组分配一个指针数组,如下所示:

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的元素数组,然后你收集N中那些数组的指针 - T *的元素数组。

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

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

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

  2. 由于每个“行”a[i]都分配了对malloc的调用,因此必须在{/ 1}} 之前显式取消分配free em>您按照a的相反顺序解除free {始终malloc

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

答案 1 :(得分:1)

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]开始i * n从A [0]开始加倍。

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

此外,因为所有内容都在一个大的内存块中,所以要访问A [i] [j]以获得任何i&lt; m,j&lt; n,我们只需访问A[0] + i*j + j处的双精度数。这比去A [i]要快得多,它指向一个双* B,并找到B [j]。

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

答案 2 :(得分:-2)

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

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

您也可以一次性分配所有内容,但后续符号A[i][j]将无效。