簡體   English   中英

如何為二維數組動態分配連續的內存塊

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM