En C, sé que puedo asignar dinámicamente una matriz bidimensional en el montón usando el siguiente código:
int** someNumbers = malloc(arrayRows*sizeof(int*));
for (i = 0; i < arrayRows; i++) {
someNumbers[i] = malloc(arrayColumns*sizeof(int));
}
Claramente, esto en realidad crea una matriz unidimensional de punteros a un conjunto de matrices unidimensionales separadas de enteros, y "El Sistema" puede entender a qué me refiero cuando pido:
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, ¿es una matriz de punteros 1D? Si no es así, ¿qué es y cómo se resuelven las referencias?)
Además, cuando dije: "El sistema", ¿qué es realmente responsable de resolver eso? El grano? ¿O el compilador de C lo soluciona mientras compila?
c
arrays
memory
data-structures
stack-memory
Chris Cooper
fuente
fuente
malloc()
no dan como resultado una matriz N-dimensional. . Resulta en conjuntos de punteros [a conjuntos de punteros [...] para separar completamente conjuntos unidimensionales . Consulte Asignación correcta de matrices multidimensionales para ver cómo asignar matrices VERDADERAS de N dimensiones.Respuestas:
Una matriz bidimensional estática se parece a una matriz de matrices: se presenta contiguamente en la memoria. Las matrices no son lo mismo que los punteros, pero debido a que a menudo puedes usarlos de manera intercambiable, a veces puede ser confuso. Sin embargo, el compilador realiza un seguimiento adecuado, lo que hace que todo se alinee bien. Debe tener cuidado con las matrices 2D estáticas como menciona, ya que si intenta pasar una a una función que toma un
int **
parámetro, sucederán cosas malas. Aquí hay un ejemplo rápido:En la memoria se ve así:
exactamente lo mismo que:
Pero si intentas pasar
array1
a esta función:recibirá una advertencia (y la aplicación no podrá acceder a la matriz correctamente):
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. Debe declarar la función como:o
Para hacer todo feliz.
Este mismo concepto se extiende a las matrices n- dimensionales. Sin embargo, aprovechar este tipo de negocios divertidos en su aplicación generalmente solo hace que sea más difícil de entender. Así que ten cuidado allá afuera.
fuente
sizeof(int[100]) != sizeof(int *)
(a menos que encuentre una plataforma con100 * sizeof(int)
bytes /int
, pero eso es algo diferente.La respuesta se basa en la idea de que C realmente no tiene matrices 2D, sino matrices de matrices. Cuando declaras esto:
Está solicitando
someNumbers
ser una matriz de 4 elementos, donde cada elemento de esa matriz es de tipoint [2]
(que en sí mismo es una matriz de 2int
s).La otra parte del rompecabezas es que las matrices siempre se presentan contiguamente en la memoria. Si solicita:
entonces eso siempre se verá así:
(4
sometype_t
objetos dispuestos uno al lado del otro, sin espacios intermedios). Entonces, en susomeNumbers
matriz de matrices, se verá así:Y cada
int [2]
elemento es en sí mismo una matriz, que se ve así:Entonces, en general, obtienes esto:
fuente
int
en la matriz de matrices (por ejemplo, evaluandoa[0]
o&a[0][0]
) entonces sí, puede compensar eso para acceder secuencialmente a cada unoint
).en memoria es igual a:
fuente
En respuesta a su también: Ambas, aunque el compilador está haciendo la mayor parte del trabajo pesado.
En el caso de arreglos asignados estáticamente, "El Sistema" será el compilador. 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 núcleo generalmente). Todo lo que el compilador asignará es el puntero base.
El compilador siempre manejará el tipo como lo que se declara que es, excepto en el ejemplo que dio Carl donde puede descubrir el uso intercambiable. Es por eso que si pasa un [] [] a una función, debe asumir que es un plano asignado estáticamente, donde ** se supone que es un puntero a otro.
fuente
malloc
se implementa no está especificado por el estándar y se deja a la implementación, resp. ambiente. Para entornos independientes, es opcional, como todas las partes de la biblioteca estándar que requieren funciones de enlace (eso es lo que realmente dan como resultado los requisitos, no literalmente lo que establece el estándar). Para algunos entornos alojados modernos, de hecho depende de las funciones del núcleo, ya sea el material completo o (por ejemplo, Linux) como escribió utilizando stdlib y kernel-primitives. Para sistemas de proceso único de memoria no virtual, solo puede ser stdlib.Supongamos que tenemos
a1
ya2
definimos e inicializamos como a continuación (c99):a1
es una matriz 2D homogénea con un diseño continuo simple en la memoria y la expresión(int*)a1
se evalúa en un puntero a su primer elemento:a2
se inicializa a partir de una matriz 2D heterogénea y es un puntero a un valor de tipoint*
, es decir, la expresión de referencia se*a2
evalúa en un valor de tipoint*
, el diseño de memoria no tiene que ser continuo:A pesar del diseño de memoria totalmente diferente y la semántica de acceso, la gramática del lenguaje C para las expresiones de acceso a la matriz se ve exactamente igual para la matriz 2D homogénea y heterogénea:
a1[1][0]
obtendrá valor144
fuera de laa1
matriza2[1][0]
obtendrá valor244
fuera de laa2
matrizEl compilador sabe que la expresión de acceso para
a1
opera en tipoint[2][2]
, cuando la expresión de acceso paraa2
opera en tipoint**
. El código de ensamblaje generado seguirá la semántica de acceso homogénea o heterogénea.El código generalmente se bloquea en tiempo de ejecución cuando la matriz de tipo
int[N][M]
se convierte en tipo y luego se accede como tipoint**
, por ejemplo:fuente
Para acceder a una matriz 2D particular, considere el mapa de memoria para una declaración de matriz como se muestra en el siguiente código:
Para acceder a cada elemento, es suficiente simplemente pasar qué matriz le interesa como parámetros a la función. Luego use offset para columna para acceder a cada elemento individualmente.
fuente