Wenn Sie eine "Zeichenfolge" in Ihren Quellcode schreiben, wird diese direkt in die ausführbare Datei geschrieben, da dieser Wert beim Kompilieren bekannt sein muss (es stehen Tools zur Verfügung, mit denen Sie Software auseinander ziehen und alle darin enthaltenen Nur-Text-Zeichenfolgen finden können). Wenn Sie schreiben char *a = "This is a string"
, befindet sich der Speicherort von "Dies ist eine Zeichenfolge" in der ausführbaren Datei, und der Speicherort, auf den a
verweist, befindet sich in der ausführbaren Datei. Die Daten im ausführbaren Image sind schreibgeschützt.
Was Sie tun müssen (wie die anderen Antworten gezeigt haben), ist, diesen Speicher an einem Ort zu erstellen, der nicht schreibgeschützt ist - auf dem Heap oder im Stapelrahmen. Wenn Sie ein lokales Array deklarieren, wird für jedes Element dieses Arrays Speicherplatz auf dem Stapel erstellt, und das Zeichenfolgenliteral (das in der ausführbaren Datei gespeichert ist) wird in diesen Speicherplatz im Stapel kopiert.
char a[] = "This is a string";
Sie können diese Daten auch manuell kopieren, indem Sie Speicher auf dem Heap zuweisen und dann strcpy()
ein Zeichenfolgenliteral in diesen Bereich kopieren.
char *a = malloc(256);
strcpy(a, "This is a string");
Wenn Sie Speicherplatz zuweisen, malloc()
denken Sie daran, den Anruf zu tätigen, free()
wenn Sie damit fertig sind (lesen Sie: Speicherverlust).
Grundsätzlich müssen Sie nachverfolgen, wo sich Ihre Daten befinden. Jedes Mal , wenn Sie eine Zeichenfolge in Ihrer Quelle zu schreiben, dass Zeichenfolge nur gelesen wird (sonst würden Sie möglicherweise das Verhalten der ausführbaren Datei zu ändern werden - sich vorstellen , wenn Sie geschrieben char *a = "hello";
und dann geändert , a[0]
um 'c'
dann woanders geschrieben. printf("hello");
Wenn Sie durften das erste ändern. Zeichen von "hello"
, und Ihr Compiler hat es nur einmal gespeichert (es sollte), dann printf("hello");
würde ausgegeben cello
!)
Nein, Sie können es nicht ändern, da die Zeichenfolge im Nur-Lese-Speicher gespeichert werden kann. Wenn Sie es ändern möchten, können Sie stattdessen ein Array verwenden, z
char a[] = "This is a string";
Alternativ können Sie Speicher mit malloc zuweisen, z
char *a = malloc(100); strcpy(a, "This is a string"); free(a); // deallocate memory once you've done
quelle
Viele Leute sind verwirrt über den Unterschied zwischen char * und char [] in Verbindung mit String-Literalen in C. Wenn Sie schreiben:
char *foo = "hello world";
... Sie zeigen foo tatsächlich auf einen konstanten Speicherblock (tatsächlich ist das, was der Compiler in diesem Fall mit "Hallo Welt" macht, implementierungsabhängig.)
Wenn Sie stattdessen char [] verwenden, wird dem Compiler mitgeteilt, dass Sie ein Array erstellen und mit dem Inhalt "Hallo Welt" füllen möchten. foo ist der a-Zeiger auf den ersten Index des char-Arrays. Beide sind Zeichenzeiger, aber nur char [] zeigt auf einen lokal zugewiesenen und veränderlichen Speicherblock.
quelle
Der Speicher für a & b wird von Ihnen nicht zugewiesen. Dem Compiler steht es frei, einen Nur-Lese-Speicherort zum Speichern der Zeichen auszuwählen. Wenn Sie also versuchen, dies zu ändern, kann dies zu einem Seg-Fehler führen. Ich empfehle Ihnen daher, selbst ein Zeichenarray zu erstellen. Etwas wie:
char a[10]; strcpy(a, "Hello");
quelle
Es scheint, als ob Ihre Frage beantwortet wurde, aber jetzt fragen Sie sich vielleicht, warum char * a = "String" im Nur-Lese-Speicher gespeichert ist. Nun, es wird vom c99-Standard tatsächlich nicht definiert, aber die meisten Compiler wählen es auf diese Weise für Instanzen wie:
printf("Hello, World\n");
c99-Standard (pdf) [Seite 130, Abschnitt 6.7.8]:
Die Erklärung:
char s[] = "abc", t[3] = "abc";
definiert "einfache" char-Array-Objekte s und t, deren Elemente mit Zeichenfolgenliteralen initialisiert werden. Diese Erklärung ist identisch mit char
s[] = { 'a', 'b', 'c', '\0' }, t[] = { 'a', 'b', 'c' };
Der Inhalt der Arrays kann geändert werden. Auf der anderen Seite die Erklärung
char *p = "abc";
definiert p mit dem Typ "Zeiger auf Zeichen" und initialisiert es so, dass es auf ein Objekt mit dem Typ "Array von Zeichen" mit der Länge 4 zeigt, dessen Elemente mit einem Zeichenfolgenliteral initialisiert werden. Wenn versucht wird, mit p den Inhalt des Arrays zu ändern, ist das Verhalten undefiniert.
quelle
Sie könnten auch verwenden
strdup
:The strdup() function returns a pointer to a new string which is a duplicate of the string s. Memory for the new string is obtained with malloc(3), and can be freed with free(3).
Für Sie Beispiel:
char *a = strdup("stack overflow");
quelle
strdup
. Ich bin mir nicht sicher, wann ich es verwenden möchte.var = malloc(strlen(str) + 1); strcpy(var, str);
, sollten Sie wahrscheinlichstrdup
stattdessen verwenden.Alle sind gute Antworten, die erklären, warum Sie Zeichenfolgenliterale nicht ändern können, weil sie im Nur-Lese-Speicher abgelegt sind. Wenn es jedoch darauf ankommt, gibt es eine Möglichkeit, dies zu tun. Schauen Sie sich dieses Beispiel an:
#include <sys/mman.h> #include <unistd.h> #include <stddef.h> #include <string.h> #include <stdlib.h> #include <stdio.h> int take_me_back_to_DOS_times(const void *ptr, size_t len); int main() { const *data = "Bender is always sober."; printf("Before: %s\n", data); if (take_me_back_to_DOS_times(data, sizeof(data)) != 0) perror("Time machine appears to be broken!"); memcpy((char *)data + 17, "drunk!", 6); printf("After: %s\n", data); return 0; } int take_me_back_to_DOS_times(const void *ptr, size_t len) { int pagesize; unsigned long long pg_off; void *page; pagesize = sysconf(_SC_PAGE_SIZE); if (pagesize < 0) return -1; pg_off = (unsigned long long)ptr % (unsigned long long)pagesize; page = ((char *)ptr - pg_off); if (mprotect(page, len + pg_off, PROT_READ | PROT_WRITE | PROT_EXEC) == -1) return -1; return 0; }
Ich habe dies als Teil meiner etwas tieferen Gedanken zur Konstanzkorrektheit geschrieben , die Sie vielleicht interessant finden (ich hoffe :)).
Ich hoffe es hilft. Viel Glück!
quelle
Sie müssen die Zeichenfolge in einen anderen, nicht schreibgeschützten Speicherpuffer kopieren und dort ändern. Verwenden Sie strncpy () zum Kopieren der Zeichenfolge, strlen () zum Erkennen der Zeichenfolgenlänge, malloc () und free () zum dynamischen Zuweisen eines Puffers für die neue Zeichenfolge.
Zum Beispiel (C ++ wie Pseudocode):
int stringLength = strlen( sourceString ); char* newBuffer = malloc( stringLength + 1 ); // you should check if newBuffer is 0 here to test for memory allocaton failure - omitted strncpy( newBuffer, sourceString, stringLength ); newBuffer[stringLength] = 0; // you can now modify the contents of newBuffer freely free( newBuffer ); newBuffer = 0;
quelle
char *a = "stack overflow"; char *b = "new string, it's real"; int d = strlen(a); b = malloc(d * sizeof(char)); b = strcpy(b,a); printf("%s %s\n", a, b);
quelle