Inicialización de matrices multidimensionales en C

5 minutos de lectura

avatar de usuario
usuario2635911

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

aquí

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.

avatar de usuario
José Myers

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

  • Pero, al comparar las dos inicializaciones donde también está escribiendo todos los 0 implícitos, ¿cómo se supone que el primero (que representa que no se usan llaves internas) es el segundo (con llaves internas) con las dos primeras filas y los dos primeros elementos de la tercera fila inicializados? Parece que todavía se están inicializando todos los números, pero no en los lugares correctos. De hecho, solo la primera fila está en el lugar correcto.

    – velocirabbit

    6 de julio de 2016 a las 23:08

  • ¿Cómo se equipara el ejemplo sin llaves internas a “las dos primeras filas y los dos primeros elementos de la tercera fila se habrían inicializado en su lugar”?

    – velocirabbit

    6 de julio de 2016 a las 23:05

avatar de usuario
Alejandro Barbarosie

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

avatar de usuario
Comunidad

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 arrsi 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.

¿Ha sido útil esta solución?

Esta web utiliza cookies propias y de terceros para su correcto funcionamiento y para fines analíticos y para mostrarte publicidad relacionada con sus preferencias en base a un perfil elaborado a partir de tus hábitos de navegación. Al hacer clic en el botón Aceptar, acepta el uso de estas tecnologías y el procesamiento de tus datos para estos propósitos. Configurar y más información
Privacidad