简体   繁体   English

如何为二维数组动态分配连续的内存块

[英]How to dynamically allocate a contiguous block of memory for a 2D array

If I allocate a 2D array like this int a[N][N] ;如果我分配一个像这样的二维数组int a[N][N] ; it will allocate a contiguous block of memory.它将分配一个连续的内存块。

But if I try to do it dynamically like this :但是,如果我尝试像这样动态地执行此操作:

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

This maintains a unit stride between the elements in the rows, but this may not be the case between rows.这在行中的元素之间保持了单位步幅,但行之间可能不是这种情况。

One solution is to convert from 2D to 1D, besides that, is there another way to do it?一种解决方案是从2D转换为1D,除此之外,还有其他方法吗?

If your array dimensions are known at compile time:如果您的数组维度在编译时已知:

#define ROWS ...
#define COLS ...

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

If your array dimensions are not known at compile time, and you are using a C99 compiler or a C2011 compiler that supports variable length arrays:如果您的数组维度在编译时未知,并且您使用的是支持可变长度数组的 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);
}

If your array dimensions are not known at compile time, and you are not using a C99 compiler or a C2011 compiler that supports variable-length arrays:如果您的数组维度在编译时未知,并且您没有使用支持可变长度数组的 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);
}

In fact, n-dimensional arrays (allocated on the stack) are really just 1-dimension vectors.事实上,n 维数组(分配在堆栈上)实际上只是一维向量。 The multiple indexing is just syntactic sugar.多重索引只是语法糖。 But you can write an accessor function to emulate something like what you want:但是你可以编写一个访问器函数来模拟你想要的东西:

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

However, if you have C99 support, then declaring a pointer to an array is possible, and you can even use the syntactic sugar:但是,如果您有 C99 支持,则可以声明指向数组的指针,您甚至可以使用语法糖:

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

Say you want to dynamically allocate a 2-dimensional integer array of ROWS rows and COLS columns.假设您要动态分配 ROWS 行和 COLS 列的二维整数数组。 Then you can first allocate a continuous chunk of ROWS * COLS integers and then manually split it into ROWS rows.然后你可以先分配一个连续的 ROWS * COLS 整数块,然后手动将其拆分为 ROWS 行。 Without syntactic sugar, this reads没有语法糖,这读作

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]

and can be done more efficiently by avoiding the multiplication,并且可以通过避免乘法来更有效地完成,

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]

Finally, one could give up the extra pointer altogether,最后,人们可以完全放弃额外的指针,

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]

but there's an important GOTCHA!但有一个重要的 GOTCHA! You would have to be careful to first deallocate A[0] and then A,你必须小心地先解除分配 A[0],然后再分配 A,

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

The same idea can be extended to 3- or higher-dimensional arrays, although the code will get messy.同样的想法可以扩展到 3 维或更高维的数组,尽管代码会变得混乱。

You can treat dynamically allocated memory as an array of a any dimension by accessing it in strides:通过分步访问,您可以将动态分配的内存视为任意维度的数组:

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

Excuse my lack of formatting or any mistakes, but this is from a cellphone.请原谅我没有格式化或有任何错误,但这是来自手机。

I also encountered strides where I tried to use fwrite() to output using the int** variable as the src address.我还遇到了 strides 我尝试使用 fwrite() 使用 int** 变量作为 src 地址进行输出的情况。

One solution was to make use of two malloc() invocations:一种解决方案是使用两个 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
.
.
.

You can typedef your array (for less headake) and then do something like that:你可以 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;
}

The best way is to allocate a pointer to an array,最好的方法是分配一个指向数组的指针,

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

If the compiler doesn't support variable length arrays, that only works if cols is a constant expression (but then you should upgrade your compiler anyway).如果编译器不支持变长数组,那么只有当cols是一个常量表达式时才有效(但无论如何你应该升级你的编译器)。

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

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