Estoy leyendo el libro “Programación en C” de Kochen y estoy confundido donde explica la inicialización de una matriz multidimensional.

En particular, no entiendo el significado de la siguiente oración Tenga en cuenta que, en este caso, se requieren los pares internos de llaves para forzar la inicialización correcta. Sin ellos, las dos primeras filas y los dos primeros elementos de la tercera fila se habrían inicializado en su lugar. No estoy seguro de qué diablos significa la oración.
Esto se debe a que el M[4][5]
matriz tiene 20 elementos (4 filas, 5 columnas) y el orden predeterminado para la inicialización es fila por fila si las filas no se especifican explícitamente mediante el uso de pares internos de llaves.
Lo que esto significa es que si asigna los mismos 12 valores como una lista lineal simple, sin los pares internos de llaves, los valores se asignan a las dos primeras filas (2*5 = 10 elementos) más las primeras 2 columnas de la tercera hilera. (Los 8 elementos restantes de la matriz que no inicializó explícitamente se establecerán automáticamente en 0).
El compilador de C es consciente de que cada fila solo tiene 5 columnas y ajustará automáticamente la lista de números a la siguiente fila cada vez que se alcance el margen de 5 columnas. Por lo tanto,
int M[4][5] = {10, 5, -3, 9, 0, 0, 32, 20, 1, 0, 0, 8};
se entiende que significa
int M[4][5] =
{
{10, 5, -3, 9, 0},
{ 0, 32, 20, 1, 0},
{ 0, 8, 0, 0, 0},
{ 0, 0, 0, 0, 0}
};
Puede anular el orden predeterminado usando llaves internas para separar sus 12 valores en filas de su gusto (pero, naturalmente, no más de 5 columnas por fila para esta definición de una matriz M
).
Por ejemplo, cuando usa llaves internas para separar los mismos 12 valores en cuatro conjuntos de 3 como su página del libro muestra, luego esas llaves internas se interpretan para inicializar filas separadas de la matriz multidimensional. Y el resultado será inicializar cuatro filas de la matriz, pero solo las primeras 3 columnas de esas cuatro filas, estableciendo las columnas restantes en cero (dos valores cero en blanco al final de cada fila).
Es decir, el compilador de C es consciente de que la matriz M
tiene 5 columnas en cada fila, por lo que agregará las columnas faltantes a cada fila para que cada fila tenga 5 columnas, por lo que la matriz tendrá un total de 20 valores:
int M[4][5] =
{
{10, 5, -3},
{ 9, 0, 0},
{32, 20, 1},
{ 0, 0, 8}
};
se entiende que significa
int M[4][5] =
{
{10, 5, -3, 0, 0},
{ 9, 0, 0, 0, 0},
{32, 20, 1, 0, 0},
{ 0, 0, 8, 0, 0}
};
Dado que todas las matrices se comportan internamente como matrices 1d, debe especificar con los corchetes qué filas exactamente inicializa.
Por ejemplo:
int a[4][5] = {
{ 1, 2, 3 }, // those are the elements of the first row.
// only the first 3 elements are initialized
{ 1, 2, 3, 4} // those are the elements of the 2nd row.
// only the first 4 element are initialized
};
// everything else will be equal to 0
mientras
int a[4][5] = { 1, 2, 3, 1, 2, 3, 4}; // this will initialize first 5 elements
// of the first row and then continue
// with the 2nd one making the first 2
// elements to be 3 and 4 respectivly
// everything else will be equal to 0
Sería útil ver el ejemplo específico.
Una matriz multidimensional es una matriz de matrices. (No es solo azúcar sintáctico para una matriz unidimensional larga).
En un inicializador, es legal omitir tanto los elementos finales (que se inicializan implícitamente en cero) como las llaves internas.
Dado:
int arr[2][2];
una inicialización completa podría verse así:
int arr[2][2] = { { 10, 20 }, { 30, 40 } };
Puede (pero en mi humilde opinión no debería) omitir las llaves internas:
int arr[2][2] = { 10, 20, 30, 40 };
y el compilador asignará los elementos del inicializador a los elementos de arr
.
Si omite elementos finales:
int arr[2][2] = { { 10, 20 } };
entonces la segunda fila se inicializa implícitamente para { 0, 0 }
.
O podrías escribir:
int arr[2][2] = { { 10 }, { 20 } };
lo que asignaría los valores 10 y 20 al primer elemento de cada fila, no a la primera fila.
Nuevamente, es difícil decir exactamente de qué estaba hablando el autor sin ver un ejemplo, pero una llave interna le dice al compilador que comience una nueva fila, incluso si la primera fila está incompleta.
Si proporciona inicializadores para los 4 elementos (o más generalmente todos X * Y
elementos), los tirantes interiores no son estrictamente necesarios; el orden de los elementos es el mismo en ambos sentidos.
Personalmente, me parece mucho más claro incluir todas las llaves internas de todos modos, porque reflejan la estructura real que estás inicializando.
(Entonces, ¿cuál es la diferencia entre una matriz unidimensional y una matriz bidimensional, aparte del azúcar sintáctico? Dada la declaración anterior de arr
si fuera lo mismo que una matriz unidimensional, entonces arr[0][2]
sería lo mismo que arr[1][0]
, con el segundo índice desbordándose en la segunda fila. Y puede funcionar de esa manera en la práctica, pero en realidad arr[0][2]
tiene un comportamiento indefinido. Esto tiene consecuencias prácticas; un compilador optimizador puede asumir que todos los límites están dentro del rango y generan un código que se comporta mal si se viola esa suposición).
Véase también esta pregunta.