Come vengono memorizzati gli array 3D in C?

Capisco che gli array in C sono assegnati in ordine di riga-maggiore. Pertanto, per un array 2 x 3:

0 1 2 3 4 5 

È archiviato in memoria come

 0 1 2 3 4 5 

Tuttavia, cosa succede se ho un array 2 x 3 x 2:

 0 1 2 3 4 5 

e

 6 7 8 9 10 11 

Come sono conservati in memoria? È solo consecutivo come:

     0 1 2 3 4 5 6 7 8 9 10 11 

    O è un altro modo? O dipende da qualcosa?

    Tutte le “dimensioni” sono memorizzate consecutivamente in memoria.

    Prendere in considerazione

      int arr[4][100][20]; 

    puoi dire che arr[1] e arr[2] (di tipo int[100][20] ) sono contigui
    o che arr[1][42] e arr[1][43] (di tipo int[20] ) sono contigui
    o che arr[1][42][7] e arr[1][42][8] (di tipo int ) sono contigui

    Ad un livello basso, non esiste una matrice multidimensionale. C’è solo un blocco piatto di memoria, abbastanza grande da contenere un determinato numero di elementi. In C, una matrice multidimensionale è concettualmente una matrice i cui elementi sono anche matrici. Quindi se lo fai:

     int array[2][3]; 

    Concettualmente si finisce con:

     array[0] => [0, 1, 2] array[1] => [0, 1, 2] 

    Ciò comporta che gli elementi siano disposti in modo contiguo nella memoria, poiché array[0] e array[1] non contengono effettivamente alcun dato, sono solo riferimenti ai due array interni. Nota che ciò significa che solo le voci [0, 1, 2] occupano effettivamente spazio nella memoria. Se estendi questo modello alla dimensione successiva, puoi vedere che:

     int array[2][3][2]; 

    … ti darà una struttura come:

     array[0] => [0] => [0, 1] [1] => [0, 1] [2] => [0, 1] array[1] => [0] => [0, 1] [1] => [0, 1] [2] => [0, 1] 

    Che continua a disporre gli elementi consecutivamente in memoria (come sopra, solo le [0, 1] voci occupano effettivamente spazio nella memoria, tutto il resto è solo parte di un riferimento a una di queste voci). Come puoi vedere, questo modello continuerà, indipendentemente da quante dimensioni hai.

    E solo per divertimento:

     int array[2][3][2][5]; 

    Ti dà:

     array[0] => [0] => [0] => [0, 1, 2, 3, 4] [1] => [0, 1, 2, 3, 4] [1] => [0] => [0, 1, 2, 3, 4] [1] => [0, 1, 2, 3, 4] [2] => [0] => [0, 1, 2, 3, 4] [1] => [0, 1, 2, 3, 4] array[1] => [0] => [0] => [0, 1, 2, 3, 4] [1] => [0, 1, 2, 3, 4] [1] => [0] => [0, 1, 2, 3, 4] [1] => [0, 1, 2, 3, 4] [2] => [0] => [0, 1, 2, 3, 4] [1] => [0, 1, 2, 3, 4] 

    Sì, hai ragione – sono archiviati consecutivamente. Considera questo esempio:

     #include  int array3d[2][3][2] = { {{0, 1}, {2, 3}, {3, 4}}, {{5, 6}, {7, 8}, {9, 10}} }; int main() { int i; for(i = 0; i < 12; i++) { printf("%d ", *((int*)array3d + i)); } printf("\n"); return 0; } 

    Produzione:

    0 1 2 3 3 4 5 6 7 8 9 10

    Sì, sono archiviati solo in ordine consecutivo. Puoi testarlo in questo modo:

     #include  int main (int argc, char const *argv[]) { int numbers [2][3][4] = {{{1,2,3,4},{5,6,7,8},{9,10,11,12}} ,{{13,14,15,16},{17,18,19,20},{21,22,23,24}}}; int i,j,k; printf("3D:\n"); for(i=0;i<2;++i) for(j=0;j<3;++j) for(k=0;k<4;++k) printf("%i ", numbers[i][j][k]); printf("\n\n1D:\n"); for(i=0;i<24;++i) printf("%i ", *((int*)numbers+i)); printf("\n"); return 0; } 

    Ciò significa che gli accessi a una matrice multiindice con dimensioni (N, M, L) vengono trasformati in accessi unidimensionali come questo:

     array[i][j][k] = array[M*L*i + L*j + k] 

    Penso che tu abbia risposto alla tua stessa domanda. Gli array multidimensionali sono memorizzati in ordine di riga maggiore.

    Vedere la sezione 3.3.2.1 delle specifiche ANSI C (esiste anche un esempio specifico):

    I successivi operatori di pedici designano un membro di un object array multidimensionale. Se E è una matrice n-dimensionale (n = 2) con dimensioni ixj “x … x” k, allora E (usato come diverso da un lvalue) viene convertito in un puntatore a una matrice (n -1) -dimensionale con dimensioni j “x … x” k. Se l’operatore unario * viene applicato esplicitamente a questo puntatore, o implicitamente come risultato dell’abbonamento, il risultato è l’array puntato a (n -1) -dimensioni, che a sua volta viene convertito in un puntatore se usato come diverso da un lvalue . Ne consegue che gli array sono memorizzati in ordine di riga maggiore (l’ultimo indice varia più velocemente).

    Per il tuo esempio, puoi semplicemente provarlo e vedere – http://codepad.org/10ylsgPj

    Diciamo che hai un array char arr[3][4][5] . È una matrice di 3 matrici di 4 matrici di 5 caratteri.

    Per semplicità, diciamo che il valore in arr[x][y][z] è xyz e in arr[1][2][3] memorizziamo 123 .

    Quindi il layout in memoria è:

      | 00 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 --+-------------------------------------------------------------------------------- 00| 000 001 002 003 004 010 011 012 013 014 020 021 022 023 024 030 031 032 033 034 20| 100 101 102 103 104 110 111 112 113 114 120 121 122 123 124 130 131 132 133 134 40| 200 201 202 203 204 210 211 212 213 214 220 221 222 223 224 230 231 232 233 234 

    arr[0] , arr[1] e arr[2] vengono uno dopo l’altro, ma ogni elemento nel è di tipo char[4][5] (quelle sono le tre righe nella tabella).

    arr[x][0] - arr[x][3] vengono anche uno dopo l’altro, e ogni elemento in essi è di tipo char[5] (quelli sono le quattro parti di ogni riga nella tabella, 000 – 004 è un elemento di arr[0][0] )

    arr[x][y][0] - arr[x][y][4] sono 5 byte che arrivano uno dopo l’altro.

    Per rispondere al commento di OP alla domanda principale (sarà un po ‘lungo, quindi ho deciso di andare con una risposta, non un commento):

    Le matrici in C devono essere dichiarate come array[ny][nx] dove ny e nx sono il numero di elementi nella direzione ye x. Inoltre, vuol dire che il mio array 3D dovrebbe essere dichiarato come array[nz][ny][nx] ?

    In matematica, una matrice MxN ha righe M e colonne N. Una notazione usuale per un elemento matrix è a(i,j), 1<=i<=M, 1<=j<=N Quindi la prima matrice nella tua domanda è una matrice 3x2.

    In effetti è diverso dalla notazione tipicamente usata per es. Elementi della GUI. Una bitmap 800x600 ha 800 pixel orizzontali (lungo l'asse X) e 600 pixel verticalmente (lungo l'asse Y). Se alcuni vorrebbero descriverlo come una matrice, nella notazione matematica sarebbe una matrice 600x800 (600 righe, 800 colonne).

    Ora, gli array multidimensionali in C sono archiviati in memoria in modo tale che a[i][j+1] sia vicino a a[i][j] mentre a[i+1][j] è N elementi lontani. Di solito si dice che "l'ultimo pedice varia più velocemente", o spesso come "archiviato da righe": una riga (cioè elementi con lo stesso primo indice) in una matrice bidimensionale si è posta contigua nella memoria mentre una colonna (stesso secondo indice ) sono costituiti da elementi distanti l'uno dall'altro. È importante conoscere le considerazioni relative alle prestazioni: l'accesso agli elementi vicini è in genere molto più rapido (a causa delle cache HW, ecc.), Quindi per esempio i cicli annidati dovrebbero essere organizzati in modo tale che l'interno più interno elimini l'ultimo indice.

    Torna alla domanda: se la tua immagine mentale (astrazione) di un array 2D è quella di un reticolo in coordinate cartesiane, allora sì, potresti pensarlo come array[NY][NX] in C. Tuttavia se hai bisogno di descrivere dati reali 2D o 3D come array, la scelta degli indici dipende probabilmente da altre cose: formati dei dati, notazione conveniente, prestazioni, ecc. Ad esempio, se la rappresentazione in memoria per una bitmap è array[NX][NY] in un formato con cui devi lavorare, lo dichiarerai in questo modo e forse non hai nemmeno bisogno di sapere che la bitmap diventa una sorta di "trasposto" 🙂

    L’array 3d è un array 2d esteso.

    Ad esempio abbiamo un array – int arr (3) (5) (6);

    Questo è un array che consiste di due array 2d in cui array avrebbe un array 2d con 4 righe e 3 colonne.