1
votes

Est-il conforme à la norme d'initialiser un tableau 2D de taille inconnue par un initialiseur de tableau 1D?

Je suis récemment venu cette question où nous avons obtenu une définition de tableau 2D comme celle-ci:

int y[2][3] = { { 0, 1, 2 } , { 3, 4, 5 } };

La première dimension est vide / la taille du tableau est inconnue. Le tableau z est initialisé par un initialiseur de tableau 1D.

Maintenant, voici ce que dit le standard C (souligner le mien):

"Si l'agrégat ou l'union contient des éléments ou des membres qui sont des agrégats ou des unions, ces règles s'appliquent de manière récursive aux sous-agrégats ou aux unions contenues. Si l'initialiseur d'un sous-agrégat ou d'une union contenue commence par une accolade gauche, les initialiseurs encadrés par l'accolade et son accolade droite correspondante initialisent les éléments ou membres du sous-agrégat ou de l'union contenue. Sinon, seuls les initialiseurs de la liste sont pris en compte pour les éléments ou membres du sous-agrégat ou du premier membre de l'union contenue; tous les initialiseurs restants sont laissés pour initialiser l'élément ou le membre suivant de l'agrégat dont le sous-agrégat actuel ou l'union contenue fait partie .

Source: ISO / CEI 9899: 2018 (C18), §6.7.9 / 20.

Cela signifie qu'il est bien défini d'initialiser un tableau 2D de quantité connue de éléments avec un initialiseur de tableau 1D.

Ainsi, fe:

int y[2][3] = { 0, 1, 2, 3, 4, 5 };

devrait être équivalent à:

int x[][3] = { 0, 1, 2, 3, 4, 5 };

Voici ce qui m'inquiète:

"Si un tableau de taille inconnue est initialisé, sa taille est déterminée par le plus grand élément indexé avec un initialiseur explicite . Le type de tableau est complété à la fin de sa liste d'initialiseurs. "

Source: ISO / CEI 9899: 2018 (C18), §6.7.9 / 22.

Cela signifie que si la taille du tableau / les quantités d'éléments qu'il contient est inconnu, il nécessite que le tableau 2D:

  1. Doit avoir un élément indexé le plus grand, et
  2. Cet élément doit avoir un initialiseur explicite.

Mes questions:

  • Est-ce fourni ici?

  • Est-il conforme à la norme d'initialiser un tableau bidimensionnel de taille inconnue par un initialiseur de tableau unidimensionnel?

À mon humble avis et après mon état actuel des connaissances, cela ne devrait pas. Mais peut-être ai-je mal compris quelque chose ici.


J'ai ouvert cette question parce que l'autre question est étiquetée avec C et C ++, donc ce n'est pas un vrai langage juridique approprié et ne se concentre pas sur C, plus la question de l'autre question est en fait assez différente.


9 commentaires

Votre premier exemple en haut a une sizeof 24. Si je ne fournis (MSVC) que 4 initiateurs comme dans int x [] [3] = {0, 1, 2, 3}; la taille est toujours 24. Cela semble en accord avec votre citation, car le plus grand élément indexé avec un initialiseur explicite dans le sens "vertical" est (encore) x [1 ] .


... n'est-ce pas simplement exprimer de manière formelle que la dimension extérieure sera suffisante pour contenir tous les éléments explicitement initialisés, et pas plus (à moins qu'ils ne soient définis)?


@WeatherVane Je ne suis pas sûr de pouvoir suivre vos commentaires. Pourquoi les deux int x [] [3] = {0, 1, 2, 3}; et int x [] [3] = {0, 1, 2, 3, 4 , 5}; aboutit à sizeof (x) = 24 (à MSVC) en premier lieu? Et comment ce comportement est-il défini? - Je dessine actuellement des blancs ...: - /


Parce qu'ils ont tous les deux besoin de deux "lignes" lorsque la longueur de la ligne a été définie comme 3 . Si vous avez ajouté un autre initialiseur à votre exemple, il aurait besoin d'une "ligne" supplémentaire (avec une valeur explicitement définie). Je ne vois pas en quoi cela diffère d'un tableau 1D: le tableau sera assez grand pour contenir les données initialisées, et pas plus grand. Dans ce cas, ce serait équivalent à int y [3] [3] = {{0, 1, 2}, {3, 4, 5}, {6}};


@WeatherVane D'accord, je comprends. Cela semble plausible, maintenant. Merci. Jusqu'ici tout va bien. Mais comment cela se rapporte-t-il exactement à la citation " sa taille est déterminée par le plus grand élément indexé avec un initialiseur explicite. Le type de tableau est terminé à la fin de sa liste d'initialisation. " - J'ai toujours des problèmes en comprenant cette citation et la relation de cette citation à ce que vous m'avez dit.


Le reformuler en "le plus grand index de tout élément initialisé ..."


@WeatherVane (Le mauvais exemple a réécrit ce commentaire) Cela me confond à nouveau. Maintenant, je pense à quelque chose comme int x [] [3] = {0, 1, 2, 3}; == int x [3] [3] = {0, 1, 2, 3}; . J'ai des problèmes pour identifier ce qui est quoi ici. Remarque: j'attribue toujours des réponses.


Ce que cela signifie est clair, même si peut-être que le langage n'est pas mathématiquement précis


@ M.M Il est clair ce que cela signifie si vous savez ce que cela signifie. Si vous ne savez pas ce que " plus grand élément indexé " et " initialiseur explicite " signifie que vous avez des problèmes. La norme a manqué d'expliquer explicitement ces termes, ce qui laisse place à l'ambiguïté et je me suis senti dans le piège. Ce n'est pas de ma faute. J'ai peut-être des problèmes à comprendre, mais la norme aurait pu faire mieux.


3 Réponses :


1
votes

Comme vous l'avez cité dans 6.7.9 Initialisation :

[..] tous les initialiseurs restants sont laissés pour initialiser le suivant élément ou membre de l'agrégat dont le sous-agrégat actuel ou l'union contenue est une partie.

Donc

int x[3][3] = { {0, 1, 2}, {3, 4, 5}, {6, 0, 0} };

équivalent à

int x[][3] = { {0, 1, 2}, {3, 4, 5}, {6} };

i.e. après avoir initialisé le premier élément du tableau avec {0, 1, 2} , le reste des initialiseurs forment l'élément suivant. Et le élément suivant étant int [3] ici.

De même,

int x[][3] = { 0, 1, 2, 3, 4, 5, 6 };

est équivalent à:

int x[][3] = { { 0, 1, 2}, {3, 4, 5} };

et équivaut à:

int x[][3] = { 0, 1, 2, 3, 4, 5 };

ie tous les sous-objets qui ne sont pas initialisés explicitement doivent être initialisés implicitement de la même manière que les objets qui ont une durée de stockage statique .


14 commentaires

Je voudrais utiliser une nouvelle réaction "Merci" (mais je ne suis pas fan de cette fonctionnalité), car j'apprécie vos efforts mais je ne vois ni ne comprends comment cela répond à mes préoccupations. Mon problème met l'accent sur la citation " Si un tableau de taille inconnue est initialisé, sa taille est déterminée par le plus grand élément indexé avec un initialiseur explicite. Le type de tableau est complété à la fin de sa liste d'initialisation." "et comment cela s'applique-t-il à l'exemple fourni selon lequel il est conforme aux normes de le faire.


Cette réponse semble montrer clairement (dernier exemple) que parce que l'élément final avec un initialiseur explicite est x [2] [0] la dimension sera 2 + 1 = 3 . Pas moins, car cela débordera le tableau, et pas plus, car une autre ligne n'est pas nécessaire pour contenir les données initialisées. Il s'agit de l ' index le plus élevé nécessaire pour contenir les données explicitement initialisées.


@RobertSsupportsMonicaCellio Comme indiqué, chacun des autres éléments d'initialisation fait partie de l'élément next . Ainsi int x [] [3] = {0, 1, 2, 3, 4, 5}; équivaut à int x [2] [3] = {0, 1, 2, 3, 4, 5}; et "l'élément indexé le plus élevé" est ici 2.


@RobertSsupportsMonicaCellio Pour les deux tableaux, la sizeof affiche 24 & 36 comme prévu: godbolt.org / z / VcHN3U


@usr Oui, le 24 & 36 était une confusion. Cela n'a pas dérangé le 6 ajouté.


@usr Mais comment l'initialiseur 2 en tant que " plus grand élément indexé " dans la première ligne a-t-il une influence sur la quantité de valeurs dans la dimension du tableau du tableau 2D x ? Après la citation " sa taille (dimension du tableau) est déterminée par le plus grand élément indexé (ligne) avec un initialiseur explicite "


@usr Pour parler clairement. Je comprends maintenant vos exemples dans la réponse, mais pas la citation.


Pour déterminer la 2ème dimension, la liste d'initialiseurs est utilisée. Étant donné que chaque élément est int [3] , chacun des 3 nombres forme "un" élément pour la deuxième dimension - total 2 pour int x [] [3] = {0, 1, 2, 3, 4, 5}; . C'est ce qu'implique la citation et j'ai essayé d'expliquer dans la 1ère partie de la réponse.


@RobertS le "initialiseur avec une influence" n'est pas dans la première ligne, mais dans la dernière ligne . Par définition, la dernière ligne utilisée détermine la taille du tableau dans cette direction. Je ne vois pas du tout avec quoi vous éprouvez des difficultés. L'index le plus élevé utilisé horizontalement est [2] (qui a été spécifié de toute façon) et l'index le plus élevé verticalement est également [2] (dans le dernier exemple). Ainsi le tableau devient x [3] [3] . Dans le premier exemple, l'index de ligne le plus élevé requis par les données initialisées est la ligne 1. Cela devient donc y [2] [3] .


Ma question repose sur la pédanterie. Mon état d'esprit est le suivant: la citation dit que la taille d'un tableau serait déterminée par le plus grand élément indexé avec un initialiseur explicite . Mais il n'y a pas d'élément indexé explicite avec un initialiseur explicite dans la liste d'initialisation. Le tableau est plié pour construire 2/3 éléments de type int [3] par le compilateur cependant, mais il n'est pas explicitement initialisé pour le faire ...


Ainsi, int x [] [3] = {{0, 1, 2}, {3, 4, 5}, {6}}; serait IMHO conforme à la norme, mais pas int x [] [3] = {0, 1, 2, 3, 4, 5, 6}; car il n'y a pas d'initialiseur explicite pour l'élément de type int [3] partie. J'espère que maintenant ce que je veux dire est plus clair. Ce sont les règles elles-mêmes qui indiquent qu'il faut un initialiseur explicite pour le plus grand élément.


Excusez-moi, il dit l ' initialiseur qui est explicite, pas l'index. L'index progresse selon les besoins. Comme vous le savez, lorsque l'index est donné explicitement, comme dans int x [2] [3] , les données doivent tenir. Il s'agit du moment où l'index n'est pas donné explicitement, et il ne peut donc pas être les deux .


@WeatherVane C'est la confusion de l'endroit où ma question se construit. Je veux (ed) avoir une explication de la citation, mais je ne trouve pas encore cela dans la réponse, pour être honnête. Je comprends maintenant que la quantité d'éléments (en fait des sous-agrégats) du tableau 2D est déterminée par la quantité de valeurs int dans la liste d'initialisation - l'initialiseur explicite est de type int , pas int [3] comme je le pensais, mais la réponse elle-même manque pour expliquer cela explicitement - ...


Dans la question, j'ai montré que cette citation est ce avec quoi j'ai des problèmes et s'il est donc conforme à la norme d'initialiser un tableau 2D de cette façon, mais la réponse ne se concentre pas sur la citation et ce problème lui-même. Au lieu de cela, il me montre comment il est évalué. La réponse se concentre sur l ' effet , mais pas sur le problème de mon émission d'origine dans la compréhension du devis.



2
votes

Selon C 2018 6.7.9 20:

  • x de int x [] [3] est en cours d'initialisation. Il contient un élément qui est un agrégat, x [0] , qui est un int [3] .
  • Le premier initialiseur pour ce sous-agrégat est 0 . Cela ne commence pas par une accolade. Ainsi, "seuls les initialiseurs de la liste sont pris en compte pour tenir compte des éléments ou membres du sous-agrégat…". Ainsi, trois initialiseurs, 0 , 1 et 2 , sont utilisés pour initialiser x [0] .
  • Puis «tous les initialiseurs restants sont laissés pour initialiser l'élément suivant…». Il reste donc 4 et 5 à initialiser x [1] .
  • Encore une fois, 4 ne commence pas par une accolade, donc 4 et 5 sont pris pour initialiser x [1] < / code>. Selon le paragraphe 21, comme il n'y a pas assez d'initialiseurs pour initialiser x [1] , «le reste de l'agrégat doit être initialisé implicitement de la même manière que les objets qui ont une durée de stockage statique.»

4 et 5 sont des initialiseurs explicites. Ils initialisent x [1] . Par conséquent, x [1] a un initialiseur explicite. C'est le plus grand élément indexé de x qui a un initialiseur explicite. Par conséquent, il détermine la taille de x .


3 commentaires

Est-ce que x [1] [0] peut être vu dans ce contexte comme "le plus grand élément indexé avec un initialiseur explicite" de x ? Je sais que c'est UB d'utiliser x [3] par exemple, mais ce que je veux dire est différent. Si x [1] [0] ne serait pas "" le plus grand élément indexé avec un initialiseur explicite "" le cas du tableau 2D ne correspondrait pas à la citation et donc nous aurait un comportement indéfini ou du moins non spécifié.


"Si x [1] [0] ne serait pas" "le plus grand élément indexé avec un initialiseur explicite" "" est une clause subjonctive qui n'est pas pertinente. 4 et 5 sont des initialiseurs explicites. x [1] a ces initialiseurs. Le fait qu'ils ne soient des initialiseurs que pour une partie de x [1] n'est pas pertinent, car cela ne modifie pas le fait que x [1] possède en fait ces initialiseurs. Par conséquent, x [1] a des initialiseurs explicites. C'est le plus grand élément indexé de x pour ce faire, et donc il détermine la taille de x .


Re "Est-ce que x [1] [0] peut être vu dans ce contexte comme" le plus grand élément indexé avec un initialiseur explicite "de x?": Non, car x [1] [0] ne l'est pas un élément de x . x [1] est un élément de x .



2
votes

Vous posez une question sur cette phrase de l'ISO / CEI 9899: 2018 (C18), §6.7.9 / 22.

Si un tableau de taille inconnue est initialisé, sa taille est déterminée par le plus grand élément indexé avec un initialiseur explicite. Le type de tableau est complété à la fin de sa liste d'initialisation.

Considérez cette définition

int x[2][3];

La largeur est définie, le compilateur initialisera donc des éléments comme celui-ci

x[0][2] = 2;    // "horizontally"
x[1][0] = 3;    // "vertically"

Cela provient des valeurs d'initialisation explicites définies. Alors maintenant

  • L'index interne le plus élevé est 2
  • L'index externe le plus élevé est 1

Donc "le plus grand élément indexé avec un initialiseur explicite" est

x[0][0] = 0;
x[0][1] = 1;
x[0][2] = 2;
x[1][0] = 3;

et le compilateur crée le tableau

int x[][3] = { 0, 1, 2, 3 };


12 commentaires

Le "plus grand élément indexé avec un initialiseur explicite" n'est-il pas uniquement x [1] [0] = 3 ?


Non, c'est la plus grande initialiseur ou valeur . La norme indique le plus grand élément indexé .


Dans le cas du premier sous-agrégat x [0] , le plus grand élément indexé avec un initialiseur explicite est en effet x [0] [2] , mais pas pour x lui-même. Dans le contexte du tableau 2D avec sa liste d'initialiseurs, x [1] [0] doit être le plus grand élément indexé avec un élément explicite. Si ce n'était pas le cas, la citation ne correspondrait pas à l'exemple, et nous aurions en effet un comportement non défini ou non spécifié initialisant le tableau x de cette façon.


En quoi n'est-ce pas ce que ma réponse dit? x [1] [0] est l'élément avec le plus grand index dans la dimension extérieure. Pour la dimension intérieure, qui est définie sinon le tableau 2D ne pourrait pas être construit.


Votre réponse contient la partie - " Ainsi, le plus grand élément indexé avec un initialiseur explicite est x [0] [2] .... et x [1] [0] < / code> ". Réel deux " plus grand élément indexé avec un initialiseur explicite ".


C'est un tableau 2D. J'ai donné le plus grand indice de chaque dimension. Je ne sais vraiment pas où vous voulez en venir, ni ce qui ne vous semble pas clair.


Vous suggérez "deux plus grands éléments indexés avec un initialiseur explicite", le guillemet état " le " seulement. C'est une différence.


C'est parce que l'un est défini, et j'ai peut-être affiché inutilement ce qui devrait être évident.


Ne le prenez pas personnel. Et non, j'apprécie chaque réponse. Mais revenons aux faits. La norme n'en décrit qu'un seul, qu'il s'agisse d'un tableau 1D ou 2D. Votre réponse est très bien, mais à ce stade, elle contredit ou du moins ne confirme pas la norme. Vous m'avez déjà beaucoup aidé mais je veux juste découvrir toute la vérité.


Eh bien, vous avez souligné ce que vous pensez être une contradiction, et (dans les commentaires) j'ai souligné que vous l'interprétez mal. «Le plus grand» fait référence à «l'indice de l'élément le plus grand» et non aux «données de l'élément le plus grand». La valeur des données n'est ni mentionnée ni pertinente.


Eh bien, je comprends maintenant que vous le vouliez bien en illustrant à la fois le plus grand élément indexé avec un initialiseur explicite au niveau sous-agrégé (horizontal) et agrégé (vertical), mais cela a juste apporté un peu plus de confusion à ce moment-là. Techniquement, x [1] est "l.i.e.w.a.e.i.", et non x [1] [0] . L'accent mis sur les éléments horizontaux et verticaux avec mes préoccupations sur ce terme spécifique m'a rendu fou.


La taille horizontale (intérieure) a été définie. Comme Eric l'a mentionné, le plus grand index de x est x [1] .