Array initialization
Lors de l'initialisation d'un objet de type tableau , l'initialiseur doit être soit un littéral de chaîne (optionnellement entre accolades), soit une liste entre accolades d'initialiseurs pour les membres du tableau :
=
string-literal
|
(1) | ||||||||
=
{
expression
,
...
}
|
(2) | (jusqu'en C99) | |||||||
=
{
designator
(optionnel)
expression
,
...
}
|
(2) | (depuis C99) | |||||||
=
{
}
|
(3) | (depuis C23) | |||||||
[
constant-expression
]
=
(depuis C99)
Les tableaux de taille connue et les tableaux de taille inconnue peuvent être initialisés , mais pas les VLA (depuis C99) (jusqu'à C23) . Un VLA ne peut être qu'initialisé vide. (depuis C23)
Tous les éléments du tableau qui ne sont pas initialisés explicitement sont empty-initialized .
Table des matières |
Initialisation à partir de chaînes
Littéral de chaîne (optionnellement entouré d'accolades) peut être utilisé comme initialiseur pour un tableau de type correspondant :
- les littéraux de chaîne ordinaires et les littéraux de chaîne UTF-8 (depuis C11) peuvent initialiser des tableaux de tout type de caractère ( char , signed char , unsigned char )
- les littéraux de chaîne larges préfixés par L peuvent être utilisés pour initialiser des tableaux de tout type compatible avec (en ignorant les qualifications cv) wchar_t
|
(depuis C11) |
Les octets successifs du littéral de chaîne ou les caractères larges du littéral de chaîne large, y compris l'octet/caractère nul de terminaison, initialisent les éléments du tableau :
char str[] = "abc"; // str a le type char[4] et contient 'a', 'b', 'c', '\0' wchar_t wstr[4] = L"猫"; // str a le type wchar_t[4] et contient L'猫', '\0', '\0', '\0'
Si la taille du tableau est connue, elle peut être inférieure d'un à la taille du littéral de chaîne, auquel cas le caractère nul de fin est ignoré :
char str[3] = "abc"; // str a pour type char[3] et contient 'a', 'b', 'c'
Notez que le contenu d'un tel tableau est modifiable, contrairement à l'accès direct à un littéral de chaîne avec char * str = "abc" ; .
Initialisation à partir de listes entre accolades
Lorsqu'un tableau est initialisé avec une liste d'initialiseurs entre accolades, le premier initialiseur de la liste initialise l'élément du tableau à l'index zéro (sauf si un désignateur est spécifié) (depuis C99) , et chaque initialiseur suivant sans désignateur (depuis C99) initialise l'élément du tableau à l'index supérieur de un à celui initialisé par l'initialiseur précédent.
int x[] = {1,2,3}; // x a le type int[3] et contient 1,2,3 int y[5] = {1,2,3}; // y a le type int[5] et contient 1,2,3,0,0 int z[4] = {1}; // z a le type int[4] et contient 1,0,0,0 int w[3] = {0}; // w a le type int[3] et contient tous des zéros
C'est une erreur de fournir plus d'initialiseurs que d'éléments lors de l'initialisation d'un tableau de taille connue (sauf lors de l'initialisation de tableaux de caractères à partir de littéraux de chaîne).
|
Un désignateur entraîne l'initialisation de l'élément du tableau décrit par le désignateur par l'initialisateur suivant. L'initialisation se poursuit ensuite séquentiellement, en commençant par l'élément suivant celui décrit par le désignateur. 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") |
(depuis C99) |
Lors de l'initialisation d'un tableau de taille inconnue, le plus grand indice pour lequel un initialiseur est spécifié détermine la taille du tableau déclaré.
Tableaux imbriqués
Si les éléments d'un tableau sont des tableaux, des structures ou des unions, les initialiseurs correspondants dans la liste d'initialiseurs entre accolades sont tous les initialiseurs valides pour ces membres, sauf que leurs accolades peuvent être omises comme suit :
Si l'initialiseur imbriqué commence par une accolade ouvrante, l'ensemble de l'initialiseur imbriqué jusqu'à son accolade fermante initialise l'élément correspondant du tableau :
int y[4][3] = { // tableau de 4 tableaux de 3 entiers chacun (matrice 4x3) { 1 }, // ligne 0 initialisée à {1, 0, 0} { 0, 1 }, // ligne 1 initialisée à {0, 1, 0} { [2]=1 }, // ligne 2 initialisée à {0, 0, 1} }; // ligne 3 initialisée à {0, 0, 0}
Si l'initialiseur imbriqué ne commence pas par une accolade ouvrante, seuls suffisamment d'initialiseurs de la liste sont pris en compte pour les éléments ou membres du sous-tableau, de la structure ou de l'union ; tout initialiseur restant est laissé pour initialiser l'élément suivant du tableau :
int y[4][3] = { // tableau de 4 tableaux de 3 entiers chacun (matrice 4x3) 1, 3, 5, 2, 4, 6, 3, 5, 7 // ligne 0 initialisée à {1, 3, 5} }; // ligne 1 initialisée à {2, 4, 6} // ligne 2 initialisée à {3, 5, 7} // ligne 3 initialisée à {0, 0, 0} struct { int a[3], b; } w[] = { { 1 }, 2 }; // tableau de structures // { 1 } est considéré comme un initialiseur entièrement entre accolades pour l'élément #0 du tableau // cet élément est initialisé à { {1, 0, 0}, 0} // 2 est considéré comme le premier initialiseur pour l'élément #1 du tableau // cet élément est initialisé { {2, 0, 0}, 0}
|
Les désignateurs de tableau peuvent être imbriqués ; l'expression constante entre crochets pour les tableaux imbriqués suit l'expression constante entre crochets pour le tableau externe : int y[4][3] = {[0][0]=1, [1][1]=1, [2][0]=1}; // ligne 0 initialisée à {1, 0, 0} // ligne 1 initialisée à {0, 1, 0} // ligne 2 initialisée à {1, 0, 0} // ligne 3 initialisée à {0, 0, 0} |
(depuis C99) |
Notes
L' ordre d'évaluation des sous-expressions dans un initialiseur de tableau est indéterminé en C (mais pas en C++ depuis C++11) :
int n = 1; int a[2] = {n++, n++}; // comportement non spécifié mais bien défini, // n est incrémenté deux fois (dans un ordre arbitraire) // a initialisé à {1, 2} ou à {2, 1} sont tous deux valides puts((char[4]){'0'+n} + n++); // comportement indéfini : // l'incrémentation et la lecture de n ne sont pas séquencées
|
En C, la liste entre accolades d'un initialiseur ne peut pas être vide. C++ autorise la liste vide : |
(until C23) |
|
Un initialiseur vide peut être utilisé pour initialiser un tableau : |
(since C23) |
int a[3] = {0}; // méthode valide en C et C++ pour initialiser à zéro un tableau de portée de bloc int a[3] = {}; // méthode valide en C++ pour initialiser à zéro un tableau de portée de bloc; valide en C depuis C23
Comme pour toute autre initialisation , chaque expression dans la liste d'initialisation doit être une expression constante lors de l'initialisation de tableaux avec durée de stockage statique ou thread-local :
Exemple
int main(void) { // Les quatre déclarations de tableau suivantes sont identiques 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}; // Les noms de caractères peuvent être associés aux constantes d'énumération // en utilisant des tableaux avec désignateurs : enum { RED, GREEN, BLUE }; const char *nm[] = { [RED] = "red", [GREEN] = "green", [BLUE] = "blue", }; }
Références
- Norme C17 (ISO/CEI 9899:2018) :
-
- 6.7.9/12-39 Initialisation (p: 101-105)
- Norme C11 (ISO/IEC 9899:2011) :
-
- 6.7.9/12-38 Initialisation (p: 140-144)
- Norme C99 (ISO/CEI 9899:1999) :
-
- 6.7.8/12-38 Initialisation (p. 126-130)
- Norme C89/C90 (ISO/IEC 9899:1990) :
-
- 6.5.7 Initialization