Was ist der Unterschied zwischen
char* name
was auf ein konstantes String-Literal verweist, und
const char* name
char*
ist ein veränderbarer Zeiger auf einen veränderbaren Zeichen/String.
const char*
ist ein veränderbarer Zeiger auf eine unveränderliche Zeichen/Zeichenfolge. Sie können den Inhalt der Orte, auf die dieser Zeiger zeigt, nicht ändern. Außerdem müssen Compiler Fehlermeldungen eingeben, wenn Sie dies versuchen. Aus demselben Grund wird die Konvertierung von const char *
in char*
nicht mehr unterstützt.
char* const
ist ein unveränderlicher Zeiger (er kann nicht auf einen anderen Ort verweisen) aber der Inhalt des Ortes, auf den er verweist - mutierbar .
const char* const
ist ein unveränderlicher Zeiger auf eine unveränderliche Zeichen/Zeichenfolge.
char *name
Sie können das Zeichen ändern, auf das name
zeigt, und auch das Zeichen, auf das es zeigt.
const char* name
Sie können das Zeichen ändern, auf das name
zeigt, aber Sie können das Zeichen, auf das es zeigt, nicht ändern.
Korrektur: Sie können den Zeiger ändern, aber nicht das Zeichen, auf das name
zeigt ( https://msdn.Microsoft .com/de-de/library/vstudio/whkd4k6a (v = vs.100) .aspx , siehe "Beispiele"). In diesem Fall gilt der const
-Spezifizierer für char
, nicht für das Sternchen.
Gemäß der MSDN-Seite und http://en.cppreference.com/w/cpp/language/declarations ist die const
vor dem *
Teil der Deklarationsspezifizierer-Sequenz, während die const
nach *
ein Teil von ist der deklarator.
Eine Deklarationsbezeichnersequenz kann von mehreren Deklaratoren gefolgt werden, weshalb const char * c1, c2
c1
als const char *
und c2
als const char
deklariert.
EDIT:
In den Kommentaren scheint Ihre Frage nach dem Unterschied zwischen den beiden Deklarationen zu fragen, wenn der Zeiger auf ein String-Literal zeigt.
In diesem Fall müssen Sie sollte nicht das Zeichen ändern, auf das name
zeigt, da dies zu Undefined Behavior..__ führen kann. String-Literale können in schreibgeschützten Speicherbereichen (Implementierung) zugewiesen werden definiert) und ein Benutzerprogramm sollte es in keiner Weise ändern. Jeder Versuch führt dazu undefiniertes Verhalten.
Der einzige Unterschied in diesem Fall (der Verwendung mit String-Literalen) besteht also darin, dass die zweite Deklaration Ihnen einen leichten Vorteil verschafft. Compiler geben normalerweise eine Warnung aus, falls Sie versuchen, das String-Literal im zweiten Fall zu ändern.
#include <string.h>
int main()
{
char *str1 = "string Literal";
const char *str2 = "string Literal";
char source[] = "Sample string";
strcpy(str1,source); //No warning or error, just Undefined Behavior
strcpy(str2,source); //Compiler issues a warning
return 0;
}
Ausgabe:
cc1: Warnungen, die als Fehler behandelt werden
prog.c: In der Funktion 'main':
prog.c: 9: Fehler: Durch das Übergeben von Argument 1 von "strcpy" werden Qualifizierer vom Zeigerzieltyp verworfen
Beachten Sie, dass der Compiler für den zweiten Fall warnt, nicht jedoch für den ersten.
char mystring[101] = "My sample string";
const char * constcharp = mystring; // (1)
char const * charconstp = mystring; // (2) the same as (1)
char * const charpconst = mystring; // (3)
constcharp++; // ok
charconstp++; // ok
charpconst++; // compile error
constcharp[3] = '\0'; // compile error
charconstp[3] = '\0'; // compile error
charpconst[3] = '\0'; // ok
// String literals
char * lcharp = "My string literal";
const char * lconstcharp = "My string literal";
lcharp[0] = 'X'; // Segmentation fault (crash) during run-time
lconstcharp[0] = 'X'; // compile error
// *not* a string literal
const char astr[101] = "My mutable string";
astr[0] = 'X'; // compile error
((char*)astr)[0] = 'X'; // ok
In keinem Fall können Sie ein String-Literal ändern, unabhängig davon, ob der Zeiger auf dieses String-Literal als char *
oder const char *
deklariert ist.
Der Unterschied besteht jedoch darin, dass der Compiler, wenn der Zeiger const char *
ist, eine Diagnose abgeben muss, wenn Sie versuchen, den angegebenen Wert zu ändern. Wenn der Zeiger char *
ist, ist dies jedoch nicht der Fall.
Das erste können Sie tatsächlich ändern, wenn Sie möchten, das zweite können Sie nicht. Informieren Sie sich über const
-Korrektheit. Es gibt auch char const * name
, wo Sie es nicht neu festlegen können.
FALL 1:
char *str = "Hello";
str[0] = 'M' //No warning or error, just Undefined Behavior
Das obige setzt str so, dass es auf den Literalwert "Hello" verweist, der im Binärbild des Programms, das im Speicher als schreibgeschützt gekennzeichnet ist, hartcodiert ist, bedeutet, dass jede Änderung dieses String-Literal ungültig ist und Segmentierungsfehler verursacht.
FALL 2:
const char *str = "Hello";
str[0] = 'M' //Compiler issues a warning
FALL 3:
char str[] = "Hello";
str[0] = 'M'; // legal and change the str = "Mello".
Tatsächlich ist char* name
kein Zeiger auf eine Konstante, sondern ein Zeiger auf eine Variable. Sie sprechen vielleicht über diese andere Frage.
Was ist der Unterschied zwischen char * const und const char *?
Die Frage ist, worin der Unterschied besteht
char *name
was auf ein konstantes String-Literal verweist, und
const char *cname
D.h. gegeben
char *name = "foo";
und
const char *cname = "foo";
Es gibt keinen großen Unterschied zwischen den beiden und beide können als richtig angesehen werden. Aufgrund des langen Erbes von C-Code hatten die String-Literale den Typ char[]
und nicht const char[]
. Außerdem gibt es viele ältere Codes, die ebenfalls char *
anstelle von const char *
akzeptieren, auch wenn sie die Argumente nicht ändern.
Der Hauptunterschied der 2 ist im Allgemeinen, dass *cname
oder cname[n]
zu lWerten des Typs const char
ausgewertet wird, während *name
oder name[n]
zu lWerten des Typs char
ausgewertet wird, die modifizierbare lWerte sind. Ein konformer Compiler ist erforderlich, um eine Diagnosemeldung zu erzeugen, wenn das Ziel der Zuweisung kein veränderbarer Wert ist ; es muss keine Warnung bei der Zuordnung zu Werten vom Typ char
ausgegeben werden:
name[0] = 'x'; // no diagnostics *needed*
cname[0] = 'x'; // a conforming compiler *must* produce a diagnostics message
Der Compiler ist nicht required, um die Kompilierung in beiden Fällen zu stoppen. es reicht aus, dass es eine warning für die Zuordnung zu cname[0]
erzeugt. Das resultierende Programm ist kein correct - Programm. Das Verhalten des Konstrukts ist undefined. Es kann abstürzen oder, was noch schlimmer ist, es kann nicht abstürzen und das Zeichenfolgenliteral im Speicher ändern.
Um nur ein Beispiel zu nennen:
std::cout << typeid(2.3).name() << '\n'; // -----> prints "double" simply because
//2.3 is a double
//But the "double" returned by typeid(2.3).name() is indeed a
//const char * which consists of 'd','o','u','b','l','e'and'\0'.
//Here's a simple proof to this:
std::cout << typeid(typeid(2.3).name()).name() << '\n'; //prints: "const char *"
const char* charptr
charptr = typeid(2.3).name();
std::cout << charptr[3]; // ---------> prints: "b"
(Ich verwende die typeinfo-Bibliothek: http://www.cplusplus.com/reference/typeinfo/type_info/name )
//Now let's do something more interesting:
char* charptr2="hubble";
strcpy(charptr, charptr2); // --------> Oops! Sorry, this is not valid!
Sie können es ausführen und die Dinge für sich selbst besser sehen.