![](/img/trans.png)
[英]dynamically allocate contiguous block of memory for 2D array of unknown data type in C 89/90 using single call to malloc
[英]How to dynamically allocate a contiguous block of memory for a 2D array
如果我分配一個像這樣的二維數組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]
但有一個重要的 GOTCHA! 你必須小心地先解除分配 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]"
請原諒我沒有格式化或有任何錯誤,但這是來自手機。
我還遇到了 strides 我嘗試使用 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
是一個常量表達式時才有效(但無論如何你應該升級你的編譯器)。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.