Ist es möglich, eine Zeichenkette in C zu ändern?

Ich habe ein paar Stunden mit allen möglichen C-Tutorials und Büchern zu pointersn gekämpft, aber was ich wirklich wissen möchte, ist, ob es möglich ist, einen Char-pointers zu ändern, sobald er erstellt wurde.

Das habe ich ausprobiert:

char *a = "This is a string"; char *b = "new string"; a[2] = b[1]; // Causes a segment fault *b[2] = b[1]; // This almost seems like it would work but the compiler throws an error. 

Gibt es eine Möglichkeit, die Werte in den Strings anstelle der pointersadressen zu ändern?

Vielen Dank

BEARBEITEN:

Vielen Dank für Ihre Antworten. Es macht jetzt mehr Sinn. Es macht besonders Sinn, warum es manchmal gut funktionierte und manchmal nicht funktionierte. Weil ich manchmal einen Char-pointers und manchmal ein Char-Array übergeben würde (das Char-Array hat gut funktioniert).

Wenn Sie einen “String” in Ihren Quellcode schreiben, wird dieser direkt in die ausführbare Datei geschrieben, da dieser Wert zum Zeitpunkt der Kompilierung bekannt sein muss (es gibt Tools, um Software auseinander zu ziehen und alle Klartextzeichenfolgen zu finden). Wenn Sie char *a = "This is a string" schreiben, befindet sich der Speicherort von “Dies ist ein String” in der ausführbaren Datei und der Speicherort, auf den a zeigt, 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 darauf hingewiesen haben), ist das Erstellen dieses Speichers an einem Ort, der nicht nur gelesen werden kann – 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 den Stapel im Stapel kopiert.

 char a[] = "This is a string"; 

Sie können diese Daten auch manuell kopieren, indem Sie Speicher auf dem Heap strcpy() und anschließend strcpy() um ein Zeichenfolgenliteral in diesen Speicherbereich zu kopieren.

 char *a = malloc(256); strcpy(a, "This is a string"); 

Wenn Sie Speicherplatz mit malloc() zuweisen, vergessen Sie nicht, free() aufzurufen, wenn Sie damit fertig sind (lesen Sie: Speicherleck).

Grundsätzlich müssen Sie verfolgen, wo sich Ihre Daten befinden. Wenn Sie eine Zeichenfolge in Ihre Quelle schreiben, ist diese Zeichenfolge schreibgeschützt (andernfalls würden Sie möglicherweise das Verhalten der ausführbaren Datei ändern – stellen Sie sich vor, Sie hätten char *a = "hello"; und dann a[0] in 'c' geändert 'c' . Dann woanders schrieb printf("hello"); Wenn Sie das erste Zeichen von "hello" ändern konnten, und Ihr Compiler nur einmal gespeichert (es sollte), dann printf("hello"); würde ausgeben 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

 char a[] = "This is a string"; 

Oder alternativ könnten Sie Speicher mit malloc z

 char *a = malloc(100); strcpy(a, "This is a string"); free(a); // deallocate memory once you've done 

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 auf einen konstanten Speicherblock (was der Compiler in diesem Fall mit “hallo world” macht, ist implementationsabhängig.)

Wenn Sie stattdessen char [] verwenden, wird der Compiler angewiesen, ein Array zu erstellen und es mit dem Inhalt “Hallo Welt” zu füllen. foo ist der a-pointers auf den ersten Index des char-Arrays. Sie sind beide Zeichenzeiger, aber nur char [] zeigt auf einen lokal zugewiesenen und veränderbaren Speicherblock.

Der Speicher für a & b wird von Ihnen nicht vergeben. Der Compiler kann einen schreibgeschützten Speicherort zum Speichern der Zeichen frei wählen. Wenn Sie also versuchen, es zu ändern, kann dies zu einem seg-Fehler führen. Also schlage ich vor, dass Sie selbst ein Zeichen-Array erstellen. Etwas wie: char a[10]; strcpy(a, "Hello"); char a[10]; strcpy(a, "Hello");

Es scheint, als ob Ihre Frage beantwortet wurde, aber jetzt könnten Sie sich fragen, warum char * a = “String” im Nur-Lese-Speicher gespeichert ist. Nun, es ist tatsächlich nicht definiert durch den c99-Standard, 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 “plain” char-Array-Objekte s und t, deren Elemente mit Zeichenkettenliteralen initialisiert werden. Diese Deklaration ist identisch mit char

 s[] = { 'a', 'b', 'c', '\0' }, t[] = { 'a', 'b', 'c' }; 

Die Inhalte der Arrays sind modifizierbar. Auf der anderen Seite die Erklärung

 char *p = "abc"; 

definiert p mit dem Typ “pointer to char” und initialisiert es so, dass es auf ein Objekt vom Typ “array of char” mit der Länge 4 zeigt, dessen Elemente mit einem Zeichenkettenliteral initialisiert werden. Wenn versucht wird, p zu verwenden, um den Inhalt des Arrays zu ändern, ist das Verhalten nicht definiert.

Sie könnten auch 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"); 

Alles gute Antworten, die erklären, warum Sie Zeichenfolgenliterale nicht ändern können, da sie in schreibgeschütztem Speicher abgelegt werden. Aber wenn es hart auf hart kommt, gibt es einen Weg, dies zu tun. Schau dir dieses Beispiel an:

 #include  #include  #include  #include  #include  #include  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 über const-Korrektheit geschrieben , die Sie vielleicht interessant finden (ich hoffe :)).

Ich hoffe es hilft. Viel Glück!

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 Ermitteln 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; 
 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);