如何为2D阵列动态分配连续的内存块

时间:2012-11-23 19:48:36

标签: c arrays multidimensional-array

如果我像这样分配一个2D数组 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,除此之外,还有另一种方法吗?

7 个答案:

答案 0 :(得分:20)

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

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

答案 1 :(得分:8)

事实上,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;

答案 2 :(得分:4)

假设您要动态分配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]

但是有一个重要的GOTCHA!您必须小心首先取消分配A [0]然后取消分配A,

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

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

答案 3 :(得分:2)

您可以通过大步访问它来将动态分配的内存视为任何维的数组:

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]"

答案 4 :(得分:2)

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

我也遇到了一些步骤,我尝试使用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
.
.
.

答案 5 :(得分:1)

你可以输入你的数组(减少头痛),然后做类似的事情:

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

答案 6 :(得分:1)

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

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是常量表达式时才有效(但是你应该升级你的编译器)。