Namespaces
Variants

Array initialization

From cppreference.net

Al inicializar un objeto de tipo array , el inicializador debe ser un string literal (opcionalmente entre llaves) o una lista entre llaves de inicializadores para los miembros del array:

= string-literal (1)
= { expression , ... } (2) (hasta C99)
= { designator (opcional) expression , ... } (2) (desde C99)
= { } (3) (desde C23)
1) inicializador de literal de cadena para arreglos de caracteres y caracteres anchos
2) lista separada por comas de constant (until C99) expresiones que son inicializadores para elementos del array , opcionalmente usando designadores de array de la forma [ constant-expression ] = (since C99)
3) el inicializador vacío inicializa vacío cada elemento del array

Los arreglos de tamaño conocido y los arreglos de tamaño desconocido pueden ser inicializados , pero no los VLAs (since C99) (until C23) . Un VLA solo puede ser inicializado vacío. (since C23)

Todos los elementos del array que no se inicializan explícitamente son empty-initialized .

Contenidos

Inicialización desde cadenas

Literal de cadena (opcionalmente encerrado entre llaves) puede utilizarse como inicializador para un arreglo de tipo coincidente:

  • los literales de cadena ordinarios y los literales de cadena UTF-8 (desde C11) pueden inicializar arrays de cualquier tipo de carácter ( char , signed char , unsigned char )
  • los literales de cadena anchos con prefijo L pueden usarse para inicializar arrays de cualquier tipo compatible con (ignorando calificadores cv) wchar_t
  • Los literales de cadena ancha con prefijo u pueden usarse para inicializar arreglos de cualquier tipo compatible con (ignorando calificadores cv) char16_t
  • Los literales de cadena ancha con prefijo U pueden usarse para inicializar arreglos de cualquier tipo compatible con (ignorando calificadores cv) char32_t
(desde C11)

Los bytes sucesivos del literal de cadena o los caracteres anchos del literal de cadena ancha, incluyendo el byte/carácter nulo de terminación, inicializan los elementos del array:

char str[] = "abc"; // str tiene tipo char[4] y contiene 'a', 'b', 'c', '\0'
wchar_t wstr[4] = L"猫"; // str tiene tipo wchar_t[4] y contiene L'猫', '\0', '\0', '\0'

Si se conoce el tamaño del array, puede ser uno menos que el tamaño del literal de cadena, en cuyo caso se ignora el carácter nulo terminador:

char str[3] = "abc"; // str tiene tipo char[3] y contiene 'a', 'b', 'c'

Tenga en cuenta que el contenido de dicho array es modificable, a diferencia de cuando se accede directamente a un literal de cadena con char * str = "abc" ; .

Inicialización a partir de listas entre llaves

Cuando un array se inicializa con una lista de inicializadores entre llaves, el primer inicializador de la lista inicializa el elemento del array en el índice cero (a menos que se especifique un designador) (since C99) , y cada inicializador posterior sin designador (since C99) inicializa el elemento del array en el índice uno mayor que el inicializado por el inicializador anterior.

int x[] = {1,2,3}; // x tiene tipo int[3] y contiene 1,2,3
int y[5] = {1,2,3}; // y tiene tipo int[5] y contiene 1,2,3,0,0
int z[4] = {1}; // z tiene tipo int[4] y contiene 1,0,0,0
int w[3] = {0}; // w tiene tipo int[3] y contiene todos ceros

Es un error proporcionar más inicializadores que elementos al inicializar un array de tamaño conocido (excepto cuando se inicializan arrays de caracteres a partir de literales de cadena).

Un designador hace que el siguiente inicializador inicialice el elemento del array descrito por el designador. La inicialización continúa entonces hacia adelante en orden, comenzando con el siguiente elemento después del descrito por el designador.

int n[5] = {[4]=5,[0]=1,2,3,4}; // holds 1,2,3,4,5
int a[MAX] = { // starts initializing a[0] = 1, a[1] = 3, ...
    1, 3, 5, 7, 9, [MAX-5] = 8, 6, 4, 2, 0
};
// for MAX=6,  array holds 1,8,6,4,2,0
// for MAX=13, array holds 1,3,5,7,9,0,0,0,8,6,4,2,0 ("sparse array")
(desde C99)

Al inicializar un arreglo de tamaño desconocido, el subíndice más grande para el cual se especifica un inicializador determina el tamaño del arreglo declarado.

Arreglos anidados

Si los elementos de un array son arrays, structs, o unions, los inicializadores correspondientes en la lista de inicializadores entre llaves son cualquier inicializador válido para esos miembros, excepto que sus llaves pueden omitirse de la siguiente manera:

Si el inicializador anidado comienza con una llave de apertura, todo el inicializador anidado hasta su llave de cierre inicializa el elemento correspondiente del array:

int y[4][3] = { // array de 4 arrays de 3 ints cada uno (matriz 4x3)
    { 1 },      // fila 0 inicializada a {1, 0, 0}
    { 0, 1 },   // fila 1 inicializada a {0, 1, 0}
    { [2]=1 },  // fila 2 inicializada a {0, 0, 1}
};              // fila 3 inicializada a {0, 0, 0}

Si el inicializador anidado no comienza con una llave de apertura, solo se toman suficientes inicializadores de la lista para cubrir los elementos o miembros del subarreglo, estructura o unión; cualquier inicializador restante se deja para inicializar el siguiente elemento del arreglo:

int y[4][3] = {    // array de 4 arrays de 3 ints cada uno (matriz 4x3)
1, 3, 5, 2, 4, 6, 3, 5, 7 // fila 0 inicializada a {1, 3, 5}
};                        // fila 1 inicializada a {2, 4, 6}
                          // fila 2 inicializada a {3, 5, 7}
                          // fila 3 inicializada a {0, 0, 0}
struct { int a[3], b; } w[] = { { 1 }, 2 }; // array de structs
   // { 1 } se interpreta como un inicializador completamente entre llaves para el elemento #0 del array
   // ese elemento se inicializa a { {1, 0, 0}, 0}
   // 2 se interpreta como el primer inicializador para el elemento #1 del array
   // ese elemento se inicializa { {2, 0, 0}, 0}

Los designadores de arreglos pueden estar anidados; la expresión constante entre corchetes para arreglos anidados sigue a la expresión constante entre corchetes para el arreglo exterior:

int y[4][3] = {[0][0]=1, [1][1]=1, [2][0]=1};  // fila 0 inicializada a {1, 0, 0}
                                               // fila 1 inicializada a {0, 1, 0}
                                               // fila 2 inicializada a {1, 0, 0}
                                               // fila 3 inicializada a {0, 0, 0}
(desde C99)

Notas

El orden de evaluación de las subexpresiones en un inicializador de array es indeterminadamente secuenciado en C (pero no en C++ desde C++11):

int n = 1;
int a[2] = {n++, n++}; // comportamiento no especificado pero bien definido,
                       // n se incrementa dos veces (en orden arbitrario)
                       // a se inicializa a {1, 2} y a {2, 1}, ambas son válidas
puts((char[4]){'0'+n} + n++); // comportamiento indefinido:
                              // el incremento y la lectura de n no están secuenciados

En C, la lista entre llaves de un inicializador no puede estar vacía. C++ permite listas vacías:

(until C23)

Se puede usar un inicializador vacío para inicializar un array:

(since C23)
int a[3] = {0}; // forma válida en C y C++ para inicializar a cero un array de ámbito de bloque
int a[3] = {}; // forma válida en C++ para inicializar a cero un array de ámbito de bloque; válida en C desde C23

Como con todas las demás inicializaciones , cada expresión en la lista de inicializadores debe ser una expresión constante al inicializar arrays de duración de almacenamiento estática o local al hilo:

static char* p[2] = {malloc(1), malloc(2)}; // error

Ejemplo

int main(void)
{
    // Las siguientes cuatro declaraciones de arreglo son iguales
    short q1[4][3][2] = {
        { 1 },
        { 2, 3 },
        { 4, 5, 6 }
    };
    short q2[4][3][2] = {1, 0, 0, 0, 0, 0, 2, 3, 0, 0, 0, 0, 4, 5, 6};
    short q3[4][3][2] = {
        {
            { 1 },
        },
        {
            { 2, 3 },
        },
        {
            { 4, 5 },
            { 6 },
        }
    };
    short q4[4][3][2] = {1, [1]=2, 3, [2]=4, 5, 6};
    // Los nombres de caracteres pueden asociarse con constantes de enumeración
    // usando arreglos con designadores:
    enum { RED, GREEN, BLUE };
    const char *nm[] = {
        [RED] = "red",
        [GREEN] = "green",
        [BLUE] = "blue",
    };
}

Referencias

  • Estándar C17 (ISO/IEC 9899:2018):
  • 6.7.9/12-39 Inicialización (p: 101-105)
  • Estándar C11 (ISO/IEC 9899:2011):
  • 6.7.9/12-38 Inicialización (p: 140-144)
  • Estándar C99 (ISO/IEC 9899:1999):
  • 6.7.8/12-38 Inicialización (p: 126-130)
  • Estándar C89/C90 (ISO/IEC 9899:1990):
  • 6.5.7 Inicialización