Wie wird das char-Array in C ++ gespeichert?
int main()
{
char c1[5]="abcde";
char c2[5]={'a','b','c','d','e'};
char *s1 = c1;
char *s2 = c2;
printf("%s",s1);
printf("%s",s2);
return 0;
}
In diesem Codeausschnitt gibt das Zeichenarray C2 keinen Fehler zurück, aber das Zeichenarray C1 gibt eine zu lange Zeichenfolge zurück. Ich weiß, dass C1 eine Größe von 6 benötigen muss, um 5 Zeichen zu speichern, da es das \0(NULL- Zeichen ) im letzten Index speichert . Aber ich bin verwirrt, warum C2 dann gut funktioniert?
Auch wenn C2 gedruckt wird %s, ist die Ausgabe abcde@wo @ein gibberish Charakter. %smit printfdruckt alle Zeichen ab der angegebenen Adresse bis \0angetroffen. Ich verstehe nicht, warum am Ende dieses zusätzliche Zeichen gedruckt wird .
Antworten
Ich weiß, dass C1 eine Größe von 6 benötigen muss, um 5 Zeichen zu speichern, da es das
\0(NULL- Zeichen ) im letzten Index speichert . Aber ich bin verwirrt, warum C2 dann gut funktioniert?
Der Compiler beschwert sich nicht über die Initialisierung von, c2da die Initialisierung mit {'a','b','c','d','e'}nicht implizit ein abschließendes Nullzeichen enthält.
Im Gegensatz dazu enthält die Initialisierung mit "abcde"ein Nullzeichen: Der C-Standard definiert ein Zeichenfolgenliteral so, dass es ein abschließendes Nullzeichen enthält char c1[5]="abcde";. Initialisiert also nominell ein 5-Element-Array mit 6 Werten. Der C-Standard erfordert in diesem Fall keine Warnung oder keinen Fehler, da C 2018 6.7.9 14 angibt, dass das Nullzeichen möglicherweise vernachlässigt wird, wenn das Array keinen Platz dafür hat. Der von Ihnen verwendete Compiler 1 hat jedoch eine Warnmeldung ausgegeben, da diese Form der Initialisierung häufig auf einen Fehler hinweist: Der Programmierer hat versucht, ein Array mit einer Zeichenfolge zu initialisieren, es ist jedoch kein Platz für die vollständige Zeichenfolge vorhanden.
In C sind Arrays von Zeichen und Zeichenfolgen verschiedene Dinge: Ein Array ist eine Folge von Werten, und ein Array von Zeichen kann beliebige Werte dieser Zeichen enthalten, einschließlich eines Nullwerts am Ende und möglicher Nullwerte in der Mitte. Wenn wir beispielsweise einen Bytepuffer aus einer Binärdatei haben, sind die Bytes für uns nur ganzzahlige Werte. Ihre Bedeutung als Zeichen, die gedruckt werden könnten, ist irrelevant. Eine Zeichenfolge ist eine Folge von Zeichen, die durch ein Nullzeichen abgeschlossen wird. Es kann keine internen Nullwerte haben, da das erste Nullzeichen das Ende markiert.
Wenn Sie also ein Array von Zeichen definieren, z. B. char c1[5], weiß der Compiler nicht automatisch, ob Sie es zum Speichern von Zeichenfolgen oder als Array von beliebigen Werten verwenden möchten. Wenn Sie das Array mit einer Zeichenfolge initialisieren, geht Ihr Compiler im Wesentlichen davon aus, dass Sie das Array zum Speichern von Zeichenfolgen verwenden möchten, und warnt Sie, wenn die Zeichenfolge, mit der Sie das Array initialisieren, nicht passt. Wenn Sie das Array mit einer Liste von Werten initialisieren, stellt Ihr Compiler im Wesentlichen fest, dass Sie es möglicherweise verwenden, um beliebige Werte zu speichern, und er warnt Sie nicht, dass möglicherweise ein Terminator fehlt.
Auch wenn C2 gedruckt wird
%s, ist die Ausgabeabcde@wo@ein gibberish Charakter.
Da c2es kein Abschlusszeichen gibt, wird der Versuch, es zu drucken, am Ende des Arrays ausgeführt, was zu einem Verhalten führt, das nicht durch den C-Standard definiert ist. Im Allgemeinen wird der printfSpeicher über das Array hinaus weiter gelesen und alles gedruckt, was gerade vorhanden ist, bis ein Nullzeichen erreicht ist.
Fußnote
1 Dies setzt voraus, dass Sie tatsächlich einen C-Compiler verwenden, um diesen Quellcode zu kompilieren. C ++ hat andere Regeln und erlaubt nicht, dass ein Array, das mit einem String-Literal initialisiert wird, zu kurz ist, um das abschließende Nullzeichen aufzunehmen.
Sie haben zwei nicht abgeschlossene Zeichenfolgen erstellt. Machen Sie Ihre Arrays groß genug, um den Null-Terminator zu halten, und vermeiden Sie dieses undefinierte Verhalten:
char c1[6] = "abcde";
char c2[6] = {'a','b','c','d','e','\0'};
Streng genommen erfordert letzteres nicht das '\0'. Diese Deklaration ist äquivalent und enthält den Nullterminator:
char c2[6] = {'a','b','c','d','e'};
Ich persönlich bevorzuge die erste Form, aber mit dem zusätzlichen Komfort, die explizite Länge weglassen zu können:
char c1[] = "abcde";