首页 文章

为2d数组分配内存c

提问于
浏览
0

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

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 回答

  • 2
    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]完全相同 .

    此外,因为一切都在一个大的内存块中,要访问任何i <m,j <n的A [i] [j],我们只需要访问 A[0] + i*j + j 处的double . 这比去A [i]要快得多,它指向一个双* B,并找到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 ,然后在 T *N -element数组中收集指向那些数组的指针 .

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

    所以,这种形式的分配要记住几件事:

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

    • 由于每个"row" a[i] 分配了对 malloc 的调用,因此在释放 a (总是 freemalloc 的反向顺序)之前,还必须使用对 free 的相应调用显式取消分配 .

    • 尽管我们可以将 a 视为2D数组,但它没有数组类型,因此您无法使用 sizeof a 技巧确定数组的大小;你'll only get the size of the pointer type, not the total size of the array. So you'我想自己跟踪数组大小 .

  • 1

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

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

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

相关问题