Zuweisen von Zeichenfolgen zu Arrays von Zeichen

78

Ich bin ein wenig überrascht von Folgendem.

Beispiel 1:

char s[100] = "abcd"; // declare and initialize - WORKS

Beispiel 2:

char s[100]; // declare
s = "hello"; // initalize - DOESN'T WORK ('lvalue required' error)

Ich frage mich, warum der zweite Ansatz nicht funktioniert. Es scheint natürlich, dass es sollte (es funktioniert mit anderen Datentypen)? Könnte mir jemand die Logik dahinter erklären?

Ree
quelle

Antworten:

64

Wenn Sie ein Array initialisieren, können Sie es mit C mit Werten füllen. Damit

char s[100] = "abcd";

ist im Grunde das gleiche wie

int s[3] = { 1, 2, 3 };

Die Zuweisung sist jedoch nicht möglich, da es sich um ein Array und nicht um einen freien Zeiger handelt. Die Bedeutung von

s = "abcd" 

ist, den Zeigerwert von to zuzuweisen abcd, saber Sie können ihn nicht ändern, sda dann nichts mehr auf das Array zeigt.
Dies kann und funktioniert, wenn ses sich um char*einen Zeiger handelt, der auf alles zeigen kann.

Wenn Sie die Zeichenfolge kopieren möchten, verwenden Sie sie einfach strcpy.

shoosh
quelle
6
Gute Antwort, außer dass Sie nie mehr einfach strcpy verwenden sollten. Verwenden Sie strncpy oder strlcpy.
dwc
3
Außerdem sollte s const char * sein, nicht char *.
Aib
1
s[0] = 'x'; s[1] = 'y'; s[2] = 'z'; s[3] = 'm';funktioniert, wenn man die Zeichenketten auch nach der Initialisierung einzeln ersetzen möchte.
RBT
@RBT, vielleicht funktioniert es auf Ihrer Plattform mit Ihren Kompilierungsflags, aber oft werden diese Zeichenfolgen im Nur-Lese-Speicher definiert. Das Schreiben würde einen Segfault oder einen Zugriffsverletzungsfehler verursachen
shoosh
Warum? Das Ausführen von char s[100]; s = "abcd";Fehlern ist absolut sinnvoll, da s effektiv als konstanter Zeiger behandelt wird. Wenn wir also versuchen, "abcd" in der zweiten Zeile zuzuweisen, versuchen wir, den Wert des Zeigers zu ändern, der nicht zulässig ist. Wenn jedoch ein const-Zeiger auf einen Speicherort zeigt, sollte der Inhalt des Speicherorts natürlich geändert werden können. Angenommen, szeigt auf Speicherplatz 1000, dann enthält s 1000 und Speicherplatz # 1000 enthält a. Ich kann s nicht ändern, um einen neuen Speicherort zu speichern, z. B. 2000, aber ich kann ein neues Zeichen, z. B. z, an einem Speicherort 1000 speichern.
RBT
52

In C gibt es keine "Zeichenfolge". In C sind Zeichenfolgen ein eindimensionales Array von char, das durch ein Nullzeichen abgeschlossen wird \0. Da Sie in C keine Arrays zuweisen können, können Sie auch keine Zeichenfolgen zuweisen. Das wörtliche "Hallo" ist syntaktischer Zucker fürconst char x[] = {'h','e','l','l','o','\0'};

Der richtige Weg wäre:

char s[100];
strncpy(s, "hello", 100);

oder noch besser:

#define STRMAX 100
char    s[STRMAX];
size_t  len;
len = strncpy(s, "hello", STRMAX);
dwc
quelle
2
Nicht der empfohlene Ansatz. Vorsicht vor den Merkwürdigkeiten von strncpy: stackoverflow.com/a/1258577/2974922
Nukleon
Ich denke, dieser Ansatz könnte leicht empfohlen werden
Volt
13

Initialisierung und Zuweisung sind zwei unterschiedliche Operationen, die hier zufällig denselben Operator ("=") verwenden.

Sparr
quelle
3
1    char s[100];
2    s = "hello";

In dem von Ihnen angegebenen Beispiel wird s tatsächlich in Zeile 1 und nicht in Zeile 2 initialisiert. Obwohl Sie ihm zu diesem Zeitpunkt keinen expliziten Wert zugewiesen haben, hat der Compiler dies getan. In Zeile 2 führen Sie eine Zuweisungsoperation aus, und Sie können ein Array von Zeichen keinem anderen Array von Zeichen wie diesem zuweisen. Sie müssen strcpy () oder eine Art Schleife verwenden, um jedes Element des Arrays zuzuweisen.

Matt Davis
quelle
Warum brauchen Sie 100 Bytes für Hallo? Ist das nicht char s[6]genug
mLstudent33
1
@ mLstudent33, es war das Beispiel des OP.
Matt Davis
2

Um Sparrs Antwort zu erweitern

Initialisierung und Zuweisung sind zwei unterschiedliche Operationen, die hier zufällig denselben Operator ("=") verwenden.

Stellen Sie sich das so vor:

Stellen Sie sich vor, es gibt zwei Funktionen: InitializeObjectund AssignObject. Wenn der Compiler sieht thing = value, sieht er sich den Kontext an und ruft einen auf, InitializeObjectwenn Sie einen neuen erstellen thing. Wenn nicht, wird stattdessen angerufen AssignObject.

Normalerweise ist dies in Ordnung InitializeObjectund AssignObjectverhält sich normalerweise genauso. Außer beim Umgang mit Char-Arrays (und einigen anderen Randfällen) verhalten sie sich in diesem Fall anders. Warum das? Nun, das ist ein ganz anderer Beitrag, der den Stapel gegen den Haufen und so weiter und so fort betrifft.

PS: Abgesehen davon hilft Ihnen das Denken auf diese Weise auch dabei, Kopierkonstruktoren und andere solche Dinge zu verstehen, wenn Sie sich jemals in C ++ wagen

Orion Edwards
quelle
0

Beachten Sie, dass Sie noch Folgendes tun können:

s[0] = 'h';
s[1] = 'e';
s[2] = 'l';
s[3] = 'l';
s[4] = 'o';
s[5] = '\0';
aib
quelle
Es ist viel schöner und einfacher, strncpy () zu verwenden, obwohl ich mir ziemlich sicher bin, dass strncpy () genau dies intern tut.
Chris Lutz
Natürlich. Aber das ist so nah wie es nur geht an 's = "Hallo";' Tatsächlich sollte dies in C implementiert worden sein, da Sie Strukturen zuweisen können.
Aib
Ich meine, Mitgliedskopien durch Zuweisung in Strukturen, aber nicht in Arrays machen keinen Sinn.
Aib
0

Ich weiß, dass dies bereits beantwortet wurde, aber ich wollte eine Antwort teilen, die ich jemandem gegeben habe, der in einer C / C ++ - Facebook-Gruppe eine sehr ähnliche Frage gestellt hat.


Arrays haben keine Zuweisungsoperatorfunktionen *. Dies bedeutet, dass Sie einem Zeichenfolgenliteral nicht einfach ein char-Array zuweisen können. Warum? Weil das Array selbst keinen Zuweisungsoperator hat. (* Es ist ein konstanter Zeiger, der nicht geändert werden kann.)

Arrays sind einfach ein Bereich des zusammenhängenden zugewiesenen Speichers, und der Name des Arrays ist tatsächlich ein Zeiger auf das erste Element des Arrays. (Zitat von https://www.quora.com/Can-we-copy-an-array-using-an-assignment-operator )

Um ein Zeichenfolgenliteral (wie "Hello world"oder "abcd") in Ihr Zeichenarray zu kopieren, müssen Sie alle Zeichenelemente des Zeichenfolgenliteral manuell in das Array kopieren.

char s[100]; Dadurch wird ein leeres Array mit der Länge 100 initialisiert.

Verwenden Sie nun, um Ihr String-Literal in dieses Array zu kopieren strcpy

strcpy(s, "abcd");Dadurch wird der Inhalt aus dem Zeichenfolgenliteral "abcd"kopiert und in das s[100]Array kopiert .

Hier ist ein großartiges Beispiel dafür, was es tut:

int i = 0; //start at 0
do {
    s[i] = ("Hello World")[i]; //assign s[i] to the string literal index i
} while(s[i++]); //continue the loop until the last char is null

Sie sollten natürlich strcpyanstelle dieses benutzerdefinierten String-Literal-Kopierers verwenden, aber es ist ein gutes Beispiel, das erklärt, wie strcpygrundlegend funktioniert.

Hoffe das hilft!

JMS Creator
quelle
-1

Sie können dies verwenden:

yylval.sval=strdup("VHDL + Volcal trance...");

Wobei yylval char * ist. strdup von macht den Job.

Jekatandilburg
quelle
strdup von <string.h> macht den Job :)
Yekatandilburg
strdup erstellt ein Duplikat und gibt den Zeiger auf das Duplikat zurück. In diesem Fall für Char-Arrays sind Sie wieder da, wo Sie ohne Arbeit begonnen haben
JoshKisb
-3

Was ich verwenden würde, ist

char *s = "abcd";
Vivek
quelle
2
Die meisten von uns würden das nicht tun, weil es undefiniertes Verhalten riskiert. Das obige ist nur sicher für const char*.
Toby Speight