Was meinst du mit " konstantes String-Literal" in C (nicht C ++)
gbulmer
1
... char * Name kann gemacht werden, um auf ein konstantes String-Literal zu verweisen
Iceman
Die Konstante im "Konstanten-String-Literal" ist redundant, da alle String-Literale theoretisch konstante Entitäten sind. Es ist der Inhalt der Variablen, der entweder konstant oder veränderbar gemacht werden kann. Die "const" -Deklaration löst einfach einen Fehler bei der Kompilierung aus, wenn Sie versuchen, den Inhalt des Zeichens zu ändern, auf das "name"
Cupcake
Einfach: Der Name "char * name" ist ein Zeiger auf char, dh beide können hier geändert werden. Der Name "const char * name" ist ein Zeiger auf const char, dh der Zeiger kann sich ändern, aber nicht char.
akD
Lesen Sie diese Dinge von rechts nach links.
Jiapeng Zhang
Antworten:
405
char*ist ein veränderbarer Zeiger auf ein veränderliches Zeichen / eine veränderbare Zeichenfolge.
const char*ist ein veränderbarer Zeiger auf ein unveränderliches Zeichen / eine unveränderliche Zeichenfolge. Sie können den Inhalt der Position (en), auf die dieser Zeiger zeigt, nicht ändern. Außerdem müssen Compiler Fehlermeldungen ausgeben, wenn Sie dies versuchen. Aus dem gleichen Grund ist die Umstellung von const char *auf char*veraltet.
char* constist ein unveränderlicher Zeiger (er kann nicht auf einen anderen Ort zeigen), aber der Inhalt des Ortes, auf den er zeigt, ist veränderlich .
const char* constist ein unveränderlicher Zeiger auf ein unveränderliches Zeichen / eine unveränderliche Zeichenfolge.
Verwirrung kann durch die Verwendung einer Variablen nach den oben genannten Anweisungen und durch Bezugnahme auf diese Variable behoben werden.
ankit.karwasra
3
@ ankit.karwasra, Sie haben noch eines verpasst:char const *
Pacerier
Ich nehme an, zwei Optionen mit veränderlichen Zeichen / Zeichenfolgen sind sehr gefährlich, da Sie einen Segmetationsfehlerspeicher erstellen könnten und wenn Sie wirklich schlau sind, könnten Sie den Computer hacken. Aus diesem Grund haben Compiler in diesen Implementierungen, glaube ich, immer Warnungen angezeigt
Daniel N.
1
Wird die Mutation char *beim Ausführen keinen Segmentierungsfehler verursachen?
Divyanshu Maithani
1
Also benutze ich, constwenn ich möchte, dass der Compiler einen Fehler macht, wenn ich die Daten versehentlich vergessen und geändert habe, oder?
Buchhalter م
43
char*name
Sie können das Zeichen ändern, auf das gezeigt wird name, und auch das Zeichen, auf das es zeigt.
constchar* name
Sie können das Zeichen auf welche namePunkte ändern, 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 nameverweist ( https://msdn.microsoft.com/en-us/library/vstudio/whkd4k6a(v=vs.100).aspx , siehe "Beispiele"). ). In diesem Fall gilt der constBezeichner fürchar und nicht das Sternchen.
Gemäß der MSDN - Seite und http://en.cppreference.com/w/cpp/language/declarations , die constvor dem *Teil der Decl-Spezifikationsfolge, während der constnach *Teil des declarator ist.
Auf eine Deklarationsspezifiziererfolge können mehrere Deklaratoren folgen, weshalb as und as const char * c1, c2deklariert werdenc1const char *c2const char .
BEARBEITEN:
Aus den Kommentaren geht hervor, dass Ihre Frage nach dem Unterschied zwischen den beiden Deklarationen fragt, wenn der Zeiger auf ein Zeichenfolgenliteral zeigt.
In diesem Fall Sie sollten nicht das Zeichen , auf die ändern namePunkte, wie es in Folge konnte nicht definiertes Verhalten . String-Literale können in schreibgeschützten Speicherbereichen zugewiesen werden (Implementierung definiert), und ein Benutzerprogramm sollte sie ohnehin nicht ändern. Jeder Versuch, dies zu tun, führt zu undefiniertem Verhalten.
Der einzige Unterschied in diesem Fall (bei Verwendung mit String-Literalen) besteht darin, dass die zweite Deklaration Ihnen einen leichten Vorteil verschafft. Compiler geben normalerweise eine Warnung aus, wenn Sie im zweiten Fall versuchen, das Zeichenfolgenliteral zu ändern.
#include<string.h>int main(){char*str1 ="string Literal";constchar*str2 ="string Literal";char source[]="Sample string";
strcpy(str1,source);//No warning or error, just Undefined Behavior
strcpy(str2,source);//Compiler issues a warningreturn0;}
Ausgabe:
cc1: Warnungen werden als Fehler behandelt
prog.c: In Funktion 'main':
prog.c: 9: Fehler: Übergabe von Argument 1 von 'strcpy' verwirft Qualifizierer vom Zeigerzieltyp
Beachten Sie, dass der Compiler für den zweiten Fall warnt, nicht jedoch für den ersten.
Danke. Ich habe mit dem konstanten String-Literal gemischt, das wie folgt definiert ist: char * name = "String-Literal"; Das Ändern von "String Literal" ist undefiniert.
Iceman
@ user1279782: Err, warte! Sprechen Sie hier über Punkte, die auf String-Literale verweisen? In diesem Fall sollten Sie dasname Zeichen, auf das die Punkte zeigen, in beiden Fällen nicht ändern. Dies könnte zu UB führen.
Alok Save
Ja, das war der Punkt. In diesem Fall verhalten sich char * name und const char * name also ähnlich, oder?
Iceman
4
Diese Antwort ist entweder äußerst zweideutig oder einfach falsch. Ich würde interpretieren "Sie können das Zeichen nicht ändern, auf das der Name zeigt, aber Sie können das Zeichen ändern, auf das es zeigt." Da nicht in der Lage ist , den Zeiger selbst, zu modifizieren , aber die Speicherstelle zu ändern , in der Lage , dass es auf, die nicht korrekt ist: ideone.com/6lUY9s alternativ für reines C: ideone.com/x3PcTP
shroudednight
1
@shroudednight: Sie müssen etwas mehr über undefinierte Verhaltensweisen lernen und unterscheiden zwischen: erlaubt und sollte nicht durchgeführt werden. :)
Alok Save
16
char mystring[101]="My sample string";constchar* constcharp = mystring;// (1)charconst* 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 literalschar* lcharp ="My string literal";constchar* lconstcharp ="My string literal";
lcharp[0]='X';// Segmentation fault (crash) during run-time
lconstcharp[0]='X';// compile error// *not* a string literalconstchar astr[101]="My mutable string";
astr[0]='X';// compile error((char*)astr)[0]='X';// ok
Keiner Ihrer Zeiger verweist gemäß der Frage auf "konstante Zeichenfolgenliterale".
Café
Es ist erwähnenswert, dass das Ändern des char *Werts einen Segmentierungsfehler verursacht, da wir versuchen, ein Zeichenfolgenliteral zu ändern (das im Nur-Lese-Speicher vorhanden ist)
Divyanshu Maithani
10
In keinem Fall können Sie ein Zeichenfolgenliteral ändern, unabhängig davon, ob der Zeiger auf dieses Zeichenfolgenliteral als char *oder deklariert ist const char *.
Der Unterschied besteht jedoch darin, dass const char *der Compiler eine Diagnose geben muss, wenn Sie versuchen, den Zeigerwert zu ändern. Wenn der Zeiger dies ist, char *ist dies jedoch nicht der Fall.
"In keinem Fall können Sie ein Zeichenfolgenliteral ändern, unabhängig davon, ob ... [es] als char * oder const char * deklariert ist." Ich stimme zu, dass der Programmierer es nicht versuchen sollte, aber sagen Sie, dass jeder C-Compiler auf jedem Plattform wird den Code ablehnen, dafür sorgen, dass der Code zur Laufzeit fehlschlägt, oder etwas anderes? Ich glaube, eine Datei könnte die Definition und Initialisierung haben, und eine andere Datei könnte enthalten extern ... nameund haben *name = 'X';. Auf einem 'richtigen Betriebssystem' könnte dies fehlschlagen, aber auf eingebetteten Systemen würde ich erwarten, dass es etwas Plattform- / Compilerspezifisches tut.
Gbulmer
@gbulmer: Sie können ein Zeichenfolgenliteral in einem korrekten C-Programm nicht ändern. Was ein falsches C-Programm, das versucht, dazu führen kann, ist weder hier noch da.
Café
@gbulmer: Eine nützliche Definition ist ein Programm, das keine im C-Sprachstandard festgelegten Einschränkungen verletzt. Mit anderen Worten, ein Programm, das ein Zeichenfolgenliteral ändert, ist genauso falsch wie eines, das einen Nullzeiger dereferenziert oder eine Division durch 0 durchführt, ist falsch.
Café
caf - Ich dachte, das könnten Sie meinen. Dann scheint "In keinem Fall können Sie ein String-Literal ändern" zu viel zu sagen. Es wäre richtig zu sagen: "In beiden Fällen wurden die vom C-Sprachstandard festgelegten Einschränkungen verletzt, unabhängig davon ... Es ist dem Compiler oder dem Laufzeitsystem nicht in allen Fällen möglich, Verstöße gegen den Standard zu identifizieren." Ich gehe davon aus, dass der Standard die Position einnimmt, dass der Effekt undefiniert ist.
Gbulmer
1
Wenn ein Standard so oder so nichts behaupten kann, scheint es genau die richtige Grenze und hilfreich zu sein, Verhalten als "undefiniert" zu definieren. Um die Beziehung zu behaupten, dass ein 'korrektes C-Programm' einen Nullzeiger nicht dereferenzieren kann , klingt dies gleichbedeutend mit dem Beweis des Halteproblems. Aber es macht mir nichts aus. Ich würde es nicht tun und erwarten, damit "
schottfrei
4
FALL 1:
char*str ="Hello";
str[0]='M'//Warning may be issued by compiler, and will cause segmentation fault upon running the programme
Die obigen Sätze str zeigen auf den Literalwert "Hello", der im Binärbild des Programms fest codiert ist und im Speicher als schreibgeschützt gekennzeichnet ist. Dies bedeutet, dass jede Änderung in diesem String-Literal unzulässig ist und Segmentierungsfehler verursachen würde.
FALL 2:
constchar*str ="Hello";
str[0]='M'//Compile time error
Fall 3:
char str[]="Hello";
str[0]='M';// legal and change the str = "Mello".
Das erste können Sie tatsächlich ändern, wenn Sie möchten, das zweite können Sie nicht. Informieren Sie sich über die constRichtigkeit (es gibt einige nette Anleitungen zum Unterschied). Es gibt auch char const * nameStellen, an denen Sie es nicht neu festlegen können.
Es gibt keinen großen Unterschied zwischen der 2 und beide können als richtig angesehen werden. Durch die lange Tradition von C - Code haben die Stringliterale eine Art hatten char[], nicht const char[], und es gibt viele älteren Code, der ebenfalls akzeptieren char *statt const char *, auch wenn sie die Argumente nicht ändern.
Der Hauptunterschied der 2 im Allgemeinen besteht darin, dass *cnameoder cname[n]wird zu l-Werten des Typs ausgewertet const char, wohingegen *nameoder name[n]zu l-Werten des Typs ausgewertet wird char, die modifizierbare l-Werte sind . Ein konformer Compiler muss eine Diagnosemeldung erstellen, wenn das Ziel der Zuweisung kein veränderbarer Wert ist . Bei der Zuordnung zu lWerten des Typs muss keine Warnung ausgegeben werden char:
name[0]='x';// no diagnostics *needed*
cname[0]='x';// a conforming compiler *must* produce a diagnostics message
Der Compiler ist nicht erforderlich , die Zusammenstellung in jedem Fall zu stoppen; es reicht aus, dass es eine Warnung für die Zuordnung zu erzeugt cname[0]. Das resultierende Programm ist kein korrektes Programm. Das Verhalten des Konstrukts ist undefiniert . Es kann abstürzen oder noch schlimmer, es kann nicht abstürzen und das String-Literal im Speicher ändern.
Antworten:
char*
ist ein veränderbarer Zeiger auf ein veränderliches Zeichen / eine veränderbare Zeichenfolge.const char*
ist ein veränderbarer Zeiger auf ein unveränderliches Zeichen / eine unveränderliche Zeichenfolge. Sie können den Inhalt der Position (en), auf die dieser Zeiger zeigt, nicht ändern. Außerdem müssen Compiler Fehlermeldungen ausgeben, wenn Sie dies versuchen. Aus dem gleichen Grund ist die Umstellung vonconst char *
aufchar*
veraltet.char* const
ist ein unveränderlicher Zeiger (er kann nicht auf einen anderen Ort zeigen), aber der Inhalt des Ortes, auf den er zeigt, ist veränderlich .const char* const
ist ein unveränderlicher Zeiger auf ein unveränderliches Zeichen / eine unveränderliche Zeichenfolge.quelle
char const *
char *
beim Ausführen keinen Segmentierungsfehler verursachen?const
wenn ich möchte, dass der Compiler einen Fehler macht, wenn ich die Daten versehentlich vergessen und geändert habe, oder?Sie können das Zeichen ändern, auf das gezeigt wird
name
, und auch das Zeichen, auf das es zeigt.Sie können das Zeichen auf welchename
Punkte ändern, 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
verweist ( https://msdn.microsoft.com/en-us/library/vstudio/whkd4k6a(v=vs.100).aspx , siehe "Beispiele"). ). In diesem Fall gilt derconst
Bezeichner fürchar
und nicht das Sternchen.Gemäß der MSDN - Seite und http://en.cppreference.com/w/cpp/language/declarations , die
const
vor dem*
Teil der Decl-Spezifikationsfolge, während derconst
nach*
Teil des declarator ist.Auf eine Deklarationsspezifiziererfolge können mehrere Deklaratoren folgen, weshalb as und as
const char * c1, c2
deklariert werdenc1
const char *
c2
const char
.BEARBEITEN:
Aus den Kommentaren geht hervor, dass Ihre Frage nach dem Unterschied zwischen den beiden Deklarationen fragt, wenn der Zeiger auf ein Zeichenfolgenliteral zeigt.
In diesem Fall Sie sollten nicht das Zeichen , auf die ändern
name
Punkte, wie es in Folge konnte nicht definiertes Verhalten . String-Literale können in schreibgeschützten Speicherbereichen zugewiesen werden (Implementierung definiert), und ein Benutzerprogramm sollte sie ohnehin nicht ändern. Jeder Versuch, dies zu tun, führt zu undefiniertem Verhalten.Der einzige Unterschied in diesem Fall (bei Verwendung mit String-Literalen) besteht darin, dass die zweite Deklaration Ihnen einen leichten Vorteil verschafft. Compiler geben normalerweise eine Warnung aus, wenn Sie im zweiten Fall versuchen, das Zeichenfolgenliteral zu ändern.
Online-Beispielbeispiel:
Ausgabe:
Beachten Sie, dass der Compiler für den zweiten Fall warnt, nicht jedoch für den ersten.
quelle
name
Zeichen, auf das die Punkte zeigen, in beiden Fällen nicht ändern. Dies könnte zu UB führen.quelle
char *
Werts einen Segmentierungsfehler verursacht, da wir versuchen, ein Zeichenfolgenliteral zu ändern (das im Nur-Lese-Speicher vorhanden ist)In keinem Fall können Sie ein Zeichenfolgenliteral ändern, unabhängig davon, ob der Zeiger auf dieses Zeichenfolgenliteral als
char *
oder deklariert istconst char *
.Der Unterschied besteht jedoch darin, dass
const char *
der Compiler eine Diagnose geben muss, wenn Sie versuchen, den Zeigerwert zu ändern. Wenn der Zeiger dies ist,char *
ist dies jedoch nicht der Fall.quelle
extern ... name
und haben*name = 'X';
. Auf einem 'richtigen Betriebssystem' könnte dies fehlschlagen, aber auf eingebetteten Systemen würde ich erwarten, dass es etwas Plattform- / Compilerspezifisches tut.FALL 1:
Die obigen Sätze str zeigen auf den Literalwert "Hello", der im Binärbild des Programms fest codiert ist und im Speicher als schreibgeschützt gekennzeichnet ist. Dies bedeutet, dass jede Änderung in diesem String-Literal unzulässig ist und Segmentierungsfehler verursachen würde.
FALL 2:
Fall 3:
quelle
Das erste können Sie tatsächlich ändern, wenn Sie möchten, das zweite können Sie nicht. Informieren Sie sich über die
const
Richtigkeit (es gibt einige nette Anleitungen zum Unterschied). Es gibt auchchar const * name
Stellen, an denen Sie es nicht neu festlegen können.quelle
Die Frage ist, was der Unterschied zwischen ist
was auf ein konstantes String-Literal zeigt, und
Dh gegeben
und
Es gibt keinen großen Unterschied zwischen der 2 und beide können als richtig angesehen werden. Durch die lange Tradition von C - Code haben die Stringliterale eine Art hatten
char[]
, nichtconst char[]
, und es gibt viele älteren Code, der ebenfalls akzeptierenchar *
stattconst char *
, auch wenn sie die Argumente nicht ändern.Der Hauptunterschied der 2 im Allgemeinen besteht darin, dass
*cname
odercname[n]
wird zu l-Werten des Typs ausgewertetconst char
, wohingegen*name
odername[n]
zu l-Werten des Typs ausgewertet wirdchar
, die modifizierbare l-Werte sind . Ein konformer Compiler muss eine Diagnosemeldung erstellen, wenn das Ziel der Zuweisung kein veränderbarer Wert ist . Bei der Zuordnung zu lWerten des Typs muss keine Warnung ausgegeben werdenchar
:Der Compiler ist nicht erforderlich , die Zusammenstellung in jedem Fall zu stoppen; es reicht aus, dass es eine Warnung für die Zuordnung zu erzeugt
cname[0]
. Das resultierende Programm ist kein korrektes Programm. Das Verhalten des Konstrukts ist undefiniert . Es kann abstürzen oder noch schlimmer, es kann nicht abstürzen und das String-Literal im Speicher ändern.quelle
Eigentlich
char* name
ist es kein Zeiger auf eine Konstante, sondern ein Zeiger auf eine Variable. Sie könnten über diese andere Frage sprechen.Was ist der Unterschied zwischen char * const und const char *?
quelle