¿Cómo se formatean matrices multidimensionales en la memoria?

En C, sé que puedo asignar dinámicamente una matriz de dos dimensiones en el montón utilizando el siguiente código:

int** someNumbers = malloc(arrayRows*sizeof(int*)); for (i = 0; i < arrayRows; i++) { someNumbers[i] = malloc(arrayColumns*sizeof(int)); } 

Claramente, esto realmente crea una matriz unidimensional de punteros a un grupo de matrices enteros unidimensionales enteros, y “The System” puede entender a qué me refiero cuando pregunto:

 someNumbers[4][2]; 

Pero cuando declaro estáticamente una matriz 2D, como en la siguiente línea …:

 int someNumbers[ARRAY_ROWS][ARRAY_COLUMNS]; 

… ¿se crea una estructura similar en la stack, o es de otra forma completamente? (es decir, ¿se trata de un conjunto 1D de indicadores? En caso negativo, ¿qué es y cómo se resuelven las referencias a él?)

Además, cuando dije “El sistema”, ¿qué es realmente responsable de resolverlo? El kernel? ¿O el comstackdor de C lo resuelve durante la comstackción?

Una matriz bidimensional estática se parece a una matriz de matrices, simplemente se presenta de forma contigua en la memoria. Las matrices no son lo mismo que los indicadores, pero debido a que a menudo puede usarlas de manera bastante intercambiable, a veces puede ser confuso. Sin embargo, el comstackdor realiza un seguimiento adecuado, lo que hace que todo se alinee bien. Tienes que tener cuidado con las matrices 2D estáticas como mencionas, ya que si tratas de pasar una a una función tomando un parámetro int ** , las cosas malas van a suceder. Aquí hay un ejemplo rápido:

 int array1[3][2] = {{0, 1}, {2, 3}, {4, 5}}; 

En la memoria se ve así:

 0 1 2 3 4 5 

exactamente lo mismo que:

 int array2[6] = { 0, 1, 2, 3, 4, 5 }; 

Pero si intenta pasar array1 a esta función:

 void function1(int **a); 

recibirás una advertencia (y la aplicación no podrá acceder correctamente a la matriz):

 warning: passing argument 1 of 'function1' from incompatible pointer type 

Porque una matriz 2D no es lo mismo que int ** . La descomposición automática de una matriz en un puntero solo tiene “un nivel de profundidad”, por así decirlo. Debes declarar la función como:

 void function2(int a[][2]); 

o

 void function2(int a[3][2]); 

Para hacer todo feliz

Este mismo concepto se extiende a matrices n- dimensionales. Sin embargo, tomar ventaja de este tipo de negocios divertidos en su aplicación generalmente hace que sea más difícil de entender. Así que ten cuidado.

La respuesta se basa en la idea de que C realmente no tiene matrices en 2D, tiene matrices de matrices. Cuando declaras esto:

 int someNumbers[4][2]; 

Usted está pidiendo que algunos someNumbers sean una matriz de 4 elementos, donde cada elemento de esa matriz es de tipo int [2] (que a su vez es una matriz de 2 int s).

La otra parte del rompecabezas es que las matrices siempre están dispuestas contiguamente en la memoria. Si usted solicita:

 sometype_t array[4]; 

entonces eso siempre se verá así:

 | sometype_t | sometype_t | sometype_t | sometype_t | 

(4 objetos de sometype_t colocados uno al lado del otro, sin espacios entre ellos). Entonces, en su array de arreglos someNumbers , se verá así:

 | int [2] | int [2] | int [2] | int [2] | 

Y cada elemento int [2] es en sí mismo una matriz, que se ve así:

 | int | int | 

Entonces, en general, obtienes esto:

 | int | int | int | int | int | int | int | int | 
 unsigned char MultiArray[5][2]={{0,1},{2,3},{4,5},{6,7},{8,9}}; 

en la memoria es igual a:

 unsigned char SingleArray[10]={0,1,2,3,4,5,6,7,8,9}; 

En respuesta a su también: Ambos, aunque el comstackdor está haciendo la mayor parte del trabajo pesado.

En el caso de matrices asignadas estáticamente, “The System” será el comstackdor. Se reservará la memoria como lo haría para cualquier variable de stack.

En el caso de la matriz malloc’d, “The System” será el implementador de malloc (el kernel generalmente). Todo lo que el comstackdor asignará es el puntero base.

El comstackdor siempre tratará el tipo como lo que se declara que sea, excepto en el ejemplo que dio Carl donde puede deducir el uso intercambiable. Esta es la razón por la cual si pasa un [] [] a una función, debe suponer que se trata de un plano estáticamente asignado, donde ** se supone que es un puntero a un puntero.

Para acceder a una matriz 2D en particular, considere el mapa de memoria para una statement de matriz como se muestra en el siguiente código:

  0 1 a[0]0 1 a[1]2 3 

Para acceder a cada elemento, es suficiente pasar el conjunto que le interesa como parámetros de la función. A continuación, use desplazamiento para columna para acceder a cada elemento individualmente.

 int a[2][2] ={{0,1},{2,3}}; void f1(int *ptr); void f1(int *ptr) { int a=0; int b=0; a=ptr[0]; b=ptr[1]; printf("%d\n",a); printf("%d\n",b); } int main() { f1(a[0]); f1(a[1]); return 0; }