【问题标题】:How to dynamically allocate a contiguous block of memory for a 2D array如何为二维数组动态分配连续的内存块
【发布时间】:2012-11-12 03:58:54
【问题描述】:

如果我像这样分配一个二维数组 int a[N][N];它将分配一个连续的内存块。

但如果我尝试像这样动态地做:

int **a = malloc(rows * sizeof(int*));
for(int i = 0; i < rows; i++) 
   a[i] = malloc(cols * sizeof(int));

这会在行中的元素之间保持一个单位步长,但行之间可能不是这样。

一种解决方案是从 2D 转换为 1D,除此之外,还有其他方法吗?

【问题讨论】:

标签: c arrays multidimensional-array


【解决方案1】:

请原谅我缺少格式或任何错误,但这是来自手机。

我还遇到了一些进步,我尝试使用 fwrite() 将 int** 变量作为 src 地址进行输出。

一种解决方案是使用两个 malloc() 调用:

#define HEIGHT 16
#define WIDTH 16

.
.
.
//allocate
int **data = malloc(HEIGHT * sizeof(int **));
int *realdata = malloc(HEIGHT * WIDTH * sizeof(int));

//manually index
for (int i = 0; i < HEIGHT; i++)
    data[i] = &realdata[i * WIDTH];

//populate
int idx = 0;
for (int i = 0; i < HEIGHT; i++)
    for (int j = 0; j < WIDTH; j++)
        data[i][j] = idx++;

//select
int idx = 0;
for (int i = 0; i < HEIGHT; i++)
{
    for (int j = 0; j < WIDTH; j++)
        printf("%i, ", data[i][j]);
    printf("/n");
}

//deallocate
.
.
.

【讨论】:

    【解决方案2】:

    假设您要动态分配一个由 ROWS 行和 COLS 列组成的二维整数数组。然后你可以先分配一个连续的 ROWS * COLS 整数块,然后手动将其拆分为 ROWS 行。没有语法糖,这就是

    int *mem = malloc(ROWS * COLS * sizeof(int));
    int **A = malloc(ROWS * sizeof(int*));
    for(int i = 0; i < ROWS; i++) 
       A[i] = mem + COLS*i;
    // use A[i][j]
    

    并且可以通过避免乘法来更有效地完成,

    int *mem = malloc(ROWS * COLS * sizeof(int));
    int **A = malloc(ROWS * sizeof(int*));
    A[0] = mem;
    for(int i = 1; i < ROWS; i++) 
       A[i] = A[i-1] + COLS;
    // use A[i][j]
    

    最后,可以完全放弃额外的指针,

    int **A = malloc(ROWS * sizeof(int*));
    A[0] = malloc(ROWS * COLS * sizeof(int));
    for(int i = 1; i < ROWS; i++) 
       A[i] = A[i-1] + COLS;
    // use A[i][j]
    

    但是有一个重要的问题!您必须小心先释放 A[0],然后再释放 A,

    free(A[0]);
    free(A);              // if this were done first, then A[0] would be invalidated
    

    同样的想法可以扩展到 3 维或更高维的数组,尽管代码会变得混乱。

    【讨论】:

    • 使用它的代码仍然必须通过行指针数组的额外间接。除非您希望能够通过重新排列指针元素来交换行,否则我不建议这样做。
    • 顺便说一句,编译器通常会为您进行“避免乘法”优化,使用tmp += COLS 而不是i*COLSen.wikipedia.org/wiki/Strength_reduction。您将其编写为A[i-1]+COLS 的方式也应该可以优化,但我不会打扰。
    【解决方案3】:

    实际上,n 维数组(分配在堆栈上)实际上只是一维向量。多重索引只是语法糖。但是你可以编写一个访问器函数来模拟你想要的东西:

    int index_array(int *arr, size_t width, int x, int y)
    {
        return arr[x * width + y];
    }
    
    const size_t width = 3;
    const size_t height = 2;
    int *arr = malloc(width * height * sizeof(*arr));
    
    // ... fill it with values, then access it:
    
    int arr_1_1 = index_array(arr, width, 1, 1);
    

    但是,如果您支持 C99,则可以声明指向数组的指针,您甚至可以使用语法糖:

    int (*arr)[width] = malloc(sizeof((*arr) * height);
    arr[x][y] = 42;
    

    【讨论】:

      【解决方案4】:

      如果您的数组维度在编译时已知:

      #define ROWS ...
      #define COLS ...
      
      int (*arr)[COLS] = malloc(sizeof *arr * ROWS);
      if (arr) 
      {
        // do stuff with arr[i][j]
        free(arr);
      }
      

      如果您的数组维度在编译时未知,并且您使用的是支持可变长度数组的 C99 编译器或 C2011 编译器:

      size_t rows, cols;
      // assign rows and cols
      int (*arr)[cols] = malloc(sizeof *arr * rows);
      if (arr)
      {
        // do stuff with arr[i][j]
        free(arr);
      }
      

      如果您的数组维度在编译时未知,并且您没有使用支持可变长度数组的 C99 编译器或 C2011 编译器:

      size_t rows, cols;
      // assign rows and cols
      int *arr = malloc(sizeof *arr * rows * cols);
      {
        // do stuff with arr[i * rows + j]
        free(arr);
      }
      

      【讨论】:

        【解决方案5】:

        最好的办法是分配一个指向数组的指针,

        int (*a)[cols] = malloc(rows * sizeof *a);
        if (a == NULL) {
            // alloc failure, handle or exit
        }
        
        for(int i = 0; i < rows; ++i) {
            for(int j = 0; j < cols; ++j) {
                a[i][j] = i+j;
            }
        }
        

        如果编译器不支持可变长度数组,那只有在 cols 是一个常量表达式时才有效(但无论如何你都应该升级你的编译器)。

        【讨论】:

        • 措辞:这是为 2D 数组分配 空间,或者更简单地说“分配一个真正的 2D 数组”。指向它的指针 (a) 是自动存储中的局部变量,因此不必手动分配。
        【解决方案6】:

        你可以 typedef 你的数组(为了减少头疼)然后做类似的事情:

        #include <stdlib.h>
        #define N 10
        typedef int A[N][N];
        int main () {
          A a; // on the stack
          a[0][0]=1;
          A *b=(A*)malloc (sizeof(A)); // on the heap
          (*b)[0][0]=1;
        }
        

        【讨论】:

          【解决方案7】:

          您可以将动态分配的内存视为 any 维度的数组,方法是跨步访问它:

          int * a = malloc(sizeof(int) * N1 * N2 * N3);  // think "int[N1][N2][N3]"
          
          a[i * N2 * N3 + j * N3 + k] = 10;              // like "a[i, j, k]"
          

          【讨论】:

            猜你喜欢
            • 2021-12-02
            • 1970-01-01
            • 1970-01-01
            • 2013-02-05
            • 2022-01-06
            • 1970-01-01
            • 1970-01-01
            • 2020-07-11
            相关资源
            最近更新 更多