繁体   English   中英

为2D数组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;
}

然后当然,我以后必须释放内存-但我只是不太了解这种方法,更具体地说,我无法真正看到最后一行中剩余的指针设置到块中的情况。内存(有人告诉我。我不确定分配完成后如何在矩阵/数组中插入元素。

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

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单独的T M元素数组,然后在T *N元素数组中收集指向这些数组的指针。

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

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

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

  2. 由于每个“行” a[i]与一个呼叫分配malloc ,它也必须明确将其相应的呼叫释放,以free取消分配之前 a (总是free相反的顺序,你malloc )。

  3. 即使我们可以将a视为2D数组,它也没有数组类型,因此您无法使用sizeof a技巧来确定数组的sizeof 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个double,这是我们2d数组所需的所有double。

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

因为每个A [i]都是n个double的块,所以我们希望A [i]从a [0]开始i * n个double。

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

此外,由于所有内容都在一个大的内存块中,因此要访问A [i] [j]的任何i <m,j <n,我们只需要访问A[0] + i*j + j的双A[0] + i*j + j 这比转到指向双* B并找到B [j]的A [i]快得多。

内存管理是一个很难理解的主题,需要花费一些时间。 希望这更有意义,我希望我不要再让您感到困惑了:)

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

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

您也可以一次分配全部,但是符号A[i][j]将不起作用。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM