如果我像这样分配一个二维数组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,除此之外,还有另一种方法吗?
如果我像这样分配一个二维数组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,除此之外,还有另一种方法吗?
如果您的数组维度在编译时已知:
#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);
}
事实上,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;
假设您要动态分配 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 维或更高维的数组,尽管代码会变得混乱。
您可以通过大步访问动态分配的内存作为任意维度的数组:
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]"
请原谅我缺乏格式或任何错误,但这是来自手机。
在尝试使用 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
.
.
.
您可以 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;
}
最好的方法是分配一个指向数组的指针,
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
它是一个常量表达式时才有效(但无论如何你都应该升级你的编译器)。