Warum kann ich den Inhalt von const char * ptr ändern?

9

Ich habe einen Zeiger ptr an eine Funktion übergeben, deren Prototyp sie als const nimmt.

%Vor%

Was meiner Meinung nach bedeutet, dass es den Inhalt von ptr nicht ändern kann. Wie im Falle von foo( const int i ) . Wenn foo() versucht, den Wert von i zu ermitteln, gibt der Compiler einen Fehler aus.
Aber hier sehe ich, dass es den Inhalt von ptr leicht ändern kann.
Bitte sehen Sie sich den folgenden Code an

%Vor%

Beim Kompilieren bekomme ich nur eine Warnung, keinen Fehler:

warning: passing argument 1 of ‘strcpy’ discards qualifiers from pointer target type

und wenn ich es ausführe, bekomme ich eine Ausgabe statt Segmentation Fault

  

main (): Es ist nur um den Raum zu füllen   foo (): ABC
  main (): ABC

Nun, meine Fragen sind: 1 - Was bedeutet const char *str im Prototyp eigentlich?
Bedeutet das, dass die Funktion den Inhalt von str nicht ändern kann? Wenn das so ist, wie kommt dann das obige Programm ändert den Wert?
2 - Wie kann ich sicherstellen, dass der Inhalt des Zeigers, den ich übergeben habe, nicht geändert werden?

Von "Inhalt des Zeigers" in der oben genannten Frage meine ich "Inhalte des Speichers, auf den der Zeiger zeigt", nicht "Adresse, die im Zeiger enthalten ist".

Bearbeiten

Die meisten Antworten sagen, dass dies wegen strcpy und C impliziter Typ-Konvertierung ist. Aber jetzt habe ich das versucht

%Vor%

Diesmal ist die Ausgabe ohne Warnung vom Compiler

  

main (): Es ist nur um den Raum zu füllen   foo (): Tim
  main (): Es ist nur um den Raum zu füllen

Offensichtlich wird der Speicher, auf den str zeigt, auf den Speicherort geändert, der "Tim" enthält, während er in foo() ist. Obwohl ich dieses Mal strcpy() nicht benutzt habe.
Soll nicht const das stoppen? oder mein Verständnis ist falsch?

Mir scheint, dass ich auch mit const die Speicherreferenz und den Inhalt der Speicherreferenz ändern kann. Was nützt es dann?

Können Sie mir ein Beispiel geben, in dem Compiler mir einen Fehler geben wird, dass ich versuche, einen const Zeiger zu ändern?

Vielen Dank an alle für Ihre Zeit und Mühe.

    
Andrew-Dufresne 12.07.2010, 12:52
quelle

5 Antworten

17

Ihr Verständnis ist richtig, const char* ist ein Vertrag, der bedeutet, dass Sie den Speicher nicht durch diesen bestimmten Zeiger ändern können.

Das Problem ist, dass C sehr lax mit Typkonvertierungen ist. strcpy nimmt einen Zeiger auf nicht-const Zeichen, und es wird implizit konvertiert von const char* in char* (wie Ihnen der Compiler hilfreich sagt). Sie könnten genauso einfach eine Ganzzahl anstelle eines Zeigers übergeben. Daher kann Ihre Funktion den Inhalt von ptr nicht ändern, aber strcpy kann, weil sie einen nicht konstanten Zeiger sieht. Sie erhalten keinen Absturz, weil der Zeiger in Ihrem Fall auf einen tatsächlichen Puffer mit ausreichender Größe und nicht auf ein schreibgeschütztes Zeichenfolgenliteral zeigt.

Um dies zu vermeiden, suchen Sie nach Compilerwarnungen oder kompilieren Sie zum Beispiel mit -Wall -Werror (wenn Sie gcc verwenden).

Dieses Verhalten ist spezifisch für C. C ++ zum Beispiel erlaubt das nicht und erfordert eine explizite Umwandlung (C-Style Cast oder const_cast ), um const Qualifikationsmerkmal zu entfernen, wie Sie es erwarten würden.

Beantworten Sie die erweiterte Frage

Sie ordnen ein Zeichenfolgenliteral einem nichtkonstanten Zeichen zu, das leider in C und sogar C ++ zulässig ist! Es wird implizit in char* konvertiert, obwohl das Schreiben über diesen Zeiger jetzt zu einem nicht definierten Verhalten führt. Es ist ein veraltetes Feature und nur C ++ 0x erlaubt dies bisher nicht.

Mit dem gesagt, Um den Zeiger selbst zu ändern, müssen Sie es als const Zeiger auf char ( char *const ) zu deklarieren. Oder, wenn Sie es so machen wollen, dass sowohl der Inhalt, auf den es zeigt, als auch der Zeiger selbst sich nicht ändern, verwenden Sie einen const Zeiger auf const char ( const char * const ).

Beispiele:

%Vor%

Für alle Fehlerzeilen gibt GCC mir "Fehler: Zuweisung der schreibgeschützten Stelle".

    
Alex B 12.07.2010, 12:57
quelle
3

"const" ist wirklich eine Kompilierungszeit, also erwarten Sie keinen segfault, wenn der Zeiger nicht auf einen ungültigen Speicher zeigt. Wenn const-Zeiger in einer Weise verwendet werden, die möglicherweise alles ändern kann, auf das sie zeigen (in diesem Fall an strcpy übergeben, das nicht-const akzeptiert), wird eine Warnung generiert.

    
atis 12.07.2010 13:04
quelle
1
  

1- Was bedeutet const char * str im Prototyp eigentlich?   Bedeutet dies, dass die Funktion den Inhalt von str nicht ändern kann?

Ja! Das bedeutet, dass wir den Inhalt von etwas (entweder char oder array of chars ), auf das str verweisen kann, nicht ändern können.

  

Wenn das so ist, wie kommt es dann, dass das obige Programm den Wert ändert?

Das liegt daran, dass der Prototyp von strcpy() char * strcpy ( char * destination, const char * source );

ist

In Ihrem Code gibt es eine implizite Konvertierung von const char* nach char* type, weil strcpy() verlangt, dass das erste Argument vom Typ char* ist.

Technisch gesehen ist Ihr Code inkorrekt, eher gefährlich. Wenn Sie den gleichen Code in C ++ versuchen, erhalten Sie einen Fehler. C ++ erlaubt solche impliziten Konvertierungen nicht, aber C tut es.

    
Prasoon Saurav 12.07.2010 13:04
quelle
1

IIRC const bedeutet, dass der Wert des Parameters nicht geändert werden darf. In Ihrem Fall ist der Wert die Adresse, auf die der Zeiger zeigt. strcpy ändert nicht die Adresse, auf die der Zeiger zeigt, sondern den Speicher, auf den der Zeiger zeigt.

Die Verwendung von const stellt sicher, dass die Speicherreferenz (Adresse) nicht geändert wird. Der referenzierte Speicher kann jedoch geändert werden. Das ist was hier passiert. Das Zuweisen einer neuen Adresse zu dem Zeiger würde zu einem Fehler führen.

SEITENHINWEIS
Ich würde Ihre foo -Methode als unsicher ansehen. Sie sollten besser auch die maximale Länge von str übergeben und eine Längenüberprüfung durchführen, sonst sind Sie für Pufferüberläufe offen.

BEARBEITEN
Ich habe Folgendes von dieser Website genommen:

  

Das const char *Str sagt dem Compiler   dass die DATA der Zeiger auch zeigt   ist const. Das heißt, Str kann sein   innerhalb von Func geändert, aber *Str kann nicht.   Als Kopie wird der Zeiger übergeben   Func, alle Änderungen an Str sind nicht möglich   gesehen von main ....

    
Thorsten Dittmar 12.07.2010 12:58
quelle
1

const char* ist dasselbe wie char const* und nicht char* const . Das bedeutet also einen Zeiger auf etwas, das Sie nicht ändern können.

Ausarbeitung nach der Bearbeitung Das erste Formular verhindert, dass die Daten geändert werden (außer Sie implizit oder explizit umwandeln), das zweite verhindert, dass der Zeiger selbst geändert wird.

Was Sie in Ihrer bearbeiteten Version tun, ist den Zeiger zu ändern. Das ist hier legal. Wenn Sie beides verhindern würden, müssten Sie char const* const schreiben.

    
Jens Gustedt 12.07.2010 12:56
quelle

Tags und Links