¿Cómo se almacenan las matrices 3D en C?

Entiendo que las matrices en C se asignan en orden mayor de fila. Por lo tanto, para una matriz de 2 x 3:

0 1 2 3 4 5 

Se almacena en la memoria como

 0 1 2 3 4 5 

Sin embargo, ¿y si tengo una matriz de 2 x 3 x 2?

 0 1 2 3 4 5 

y

 6 7 8 9 10 11 

¿Cómo se almacenan estos en la memoria? Es solo consecutiva como:

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

¿O es de otra manera? ¿O depende de algo?

Todas las “dimensiones” se almacenan consecutivamente en la memoria.

Considerar

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

se puede decir que arr[1] y arr[2] (de tipo int[100][20] ) son contiguos
o que arr[1][42] y arr[1][43] (de tipo int[20] ) son contiguos
o que arr[1][42][7] y arr[1][42][8] (de tipo int ) son contiguos

En un nivel bajo, no existe una matriz multidimensional. Solo hay un bloque plano de memoria, lo suficientemente grande como para contener una cantidad dada de elementos. En C, una matriz multidimensional es conceptualmente una matriz cuyos elementos también son matrices. Entonces si lo haces:

 int array[2][3]; 

Conceptualmente terminas con:

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

Esto hace que los elementos se organicen contiguamente en la memoria, ya que la array[0] y la array[1] realidad no contienen ningún dato, solo son referencias a las dos matrices internas. Tenga en cuenta que esto significa que solo las entradas [0, 1, 2] ocupan espacio en la memoria. Si extiende este patrón a la siguiente dimensión, puede ver que:

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

… te dará una estructura como:

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

Que continúa organizando los elementos consecutivamente en la memoria (como se indicó anteriormente, solo las entradas [0, 1] ocupan espacio en la memoria, todo lo demás es solo parte de una referencia a una de estas entradas). Como puede ver, este patrón continuará sin importar cuántas dimensiones tenga.

Y solo por diversión:

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

Te dio:

 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í, tienes razón, están almacenados consecutivamente. Considera este ejemplo:

 #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; } 

Salida:

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

Sí, están almacenados en orden consecutivo. Puedes probar eso así:

 #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; } 

Eso significa que los accesos a una matriz multindexada con dimensiones (N, M, L) se transforman en accesos unidimensionales como este:

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

Creo que has respondido tu propia pregunta. Las matrices multidimensionales se almacenan en orden mayor de fila.

Consulte la especificación ANSI C, sección 3.3.2.1 (también hay un ejemplo específico):

Los operadores de subíndice sucesivos designan un miembro de un objeto de matriz multidimensional. Si E es una matriz n-dimensional (n = 2) con dimensiones ixj “x … x” k, entonces E (usado como otro que no sea un valor l) se convierte en un puntero a una matriz (n -1) -dimensional con dimensiones j “x … x” k. Si el operador unario * se aplica a este puntero de forma explícita, o implícitamente como resultado de la subscripción, el resultado es la matriz apuntada (n -1) -dimensional, que a su vez se convierte en un puntero si se usa como un valor distinto de un lvalor . De esto se deduce que las matrices se almacenan en orden de fila mayor (el último subíndice varía más rápido).

Para su ejemplo, puede probarlo y verlo – http://codepad.org/10ylsgPj

Digamos que tienes una matriz char arr[3][4][5] . Es una matriz de 3 matrices de 4 matrices de 5 caracteres.

Para simplificar, digamos que el valor en arr[x][y][z] es xyz y en arr[1][2][3] almacenamos 123 .

Entonces el diseño en la memoria es:

  | 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] y arr[2] vienen uno tras otro, pero cada elemento en el es del tipo char[4][5] (esas son las tres filas de la tabla).

arr[x][0] - arr[x][3] también vienen uno tras otro, y cada elemento en ellos es del tipo char[5] (esas son las cuatro partes de cada línea en la tabla, 000 – 004 es un elemento de arr[0][0] )

arr[x][y][0] - arr[x][y][4] son 5 bytes que vienen uno tras otro.

Para responder el comentario de OP a la pregunta principal (será algo largo, así que decidí ir con una respuesta, no un comentario):

En caso de que las matrices en C se declaren como array[ny][nx] donde ny y nx son el número de elementos en la dirección y y x. Además, ¿eso significa que mi matriz 3D debería declararse como array[nz][ny][nx] ?

En matemáticas, una matriz MxN tiene M filas y N columnas. Una notación usual para un elemento de matriz es a(i,j), 1<=i<=M, 1<=j<=N Entonces, la primera matriz en su pregunta es una matriz de 3x2.

De hecho, es diferente de la notación utilizada normalmente, por ejemplo, para elementos GUI. Un bitmap de 800x600 tiene 800 píxeles horizontalmente (a lo largo del eje X) y 600 píxeles verticalmente (a lo largo del eje Y). Si algunos quisieran describirlo como una matriz, en notación matemática sería una matriz de 600x800 (600 filas, 800 columnas).

Ahora, las matrices multidimensionales en C se almacenan en la memoria de tal forma que a[i][j+1] está al lado de a[i][j] mientras que a[i+1][j] está a N elementos de distancia. Generalmente se dice que "el último subíndice varía más rápido", o a menudo como "almacenado por filas": una fila (es decir, elementos con el mismo primer índice) en una matriz bidimensional se ha colocado contiguamente en la memoria mientras que una columna (el mismo segundo índice ) consisten en elementos que se encuentran muy lejos el uno del otro. Es importante saber por consideraciones de rendimiento: el acceso a los elementos vecinos suele ser mucho más rápido (debido a cachés HW, etc.), por lo que, por ejemplo, los bucles nesteds deben organizarse de manera que el más interno itere sobre el último índice.

Volviendo a la pregunta: si su imagen mental (abstracción) de una matriz 2D es la de una retícula en coordenadas cartesianas, entonces sí, puede pensar que es una array[NY][NX] en C. Sin embargo, si necesita describir datos 2D o 3D reales como una matriz, la elección de índices probablemente dependa de otras cosas: formatos de datos, notación conveniente, rendimiento, etc. Por ejemplo, si la representación en memoria para un bitmap es una array[NX][NY] en un formato con el que necesita trabajar, lo declarará de esa manera, y tal vez ni siquiera necesite saber que el bitmap se convierte en una especie de "transposición" 🙂

La matriz 3D es una matriz 2d extendida.

Por ejemplo, tenemos una matriz – int arr (3) (5) (6);

Esta es una matriz que consta de dos matrices en 2D, donde la matriz tendría una matriz 2d con 4 filas y 3 columnas.