web-dev-qa-db-fra.com

Confusion sur l'initialisation du tableau en C

En langage C, si vous initialisez un tableau comme celui-ci:

int a[5] = {1,2};

alors tous les éléments du tableau qui ne sont pas initialisés explicitement seront initialisés implicitement avec des zéros.

Mais si j'initialise un tableau comme ceci:

int a[5]={a[2]=1};

printf("%d %d %d %d %d\n", a[0], a[1],a[2], a[3], a[4]);

sortie:

1 0 1 0 0

Je ne comprends pas pourquoi a[0] imprime 1 au lieu de 0? Est-ce un comportement indéfini?

Note: / Cette question a été posée dans une interview.

98
M.S Chaudhari

Je ne comprends pas pourquoi a[0] imprime 1 au lieu de 0?

Vraisemblablement, a[2]=1 initialise a[2] en premier et le résultat de l'expression est utilisé pour initialiser a[0].

À partir de N2176 (ébauche C17):

6.7.9 Initialisation

  1. Les évaluations des expressions de la liste d'initialisation sont séquencées de manière indéterminée par rapport à les uns des autres et l’ordre dans lequel les effets indésirables se produisent est donc indéterminé.  154)

Il semblerait donc que la sortie 1 0 0 0 0 aurait également été possible.

Conclusion: N'écrivez pas d'initialiseurs modifiant à la volée la variable initialisée.

22
user694733

Je pense que la norme C11 couvre ce comportement et indique que le résultat est est non spécifié, et je ne pense pas que C18 a apporté des modifications pertinentes dans ce domaine.

La langue standard n'est pas facile à analyser . La section pertinente de la norme est §6.7.9 Initialisation . La syntaxe est documentée comme suit:

initializer:
assignment-expression
{ initializer-list }
{ initializer-list , }
initializer-list:
designationopt initializer
initializer-list , designationopt initializer
designation:
designator-list =
designator-list:
designator
designator-list designator
designator:
[ constant-expression ]
. identifier

Notez que l'un des termes est Affectation-expression et que a[2] = 1 est indubitablement une expression d'affectation, il est autorisé à l'intérieur des initialiseurs

§4 Toutes les expressions dans un initialiseur pour un objet qui a la durée de stockage statique ou de thread doit être une expression constante ou littéraux de chaîne.

L'un des paragraphes clés est:

§19 L'initialisation doit avoir lieu dans l'ordre de la liste d'initialisation, chacune initialiseur fourni pour un sous-objet particulier écrasant tout initialiseur précédemment répertorié pour le même sous-objet;151) tous les sous-objets qui ne sont pas initialisés explicitement doivent être initialisé implicitement de la même façon que les objets qui ont un stockage statique durée.

151) N'importe quel initialiseur pour le sous-objet qui est remplacé et donc pas utilisé pour initialiser ce sous-objet pourrait ne pas être évalué à tout.

Et un autre paragraphe clé est:

§23 Les évaluations des expressions de la liste d'initialisation sont séquencés de manière indéterminée les uns par rapport aux autres et donc au L'ordre dans lequel des effets secondaires se produisent est indéterminé.152)

152) En particulier, l'ordre d'évaluation ne doit pas nécessairement être le identique à l'ordre d'initialisation du sous-objet.

Je suis à peu près sûr que le paragraphe §23 indique que la notation dans la question

int a[5] = { a[2] = 1 };

conduit à un comportement non spécifié . L'attribution à a[2] est un effet secondaire et l'ordre d'évaluation des expressions façon de faire appel à la norme et à la réclamation selon laquelle un compilateur gère cela correctement ou incorrectement.

6
Jonathan Leffler

Ma compréhension est a[2]=1 renvoie la valeur 1 donc le code devient 

int a[5]={a[2]=1} --> int a[5]={1}

int a[5]={1} assigner une valeur pour a [0] = 1  

Par conséquent, il affiche 1 pour a [0]

Par exemple 

char str[10]={‘H’,‘a’,‘i’};


char str[0] = ‘H’;
char str[1] = ‘a’;
char str[2] = ‘i;
2
Karthika

J'essaie de donner une réponse simple et rapide au puzzle: int a[5] = { a[2] = 1 };

  1. Le premier a[2] = 1 est défini. Cela signifie que le tableau dit: 0 0 1 0 0
  2. Mais voici, étant donné que vous l'avez fait entre les crochets { }, qui sont utilisés pour initialiser le tableau dans l'ordre, il prend la première valeur (qui est 1) et le définit sur a[0]. C'est comme si int a[5] = { a[2] }; resterait, où nous avons déjà eu a[2] = 1. Le tableau résultant est maintenant: 1 0 1 0 0

Un autre exemple: int a[6] = { a[3] = 1, a[4] = 2, a[5] = 3 }; - Même si l'ordre est quelque peu arbitraire, en supposant qu'il va de gauche à droite, il irait en 6 étapes:

0 0 0 1 0 0
1 0 0 1 0 0
1 0 0 1 2 0
1 2 0 1 2 0
1 2 0 1 2 3
1 2 3 1 2 3
1
Battle

L'affectation a[2]= 1 est une expression qui a pour valeur 1 et vous avez essentiellement écrit int a[5]= { 1 }; (avec comme effet secondaire que a[2] est également attribué à 1).

0
Yves Daoust