Warum kann ich Zeiger als Zeichenfolgen verwenden, wenn sie in C mit doppelten Anführungszeichen, aber nicht mit geschweiften Klammern deklariert werden? [duplicate]

Lesezeit: 4 Minuten

Benutzer-Avatar
Jawi Mmm

Wenn ich einen Zeiger wie diesen deklariere und verwende:

int counter;
char *pCow = "pCow goes MOO";

for(counter = 0; counter < 14; counter++)
    printf("%c", pCow[counter]);

es zeigt die ganze Saite und funktioniert und ja und es gibt viel Freude.

Wenn ich jedoch einen Initialisierer wie diesen verwende:

int counter;
char *pCow = {'p','C','o','w',' ','g','o','e','s',' ','M','O','O','\0'};

for(counter = 0; counter < 14; counter++)
    printf("%c", pCow[counter]);

Das Programm stürzt ab und pCow weigert sich, zu meinem hedonistischen Vergnügen zu muhen!

3 Warnings. 0 Errors
line 11 (near initialization for 'pCow') [enabled by default]   C/C++ Problem
line 11 excess elements in scalar initializer [enabled by default]  C/C++ Problem
line 11 initialization makes pointer from integer without a cast [enabled by default]   C/C++ Problem

Liebevoll getestet in Eclipse CDT.

  • Wenn dies C (und nicht C++) ist, dann char *pCow = (char[]){'p','C','o','w',' ','g','o','e','s',' ','M','O','O','\0'}; sollte funktionieren und den gleichen effekt haben.

    – Benutzer253751

    16. Oktober 2015 um 6:57 Uhr

  • Beachten Sie, dass die @immibis-Lösung oben ↑ C99 oder höher erfordert. Schau auf Zusammengesetzte Literale um mehr darüber zu erfahren.

    – Spikatrix

    16. Oktober 2015 um 16:17 Uhr


Benutzer-Avatar
DaoWen

In diesem Fall, pCow wird auf die Adresse eines C-Strings im statischen Speicher gesetzt:

char *pCow = "pCow goes MOO";

In diesem Fall, pCow wird auf den Wert gesetzt 'p' (dh, 112):

char *pCow = {'p','C','o','w',' ','g','o','e','s',' ','M','O','O','\0'};

Da die Adresse 112 zeigt höchstwahrscheinlich auf eingeschränkten/ungültigen Speicher, was dazu führt, dass Ihr Programm explodiert, wenn Sie versuchen, darauf zuzugreifen pCow[counter].

Die Warnung “überschüssige Elemente im skalaren Initialisierer” sagt Ihnen, dass es all das Zeug nach dem ignoriert 'p' da der Zeiger nur einen Wert benötigt.

Die Warnung “Initialisierung macht Zeiger aus Integer ohne Cast” sagt Ihnen, dass Sie verwenden 'p' als Anhaltspunkt, was wahrscheinlich keine gute Idee ist …

Was Sie tun möchten, ist zu erklären pCow Als ein Zeichen-Array eher als ein Zeichenzeiger wenn Sie die Initialisierungssyntax verwenden möchten:

char pCow[] = {'p','C','o','w',' ','g','o','e','s',' ','M','O','O','\0'};

  • Macht Sinn. Vielen Dank! du bist heiß. 😐 (kann noch nicht als Antwort akzeptiert werden. Schaltfläche klickt nicht. Ich werde darauf zurückkommen!)

    – Jawi Mmm

    16. Oktober 2015 um 5:33 Uhr


  • @JawiMmm – Ja, sie tun das absichtlich. Freut mich auf jeden Fall, dass dir das geholfen hat! In einer separaten Anmerkung, mit a char* auf ein C-String-Literal zu zeigen, ist auch keine gute Idee (Sie sollten a const char* stattdessen).

    – DaoWen

    16. Oktober 2015 um 5:42 Uhr


  • Beachten Sie hier den Unterschied: using char[] erstellt das Array als lokale Variable und kopiert statische Daten dorthin, während char * erstellt nur einen Zeiger als lokale Variable, der dann auf statische Daten zeigen kann, ohne etwas zu kopieren (weshalb Sie das wollen const char * um auf String-Literale zu zeigen).

    – Hyde

    16. Oktober 2015 um 6:21 Uhr

  • In GCC kann man das so schreiben:char *pCow = (char []) {'p','C','o','w',' ','g','o','e','s',' ','M','O','O','\0'};. Auf diese Weise haben Sie einen Zeiger, der auf ein im statischen Speicher gespeichertes Array zeigt, was der Verwendung von Anführungszeichen entspricht. Mit dieser Syntax können Sie jedoch nicht nur Zeichenarrays verwenden, was praktisch sein kann.

    – Aragaer

    16. Oktober 2015 um 7:15 Uhr

  • @aragaer diese Syntax ist Teil von Standard C

    – MM

    16. Oktober 2015 um 7:49 Uhr

"pCow goes MOO" ist ein Zeichenfolgenliteral und hat zwei unterschiedliche Verwendungszwecke. Entweder Sie können es als Initialisierer für ein Array verwenden:

char aCow[] = "pCow goes MOO";

In diesem Fall wird der Inhalt des String-Literals in das Array kopiert.

Alternativ können Sie ein Zeichenfolgenliteral überall in Ihrem Programm als eigenständiges konstantes Array verwenden. Zum Beispiel strcpy(cow, "pCow goes MOO");. Es gibt also einen deutlichen Unterschied zwischen diesen beiden:

char aCow[] = "pCow goes MOO";
char* pCow  = "pCow goes MOO";

Im ersten Fall wird das Literal in das Array kopiert. Im zweiten Fall bleibt das Literal eine eigenständige Konstante im Nur-Lese-Speicher, auf die wir mit einem Zeiger zeigen. Ersteres kann geändert werden, letzteres nicht.

Was den Fall betrifft

char *pCow = {'p','C','o','w',' ','g','o','e','s',' ','M','O','O','\0'};

Sie verwenden einen Zeiger, aber Sie haben kein Zeichenfolgenliteral. Stattdessen haben Sie eine Initialisierungsliste, die für ein Array bestimmt ist. Ein guter Compiler würde Sie vor “überschüssigem Initialisierer” warnen. Der Grund, warum der Code kompiliert wird, ist eine sehr seltsame Regel in C, die es beispielsweise erlaubt, einfache Variablen mit geschweiften Klammern zu initialisieren int x = {1};. Der Compiler verwendet also diese Regel, um Ihren Zeiger so zu initialisieren, dass er auf die Adresse zeigt 'p'was natürlich Unsinn ist, und verwirft dann den Rest der Initialisierungsliste.

Denn char * zeigt die Daten auf das Textsegment im Speicher und char a[ size ] speichert Daten im Stack. Die Daten im Stapel können geändert werden, aber die Daten im Textsegment können nicht geändert werden.

1368540cookie-checkWarum kann ich Zeiger als Zeichenfolgen verwenden, wenn sie in C mit doppelten Anführungszeichen, aber nicht mit geschweiften Klammern deklariert werden? [duplicate]

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

Privacy policy