15 Stimmen

Strtok - char-Array gegen char-Pointer

Möglicher Duplikat:
strtok lehnt char *str ab

Wenn die strtok-Funktion verwendet wird, führt die Verwendung von char * anstelle von char [] zu einem Segmentation-Fehler.

Dies läuft korrekt:

char string[] = "hello world";
char *result = strtok(string, " ");

Dies führt zu einem Segmentation-Fehler:

char *string = "hello world";
char *result = strtok(string, " ");

Kann jemand erklären, was dieses unterschiedliche Verhalten verursacht?

34voto

aschepler Punkte 68538
char string[] = "hello world";

Diese Zeile initialisiert string als ein groß genuges Array von Zeichen (in diesem Fall char[12]). Es kopiert diese Zeichen in Ihr lokales Array, als ob Sie geschrieben hätten

char string[] = { 'h', 'e', 'l', 'l', 'o', ' ', 'w', 'o', 'r', 'l', 'd', '\0' };

Die andere Zeile:

char* string = "hello world";

initialisiert kein lokales Array, sondern nur einen lokalen Zeiger. Der Compiler darf ihn auf einen Zeiger auf ein Array setzen, das Sie nicht ändern dürfen, als ob der Code wie folgt wäre

const char literal_string[] = "hello world";
char* string = (char*) literal_string;

Der Grund, warum C dies ohne Cast erlaubt, ist hauptsächlich, um alten Code weiterhin kompilieren zu lassen. Sie sollten so tun, als ob der Typ eines Zeichenliteral in Ihrem Quellcode const char[] ist, der sich in const char* umwandeln lässt, aber es niemals in ein char* umwandeln.

14voto

Michael Burr Punkte 320591

Im zweiten Beispiel:

char *string = "hello world";
char *result = strtok(string, " ");

Der Zeiger string zeigt auf eine String-Literalkonstante, die nicht modifiziert werden kann (wie es strtok() gerne machen würde).

Sie könnten etwas in der Art tun:

char *string = strdup("hello world");
char *result = strtok(string, " ");

so dass string auf eine veränderbare Kopie des Literals zeigt.

4voto

Jerry Coffin Punkte 452852

strtok modifiziert den von Ihnen übergebenen String (oder versucht es zumindest). In Ihrem ersten Code geben Sie die Adresse eines Arrays an, das auf einen bestimmten Wert initialisiert wurde - aber da es sich um ein normales Array von char handelt, ist das Modifizieren erlaubt.

Im zweiten Code geben Sie die Adresse eines String-Literals an. Der Versuch, einen String-Literal zu ändern, führt zu undefiniertem Verhalten.

3voto

zwol Punkte 128461

In dem zweiten Fall (char *) befindet sich der String im schreibgeschützten Speicher. Der korrekte Typ für String-Konstanten ist const char *, und wenn Sie diesen Typ verwenden, um die Variable zu deklarieren, werden Sie vom Compiler gewarnt, wenn Sie versuchen, sie zu ändern. Aus historischen Gründen dürfen Sie String-Konstanten verwenden, um Variablen vom Typ char * zu initialisieren, obwohl sie nicht geändert werden können. (Einige Compiler ermöglichen es Ihnen, diese historische Lizenz auszuschalten, z.B. mit gcc's -Wwrite-strings.)

0voto

Chris Dodd Punkte 109402

Der erste Fall erstellt ein (nicht konstantes) Char-Array, das groß genug ist, um den String zu halten, und initialisiert es mit dem Inhalt des Strings. Der zweite Fall erstellt einen Char-Pointer und initialisiert ihn so, dass er auf das String-Literal zeigt, das wahrscheinlich im schreibgeschützten Speicher gespeichert ist.

Da strtok den Speicher modifizieren möchte, auf den das Argument zeigt, verursacht der letztere Fall ein undefiniertes Verhalten (Sie übergeben einen Zeiger, der auf ein (konstantes) String-Literal zeigt), daher ist es nicht überraschend, dass es abstürzt

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X