【问题标题】:allocate memory for 2d array c为二维数组 c 分配内存
【发布时间】:2015-10-18 15:41:57
【问题描述】:

我已经阅读了很多关于分配内存的帖子,并且我认为我理解了这个概念,但有人告诉我必须使用看起来像这样的方法:

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

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

【问题讨论】:

  • 你可以随时谷歌..
  • 你也可以保持一致,你第二次投malloc()只是根本不这样做,或者即使它丑陋和不必要但也要保持一致。
  • for 循环非常小,尝试取小的具体值(比如m=n=2),然后写出函数的作用,扩展循环迭代。为分配的块和指针画框和箭头...如果您仍然看不到发生了什么,请说明您确实了解哪些位。
  • 不是一个二维数组,而是一个奇怪的模拟。这属于博物馆,现代C自C99以来可以做得更好。只需使用double (*arr)[m] = malloc(sizeof(double[n][m])); 一次性分配一个二维数组。您甚至不需要为此提供特殊功能。

标签: c arrays malloc


【解决方案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 双精度的内存块,这是二维数组所需的所有双精度。

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 A[0] + i*j + j 的双精度数。这比转到指向双 * B 的 A[i] 并找到 B[j] 快得多。

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

【讨论】:

  • 谢谢!这完全有道理:)
【解决方案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-element 数组T,然后将指向这些数组的指针收集到N-element 数组T * 中。

您可以使用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. 1234563 @(始终为 free,与您 malloc 的顺序相反)。
  3. 尽管我们可以将a 视为二维数组,但它没有数组类型,因此您无法使用sizeof a 技巧确定数组的大小;你只会得到指针类型的大小,而不是数组的总大小。因此,您需要自己跟踪数组大小。

【讨论】:

    【解决方案3】:

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

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

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

    【讨论】:

    • 问题中的代码确实有效。它一次全部分配,然后将指针指向分配的块。
    • 是的,我认为这是我在谷歌搜索时最常看到的方法——这在我的脑海中是有道理的——但我刚刚被告知这是一种“幼稚”的方法,而且是一种更快的方法是分配一个大块 m*n 的内存,然后设置然后设置指向这个内存块的指针 - 我的书说要这样做:)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2015-02-01
    • 2012-12-25
    • 2012-02-05
    • 1970-01-01
    • 1970-01-01
    • 2014-07-19
    相关资源
    最近更新 更多