matriz - ¿Cómo se formatean matrices multidimensionales en la memoria?
matriz dinamica en c (5)
En respuesta a su también: Ambos, aunque el compilador está haciendo la mayor parte del trabajo pesado.
En el caso de matrices asignadas estáticamente, "The System" será el compilador. Se reservará la memoria como lo haría para cualquier variable de pila.
En el caso de la matriz malloc''d, "The System" será el implementador de malloc (el kernel generalmente). Todo lo que el compilador asignará es el puntero base.
El compilador 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.
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 pila, 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 compilador de C lo resuelve durante la compilación?
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 |
Para acceder a una matriz 2D en particular, considere el mapa de memoria para una declaración 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;
}
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 compilador 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.
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};