Unterschied zwischen char *str=”STRING” und char str[] = “ZEICHENFOLGE”?

Lesezeit: 4 Minuten

Benutzer-Avatar
Gui13

Beim Codieren einer einfachen Funktion zum Entfernen eines bestimmten Zeichens aus einer Zeichenfolge bin ich auf dieses seltsame Problem gestoßen:

void str_remove_chars( char *str, char to_remove)
{
    if(str && to_remove)
    {
       char *ptr = str;
       char *cur = str;
       while(*ptr != '\0')
       {
           if(*ptr != to_remove)
           {
               if(ptr != cur)
               {
                   cur[0] = ptr[0];
               }
               cur++;
           }
           ptr++;
       }
       cur[0] = '\0';
    }
}
int main()
{
    setbuf(stdout, NULL);
    {
        char test[] = "string test"; // stack allocation?
        printf("Test: %s\n", test);
        str_remove_chars(test, ' '); // works
        printf("After: %s\n",test);
    }
    {
        char *test = "string test";  // non-writable?
        printf("Test: %s\n", test);
        str_remove_chars(test, ' '); // crash!!
        printf("After: %s\n",test);
    }

    return 0;
}

Was ich nicht verstehe ist, warum der zweite Test fehlschlägt? Für mich sieht es aus wie die erste Notation char *ptr = "string"; ist äquivalent zu diesem: char ptr[] = "string";.

Ist es nicht der Fall?

  • Sehr guter Artikel zu diesem Thema: eli.thegreenplace.net/2009/10/21/…

    – jyz

    10. April 2013 um 17:03 Uhr

  • Lesen Sie: Unterschied zwischen char *str und char str[] und wie speichert beides im Gedächtnis?

    – Grijesh Chauhan

    6. September 2013 um 5:36 Uhr

Benutzer-Avatar
codaddict

Die beiden Deklarationen sind nicht identisch.

char ptr[] = "string"; deklariert ein char-Array der Größe 7 und initialisiert es mit den Zeichen
s ,t,r,i,n,g und \0. Sie sind erlaubt um den Inhalt dieses Arrays zu ändern.

char *ptr = "string"; erklärt ptr als Zeichenzeiger und initialisiert ihn mit der Adresse von String-Literal "string" welches ist schreibgeschützt. Das Ändern eines Zeichenfolgenliterals ist eine undefiniertes Verhalten. Was Sie gesehen haben (seg fault) ist eine Manifestation des undefinierten Verhaltens.

  • Und ein sizeof(ptr) liefert auch unterschiedliche Ergebnisse für die verschiedenen Deklarationen. Der erste gibt die Länge des Arrays einschließlich des abschließenden Nullzeichens zurück. Die zweite gibt die Länge eines Zeigers zurück, normalerweise 4 oder 8.

    – Prof. Falken

    5. Oktober 2010 um 12:53 Uhr

  • Es gilt zweitens auch, dass der Inhalt von ptr verändert werden kann. Aber der Inhalt ist der Zeiger auf das Literal, nicht die Zeichen.

    – Daron

    5. Oktober 2010 um 13:10 Uhr

  • +1, tolle Antwort. Es ist auch wahr und wichtig, das mit zu verstehen char *ptr = "string"; das ptr kann auf etwas anderes zeigen und kann daher in dem, worauf es zeigt, außer den Zeichen “geändert” werden "string" ist ein Literal und kann sich nicht ändern.

    – Kumpel

    5. Oktober 2010 um 16:07 Uhr


  • Erwähnenswert wären auch die Performance-Probleme. Das Deklarieren einer initialisierten automatischen Array-Variablen füllt den gesamten Array-Inhalt jedes Mal, wenn die Variable in den Geltungsbereich kommt. Durch das Deklarieren einer initialisierten automatischen Zeigervariablen wird einfach der Zeiger zugewiesen (ein einzelnes Wort schreiben), wenn die Variable in den Gültigkeitsbereich kommt. Wenn die Zeichenfolge lang ist oder der Block häufig eingegeben wird (wie bei jeder Iteration einer Schleife), kann der Unterschied sehr signifikant sein!

    – R.. GitHub HÖR AUF, EIS ZU HELFEN

    6. Oktober 2010 um 6:27 Uhr

  • @AmigableClarkKant, eigentlich, sizeof(ptr) ist nicht die Länge des Arrays, es sei denn ptr wird als char-Array deklariert. Wenn ptr ist definiert als ein int Array mit 3 Elementen, sizeof(ptr) wird die Summe von zurückgeben sizeof(int) jedes Elements.

    – 爱国者

    24. Januar 2012 um 8:20 Uhr

Genau genommen eine Erklärung von char *ptr garantiert Ihnen nur einen Zeiger auf den Zeichentyp. Es ist nicht ungewöhnlich, dass die Zeichenfolge einen Teil des Codesegments der kompilierten Anwendung bildet, die von einigen Betriebssystemen auf schreibgeschützt gesetzt wird. Das Problem liegt in der Tatsache, dass Sie eine Annahme über die Art der vordefinierten Zeichenfolge treffen (dass sie beschreibbar ist), obwohl Sie tatsächlich nie selbst explizit Speicher für diese Zeichenfolge erstellt haben. Es ist möglich, dass einige Implementierungen von Compiler und Betriebssystem es Ihnen ermöglichen, das zu tun, was Sie versucht haben.

Auf der anderen Seite die Erklärung von char test[]weist in diesem Fall per Definition lesbaren und beschreibbaren Speicher für das gesamte Array von Zeichen auf dem Stapel zu.

So weit ich mich erinnere

char ptr[] = "string";

schafft ein Kopieren von "string" auf dem Stapel, also ist dieser veränderlich.

Die Form

char *ptr = "string";

ist nur Abwärtskompatibilität für

const char *ptr = "string";

und Sie dürfen (in Bezug auf undefiniertes Verhalten) seinen Inhalt nicht ändern. Der Compiler kann solche Strings in einem Nur-Lese-Abschnitt des Speichers platzieren.

char *test = "string test"; ist falsch, hätte es sein sollen const char*. Dieser Code wird nur aus Gründen der Abwärtskompatibilität kompiliert. Die Erinnerung wies darauf hin const char* ist ein Nur-Lese-Speicher und wenn Sie versuchen, darauf zu schreiben, wird er ein undefiniertes Verhalten hervorrufen. Auf der anderen Seite char test[] = "string test" schafft ein schreibbar Zeichenarray auf Stapel. Dies ist wie jede andere reguläre lokale Variable, in die Sie schreiben können.

Gute Antwort @codaddict.

Auch eine sizeof(ptr) wird für die verschiedenen Deklarationen unterschiedliche Ergebnisse liefern.

Die erste, die Array-Deklaration, gibt die Länge des Arrays zurück einschließlich das abschließende Nullzeichen.

Der zweite, char* ptr = "a long text..."; gibt die Länge eines Zeigers zurück, normalerweise 4 oder 8.

Benutzer-Avatar
Ravi Chandra

char *str = strdup("test");
str[0] = 'r';

ist richtiger Code und erstellt eine veränderliche Zeichenfolge. str wird ein Speicher im Heap zugewiesen, der Wert ‘test’ wird darin ausgefüllt.

1369300cookie-checkUnterschied zwischen char *str=”STRING” und char str[] = “ZEICHENFOLGE”?

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

Privacy policy