2016-10-10 1 views
3

Zum Beispiel, warum nicht:Warum werden Zeichenfolgen in C mit 'const' deklariert?

char *s= "example"; 

statt:

const char *s= "example"; 

verstehe ich, dass const es unveränderlich macht, aber warum erhalte ich einen Fehler, wenn die erste Zusammenstellung?

Zusätzlich wie funktioniert das Konzept

int * x; 

vs

const int *x; 

gelten sehe ich die zweite viel mehr verwendet wird, ist es gute Praxis "cons * int" zu benutzen?

+2

Weil Sie String-Literale nicht ändern können. –

+0

das erklärt nicht, warum es nicht geändert werden kann. Da char * s = "Beispiel" sollte nur ein Array von Zeichen geben. Ich verstehe, dass Sie nicht sollten, aber es erklärt nicht, warum Sie nicht können. –

+0

Ich glaube nicht, dass Sie einen Fehler mit dem ersten bekommen, es ist gültig. – krato

Antwort

12

Es gibt keine Anforderung, const zu verwenden, aber es ist eine gute Idee.

In C wird ein Stringliteral ist ein Ausdruck des Typs char[N], wo N die Länge der Zeichenkette plus 1 (für die Beendigung '\0' Null-Zeichen). Der Versuch, das Array zu ändern, das dem Zeichenfolgenliteral entspricht, hat jedoch ein nicht definiertes Verhalten. Viele Compiler sorgen dafür, dass dieses Array im Nur-Lese-Speicher gespeichert wird (kein physisches ROM, sondern Speicher, der vom Betriebssystem als schreibgeschützt markiert ist). (Ein Array-Ausdruck wird in den meisten Kontexten in einen Zeiger-Ausdruck umgewandelt, der sich auf das Anfangselement des Array-Objekts bezieht.)

Es wäre sinnvoller gewesen, Zeichenfolgenliterale const zu erstellen, aber das Schlüsselwort const existierte nicht in alten Versionen von C, und es hätte bestehenden Code gebrochen. (C++ hat String-Literale gemacht const).

Dies:

char *s= "example"; /* not recommended */ 

ist in C tatsächlich vollkommen gültig, aber es ist potenziell gefährlich. Wenn Sie nach dieser Deklaration Folgendes tun:

s[0] = 'E'; 

dann versuchen Sie, das Zeichenfolgenliteral zu ändern, und das Verhalten ist nicht definiert.

Dies:

const char *s= "example"; /* recommended */ 

ist auch gültig; Der Wert char*, der aus der Auswertung des Zeichenfolgenliterals resultiert, wird sicher und leise in const char* konvertiert. Und es ist im Allgemeinen besser als die erste Version, weil es Sie vom Compiler warnen lässt, wenn Sie versuchen, das String-Literal zu ändern (es ist besser, Fehler während der Kompilierung als zur Laufzeit zu finden).

Wenn Sie bei Ihrem ersten Beispiel einen Fehler erhalten, ist es wahrscheinlich, dass Sie versehentlich Ihren Code als C++ anstatt als C kompilieren - oder dass Sie die Option -Wwrite-strings von gcc oder etwas ähnliches verwenden. (-Wwrite-strings macht Stringliterale const;. Es die Sicherheit verbessern kann, aber es kann auch gcc verursachen abzulehnen oder zumindest zu warnen, gültig C-Code)

+0

Es ist vielleicht erwähnenswert, dass 'char s1 [] =" Beispiel "; char s2 [] = "example"; 'Jede Variable erhält ein eigenes Array, das den String" example "enthält, und die beiden Kopien können unabhängig voneinander modifiziert werden, aber mit' char * p1 = "example"; char * p2 = "Beispiel"; 'Beide Zeiger können das * selbe * Array identifizieren; Selbst wenn der Speicher nicht schreibgeschützt ist, kann das Ändern des Ziels eines Zeigers auch das Ziel des anderen ändern (oder eine beliebige andere Zeichenfolge, die zufälligerweise mit einigen oder allen Zeichen in "Beispiel" endet). – supercat

+0

Gegeben der Kontext einiger der Bibliotheksfunktionen string.h, zum Beispiel char * strcat (char * dest, const char * src), die Funktion, die Strings verkettet, wäre der Rückgabewert und der erste Parameter nicht 'unsicher' '? –

+1

@ B.Li: Der von 'strcat' zurückgegebene Wert ist einfach der Wert des' dest' Arguments.Es kann unsicher sein, wenn eines der Argumente ein ungültiger oder anderweitig ungültiger Zeiger ist oder wenn das Zielarray keinen Platz hat. Es gibt kein Problem mit der Korrektheit, wenn Sie das denken. –

2

Mit Visual Studio 2015 auf Warnstufe 4, das kompiliert und läuft entweder als C oder C++ kompiliert:

#include <stdio.h> 

char *s1= "example\n"; 
const char *s2= "example\n"; 

int main(int argc, char **argv) 
{ 
    printf(s1); // prints "example" 
    s1[2] = 'x'; 
    printf(s1); // prints "exxmple" 

    printf(s2); 

    return 0; 
} 

Wenn ich diese Zeile hinzufügen, wird es nicht wie C oder C++ mit jedem Compiler, den ich kompilieren weiß von:

s2[2] = 'x'; // produces compile error 

Dies ist der Fehler des const Schlüsselwort ausgelegt ist, zu vermeiden. Es weist den Compiler einfach an, Zuweisungen zu dem Objekt zuzulassen, auf das verwiesen wird.

Es spielt keine Rolle, ob Ihr Zeiger auf char oder int oder irgendetwas anderes zeigt. Das Schlüsselwort const hat den gleichen Effekt auf alle Zeiger, und das macht es unmöglich (gut, sehr schwer), dem Ding zu deklarieren, das als const deklariert wurde.

0

A Stringliteral verwendet als ein Wert auf ein Array von char kompiliert, sollte nicht geändert werden. Der Versuch, sie zu ändern, ruft undefiniertes Verhalten auf. Aus historischen Gründen der Abwärtskompatibilität ist sein Typ char [], obwohl es wirklich const char [] sein sollte. Sie können zusätzliche Compilerwarnungen aktivieren, um dies zu ändern, und den Compiler anweisen, solche Zeichenfolgen als const zu betrachten.

Verwandte Themen