簡體   English   中英

如何在 C 中使用動態多維數組?

[英]How do I work with dynamic multi-dimensional arrays in C?

有人知道我如何使用 C 使用動態分配的多維數組嗎? 那可能嗎?

從 C99 開始,C 具有動態邊界的二維數組。 如果你想避免這種野獸被分配在堆棧上(你應該這樣做),你可以一次輕松地分配它們,如下所示

double (*A)[n] = malloc(sizeof(double[n][n]));

就是這樣。 然后,您可以輕松地使用它,因為它用於具有A[i][j]類的二維數組。 別忘了最后那個

free(A);

Randy Meyers 撰寫了一系列解釋可變長度數組(VLA)的文章。

使用動態分配,使用 malloc:

int** x;

x = malloc(dimension1_max * sizeof(*x));
for (int i = 0; i < dimension1_max; i++) {
  x[i] = malloc(dimension2_max * sizeof(x[0]));
}

//Writing values
x[0..(dimension1_max-1)][0..(dimension2_max-1)] = Value; 
[...]

for (int i = 0; i < dimension1_max; i++) {
  free(x[i]);
}
free(x);

這將分配一個尺寸為dimension1_max * dimension2_max 2_max 的二維數組。 因此,例如,如果您想要一個 640*480 的數組(圖像的 fe 像素),請使用dimension1_max 1_max = 640, dimension2_max 2_max = 480。然后您可以使用x[d1][d2]訪問數組,其中d1 = 0.. 639, d2 = 0..479。

但是在 SO 或 Google 上的搜索也揭示了其他可能性,例如在這個 SO 問題中

請注意,在這種情況下,您的數組不會分配連續的內存區域(640*480 字節),這可能會給假設此的函數帶來問題。 所以為了讓數組滿足條件,用這個替換上面的 malloc 塊:

int** x;
int* temp;

x = malloc(dimension1_max * sizeof(*x));
temp = malloc(dimension1_max * dimension2_max * sizeof(x[0]));
for (int i = 0; i < dimension1_max; i++) {
  x[i] = temp + (i * dimension2_max);
}

[...]

free(temp);
free(x);

基本

c 中的數組使用[]運算符聲明和訪問。 以便

int ary1[5];

聲明一個包含 5 個整數的數組。 元素從零開始編號,因此ary1[0]是第一個元素,而ary1[4]是最后一個元素。 注1:沒有默認初始化,所以數組占用的內存最初可能包含任何內容 注2: ary1[5]訪問未定義狀態的內存(您甚至可能無法訪問),所以不要這樣做!

多維數組被實現為數組數組 (of arrays (of ... ) )。 所以

float ary2[3][5];

聲明一個由 3 個一維數組組成的數組,每個數組包含 5 個浮點數。 現在ary2[0][0]是第一個數組的第一個元素, ary2[0][4]是第一個數組的最后一個元素,而ary2[2][4]是最后一個數組的最后一個元素。 '89 標准要求這些數據是連續的(我的 K&R 第二版第 216 頁上的 A8.6.2 節),但似乎與填充無關。

嘗試在多個維度上保持動態

如果在編譯時不知道數組的大小,則需要動態分配數組。 很想嘗試

double *buf3;
buf3 = malloc(3*5*sizeof(double));
/* error checking goes here */

如果編譯器沒有填充分配(在一維數組之間留出額外空間),這應該可以工作。 使用以下方法可能更安全:

double *buf4;
buf4 = malloc(sizeof(double[3][5]));
/* error checking */

但無論哪種方式,訣竅都是在取消引用時間。 你不能寫buf[i][j]因為buf的類型錯誤。 你也不能用

double **hdl4 = (double**)buf;
hdl4[2][3] = 0; /* Wrong! */

因為編譯器期望hdl4是雙hdl4地址的地址。 你也不能使用double incomplete_ary4[][]; 因為這是一個錯誤;

所以,你可以做什么?

  • 自己做行和列算術
  • 在函數中分配和執行工作
  • 使用指針數組(qrdl 正在談論的機制)

自己做數學

簡單地計算每個元素的內存偏移量,如下所示:

  for (i=0; i<3; ++i){
     for(j=0; j<3; ++j){
        buf3[i * 5 + j] = someValue(i,j); /* Don't need to worry about 
                                             padding in this case */
     }
  }

在函數中分配和執行工作

定義一個將所需大小作為參數並正常進行的函數

void dary(int x, int y){
  double ary4[x][y];
  ary4[2][3] = 5;
}

當然,在這種情況下ary4是一個局部變量,因此不能返回它:所有與陣列的工作必須在你函數調用的,調用函數來完成。

指針數組

考慮一下:

double **hdl5 = malloc(3*sizeof(double*));
/* Error checking */
for (i=0; i<3; ++i){
   hdl5[i] = malloc(5*sizeof(double))
   /* Error checking */
}

現在hdl5指向一個指針數組,每個指針指向一個雙精度數組。 很酷的一點是你可以使用二維數組符號來訪問這個結構--- hdl5[0][2]獲取第一行的中間元素---但這仍然是一種不同的類型對象不是由double ary[3][5];聲明的二維數組double ary[3][5]; .

這種結構比二維數組更靈活(因為行不需要具有相同的長度),但訪問它通常會更慢並且需要更多內存(您需要一個地方來保存中間指針)。

請注意,由於我沒有設置任何保護,因此您必須自己跟蹤所有數組的大小。

算術

c 不支持向量、矩陣或張量數學,你必須自己實現它,或者引入一個庫。

乘以縮放器以及相同等級數組的加減法很容易:只需循環遍歷元素並執行操作即可。 內部產品同樣直接。

外部產品意味着更多的循環。

如果您知道編譯時的列數,這很簡單:

#define COLS ...
...
size_t rows;
// get number of rows
T (*ap)[COLS] = malloc(sizeof *ap * rows); // ap is a *pointer to an array* of T

您可以將ap視為任何二維數組:

ap[i][j] = x;

完成后,您將其釋放為

free(ap);

如果您在編譯時不知道列數,但您正在使用支持可變長度數組的 C99 編譯器或 C2011 編譯器,它仍然非常簡單:

size_t rows;
size_t cols;
// get rows and cols
T (*ap)[cols] = malloc(sizeof *ap * rows);
...
ap[i][j] = x;
...
free(ap);

如果您在編譯時不知道列數,並且您正在使用不支持可變長度數組的 C 版本,那么您需要做一些不同的事情。 如果您需要將所有元素分配到一個連續的塊中(如常規數組),那么您可以將內存分配為一維數組,並計算一維偏移量:

size_t rows, cols;
// get rows and columns
T *ap = malloc(sizeof *ap * rows * cols);
...
ap[i * rows + j] = x;
...
free(ap);

如果不需要內存連續,可以按照兩步分配方式:

size_t rows, cols;
// get rows and cols
T **ap = malloc(sizeof *ap * rows);
if (ap)
{
  size_t i = 0;
  for (i = 0; i < cols; i++)
  {
    ap[i] = malloc(sizeof *ap[i] * cols);
  }
}

ap[i][j] = x;

由於分配是一個兩步過程,因此釋放也需要是一個兩步過程:

for (i = 0; i < cols; i++)
  free(ap[i]);
free(ap);

malloc 會做。

 int rows = 20;
 int cols = 20;
 int *array;

  array = malloc(rows * cols * sizeof(int));

請參閱以下文章尋求幫助:-

http://courses.cs.vt.edu/~cs2704/spring00/mcquain/Notes/4up/Managing2DArrays.pdf

這是定義子例程make_3d_array工作代碼,用於在每個維度分配具有N1N2N3元素的多維 3D 數組,然后用隨機數填充它。 您可以使用符號A[i][j][k]來訪問其元素。

#include <stdio.h>
#include <stdlib.h>
#include <time.h>


// Method to allocate a 2D array of floats
float*** make_3d_array(int nx, int ny, int nz) {
    float*** arr;
    int i,j;

    arr = (float ***) malloc(nx*sizeof(float**));

    for (i = 0; i < nx; i++) {
        arr[i] = (float **) malloc(ny*sizeof(float*));

        for(j = 0; j < ny; j++) {
            arr[i][j] = (float *) malloc(nz * sizeof(float));
        }
    }

    return arr;
} 



int main(int argc, char *argv[])
{
    int i, j, k;
    size_t N1=10,N2=20,N3=5;

    // allocates 3D array
    float ***ran = make_3d_array(N1, N2, N3);

    // initialize pseudo-random number generator
    srand(time(NULL)); 

    // populates the array with random numbers
    for (i = 0; i < N1; i++){
        for (j=0; j<N2; j++) {
            for (k=0; k<N3; k++) {
                ran[i][j][k] = ((float)rand()/(float)(RAND_MAX));
            }
        }
   }

    // prints values
    for (i=0; i<N1; i++) {
        for (j=0; j<N2; j++) {
            for (k=0; k<N3; k++) {
                printf("A[%d][%d][%d] = %f \n", i,j,k,ran[i][j][k]);
            }
        }
    }

    free(ran);
}

沒有辦法一次性分配整個事情。 相反,創建一個指針數組,然后為每個指針創建內存。 例如:

int** array;
array = (int**)malloc(sizeof(int*) * 50);
for(int i = 0; i < 50; i++)
    array[i] = (int*)malloc(sizeof(int) * 50);

當然,你也可以將數組聲明為int* array[50]並跳過第一個 malloc,但是為了動態分配所需的存儲,需要第二個集合。

有可能在一個步驟中破解一種方法來分配它,但這需要一個自定義查找函數,但是以這樣的方式編寫它總是可以工作可能會很煩人。 一個例子可能是L(arr,x,y,max_x) arr[(y)*(max_x) + (x)] ,然后 malloc 一個 50*50 整數塊或其他任何東西,並使用該L宏訪問,例如

#define L(arr,x,y,max_x) arr[(y)*(max_x) + (x)]

int dim_x = 50;
int dim_y = 50;

int* array = malloc(dim_x*dim_y*sizeof(int));

int foo = L(array, 4, 6, dim_x);

但這更令人討厭,除非您知道使用預處理器宏所做的事情的影響。

int rows, columns;
/* initialize rows and columns to the desired value */

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

// 使用 new 而不是 malloc 因為使用 malloc 會導致內存泄漏 `在此處輸入代碼

    int **adj_list = new int*[rowsize];       
    for(int i = 0; i < rowsize; ++i)    
    {

        adj_list[i] = new int[colsize];

    }

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

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