Array-Initialisierung in C

Lesezeit: 7 Minuten

Benutzer-Avatar
voltaa7

Ich habe Zweifel bezüglich des folgenden Codeabschnitts:

int main()
{
    int array1 = {1,2,3,4,5}; //error in c++ , warning in c
    int array2[] = {1,2,3,4,5};
    int array3[5] = {1,2,3,4,5};
}

Dieser Codeabschnitt gibt in Zeile 3 einen Fehler aus c++ aber nicht drin c?

Ich weiss array1 ist eigentlich ein int und array2 und array3 sind Arrays, warum also nicht a c Compiler zeigt einen Fehler, aber nur eine Warnung: “excess elements in skalar initialization”

Gibt es eine Verwendung einer solchen Definition und warum ist sie gültig in c?

  • Welchen Compiler verwenden Sie, da VS 2012 dies als Fehler behandelt

    – Ali Kazmi

    29. Oktober 2014 um 10:25 Uhr

  • C ist nicht gleich C++.

    – Basile Starynkevitch

    29. Oktober 2014 um 10:26 Uhr

  • Welche Zeile genau gibt den Fehler aus? Zeile 4 ist die Deklaration von array2aber die einzige problematische Zeile ist die von array1.

    – Mike Seymour

    29. Oktober 2014 um 10:27 Uhr

  • Er soll sagen, was er meint.

    – Leichtigkeitsrennen im Orbit

    29. Oktober 2014 um 11:18 Uhr

  • @BasileStarynkevitch In diesem Fall sind sie es. Fast Wort für Wort.

    – James Kanze

    29. Oktober 2014 um 11:56 Uhr

Benutzer-Avatar
Lundin

Es ist nicht gültig C. Siehe C11 6.7.9:

Kein Initialisierer darf versuchen, einen Wert für ein Objekt bereitzustellen, das nicht in der zu initialisierenden Entität enthalten ist.

Ich würde vermuten, dass Sie gcc verwenden. Wenn Sie dann möchten, dass sich Ihr Programm wie striktes Standard-C verhält, kompilieren Sie es als solches:

gcc -std=c11 -pedantic-errors

gibt

Fehler: Überzählige Elemente im Skalar-Initialisierer

  • Es handelt sich um eine Einschränkungsverletzung, und gcc gibt auch ohne die erforderliche Diagnose korrekt aus -pedantic-errors, was in Bezug auf ISO C streng genug ist. Eine Implementierung ist nicht erforderlich, um den Code abzulehnen.

    – PP

    29. Oktober 2014 um 11:12 Uhr

  • @BlueMoon Das liegt daran, dass es im Standard keine Warnungen und Fehler gibt. Für den Programmierer sind Fehler besser.

    – Ludin

    29. Oktober 2014 um 11:57 Uhr

Benutzer-Avatar
Baldrickk

Es ist nicht gültig in C. Es hat nur weniger Überprüfungen des Codes. Dies ist ein undefiniertes Verhalten.

Aus: C11-Entwurf N1570; 6.7.9 Initialisierung

Einschränkungen
2 Kein Initialisierer darf versuchen, einen Wert für ein Objekt bereitzustellen, das nicht in der zu initialisierenden Entität enthalten ist.
3 Der Typ der zu initialisierenden Entität muss ein Array unbekannter Größe oder ein vollständiger Objekttyp sein, der kein Array-Typ mit variabler Länge ist.

Bricht definitiv Einschränkung 2. Ist ein int a vollständiger Objekttyp?

aus Anhang J.2 (undefiniertes Verhalten):

Der Initialisierer für einen Skalar ist weder ein einzelner Ausdruck noch ein einzelner Ausdruck in geschweiften Klammern (6.7.9).

extra:
@JamesKanze:

prog.c:4:12: error: expected identifier or ‘(’ before numeric constant
  int i = 1,2,3,4,5;
            ^

Sie können es tun, aber Sie müssen es zu einem Ausdruck machen:

int i = (1,2,3,4,5); //need parenthesis, evaluates to 5, values 1-4 thrown away.

Kompilieren mit einem int mit einem initialisiert Initialisierungsliste erzeugt eine Warnung (in gcc):

prog.c:5:2: warning: excess elements in scalar initializer [enabled by default]
  int j = {1,2,3,4,5};
  ^

aber es scheint, dass der Compiler schlau genug ist, nur das int und nicht den folgenden Speicher zu initialisieren.
Demo

  • Nicht sicher, ob eine Einschränkungsverletzung zu undefiniertem Verhalten führt. Sagt oder impliziert die C-Norm das?

    – PP

    29. Oktober 2014 um 11:19 Uhr


  • Aber 1, 2, 3, 4, 5 kann als einzelner Initialisierer interpretiert werden. (int x = 1, 2, 3, 4, 5; ist auf jeden Fall legal.)

    – James Kanze

    29. Oktober 2014 um 11:57 Uhr

  • aber {1,2,3,4,5} != 1,2,3,4,5. Ersteres ist eine Initialisierungsliste und letzteres sind 5 verschiedene Werte mit dem Komma-Operator. Ich denke das gilt: The initializer for a scalar is neither a single expression nor a single expression enclosed in braces (6.7.9). Bitte korrigieren Sie mich, wenn falsch

    – Baldrickk

    29. Oktober 2014 um 12:00 Uhr


  • @JamesKanze hat einen Vergleich zwischen hinzugefügt int i = {12345}; und int j = (1,2,3,4,5);

    – Baldrickk

    29. Oktober 2014 um 14:05 Uhr

Es ist gemäß der C-Spezifikation gültig.

Zitat aus C11 Abschnitt 6.7.9 (Initialisierung):

Syntax

1 initializer:
    assignment-expression
    { initializer-list }
    { initializer-list , }

Ein Initialisierer kann also entweder ein direkter Ausdruck sein (assignment-expression oben) oder eine in geschweifte Klammern eingeschlossene Liste von Initialisierern. Die Einschränkungen in diesem Abschnitt des Standards schränken dies nicht für “normale” (Nicht-Array- oder Nicht-Zeiger-)Variablen ein.

Damit schreibt man zB

int a = { 1 };

  • Dies ist die relevanteste (und sogar richtige) Antwort aus dieser Liste von Antworten.

    – Bitzelle

    29. Oktober 2014 um 10:34 Uhr

  • Mein C-Compiler akzeptiert den einzelnen Wert {1} sagt aber von OP’s array1 “Fehler C2078: zu viele Initialisierer”.

    – Wetterfahne

    29. Oktober 2014 um 10:38 Uhr

  • Aber was ist mit dem allerersten normativen Text unterhalb der erwähnten Syntax? No initializer shall attempt to provide a value for an object not contained within the entity being initialized. Die Syntax, die Sie zitieren, erlaubt es tatsächlich int a = {1} aber das heißt nicht int array1 = {1,2,3,4,5}; erlaubt ist, aus dem gleichen Grund nicht erlaubt int array1[1] = {1,2,3,4,5};

    – Ludin

    29. Oktober 2014 um 10:43 Uhr


  • Eigentlich gibt es hier keinen Unterschied zwischen C und C++. In beiden Fällen gibt es eine Mehrdeutigkeit im Standard, und der Grund dafür, dass sich die C- und C++-Compiler des OP unterschiedlich verhalten, liegt einfach darin, dass die Autoren den Standard unterschiedlich interpretiert haben.

    – James Kanze

    29. Oktober 2014 um 11:55 Uhr

  • Das Zitieren der Grammatik ohne die Einschränkungen sagt wirklich nicht genug über die Geschichte aus, dies ist wirklich nur die halbe Antwort, die Einschränkungen im Text sind für diese Frage wichtig.

    – Shafik Yaghmour

    29. Oktober 2014 um 12:17 Uhr


Benutzer-Avatar
James Kanze

Wie alle anderen gehe ich davon aus, dass die Zeile, über die Sie sich wundern, lautet:

int array1 = {1,2,3,4,5};

In diesem Fall gibt es keinen Unterschied zwischen C und C++; Die Zeile ist wohl in beiden Sprachen legal, aber sie bedeutet nicht, was Sie vielleicht denken. Sowohl in C als auch in C++ gibt es eine Anweisung, dass, wenn der Typ ein Skalartyp ist (int ist), dann der Inhalt der {...} muss ein einzelner Ausdruck sein. Und 1,2,3,4,5 kann als einzelner Ausdruck interpretiert werden (mit dem Komma-Operator); etwas wie:

int array1 = 1, 2, 3, 4, 5;

ist eindeutig legal.

Es ist jedoch etwas mehrdeutig, da in beiden Sprachen die Grammatik für diese Art der Initialisierung macht das , Satzzeichen und kein Operator. Es ist also eine Frage der Interpretation; ist die Aussage, dass der Inhalt ein einzelner Ausdruck sein muss, eine Beschränkung der Grammatik (wodurch das Komma zu einem Operator werden würde) oder eine Beschränkung der Ergebnisse der Auswertung der angegebenen Grammatik. Mein intuitives Gefühl ist, dass das zweite die Absicht ist und dass die Aussage zu einem Fehler führen sollte. Aber der Unterschied liegt nicht zwischen C und C++, sondern darin, wie die Autoren der Compiler den Standard interpretieren.

BEARBEITEN:

Um nochmal etwas genauer nachzulesen: Im C++-Standard steht das explizit drin

Wenn T ein Skalartyp ist, dann eine Deklaration der Form

    T x = { a };

ist äquivalent zu

    T x = a;

Was nicht viel Spielraum lässt: In C++ scheint die Aussage eindeutig legal zu sein; Nur in C gibt es einige Mehrdeutigkeiten.

Der richtige Weg, ein Array in C/C++ zu initialisieren, ist:

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

Hier informieren die eckigen Klammern den Compiler tatsächlich darüber, dass dies ein Array ist, in Ihrem Fall eine Reihe von Zahlen. Bei dieser Art der Initialisierung ist es nicht erforderlich, die Länge des Arrays anzugeben. Der Compiler wird es wissen.

Die zweite Möglichkeit besteht darin, ein Array zu definieren und es nachträglich zu initialisieren:

int array3[5];
int *array = new int[5];

In diesem Fall müssen Sie dem Compiler mitteilen, welche Größe das Array haben wird. Außerdem müssen Sie im zweiten Fall den Speicher manuell löschen.

  • Das ist keine Antwort auf die Frage.

    – Jens Gustedt

    29. Oktober 2014 um 13:07 Uhr

Benutzer-Avatar
Jens Gustedt

Wie Ihr Compiler sagt, ist dies auch für C nicht korrekt. Das Wichtige, was hier zu beachten ist, ist, dass der Compiler im Falle solcher “Einschränkungsverletzungen” (der offizielle Begriff) möglicherweise nur eine Diagnose erstellt (was Ihr Compiler getan hat) und fortfährt.

Deshalb sollten Sie generell darauf achten, dass Ihr Code ohne kompiliert wird irgendein Diagnose was auch immer.

  • Das ist keine Antwort auf die Frage.

    – Jens Gustedt

    29. Oktober 2014 um 13:07 Uhr

C ist eine permissive Low-Level-Sprache. Es erlaubt, einen Zeiger auf ein int zu beeinflussen.

int array1 = {1,2,3,4,5};

BEARBEITEN :

Ich hätte es unter verschiedenen Compilern testen sollen, bevor ich dumme Dinge schreibe.

Dies wird von MSVC (2008) als Fehler zurückgewiesen.

Sowohl gcc als auch clang geben eine Warnung aus excess elements in scalar initializer und beeinflussen einfach 1 bis a.

  • Woher weiß der Compiler, dass es sich um ein Array von handelt chars? Warum nicht integers? doubleist jemand? Entschuldigung, aber Ihre Antwort ist Unsinn. Die Initialisierungsliste hat keinen Typ C.

    – GreenScape

    29. Oktober 2014 um 13:00 Uhr

  • Sie könnten ein böses Reinterpreting-Casting durchführen, um den Zeiger zu einem zu machen int, obwohl ich nicht auf Initialisierung vermute. +1 für eine falsche Aussage und daraus lernen.

    – imallett

    29. Oktober 2014 um 18:12 Uhr

1225300cookie-checkArray-Initialisierung in C

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy