Kiedy piszesz „ciąg” w swoim kodzie źródłowym, jest on zapisywany bezpośrednio w pliku wykonywalnym, ponieważ ta wartość musi być znana w czasie kompilacji (dostępne są narzędzia do rozdzielania oprogramowania i znajdowania w nim wszystkich zwykłych ciągów tekstowych). Kiedy piszesz char *a = "This is a string"
, lokalizacja „To jest ciąg znaków” znajduje się w pliku wykonywalnym, a lokalizacja a
wskazuje na plik wykonywalny. Dane w obrazie wykonywalnym są tylko do odczytu.
To, co musisz zrobić (jak wskazywały inne odpowiedzi), to utworzyć tę pamięć w lokalizacji, która nie jest tylko do odczytu - na stercie lub w ramce stosu. Jeśli deklarujesz tablicę lokalną, na stosie jest tworzona przestrzeń dla każdego elementu tej tablicy, a literał ciągu (który jest przechowywany w pliku wykonywalnym) jest kopiowany do tego miejsca na stosie.
char a[] = "This is a string";
można również skopiować te dane ręcznie, przydzielając część pamięci na stercie, a następnie używając polecenia strcpy()
do skopiowania literału ciągu do tej przestrzeni.
char *a = malloc(256);
strcpy(a, "This is a string");
Za każdym razem, gdy przydzielasz miejsce za pomocą malloc()
pamiętaj, aby zadzwonić, free()
gdy skończysz z nim (czytaj: wyciek pamięci).
Zasadniczo musisz śledzić, gdzie są twoje dane. Za każdym razem, gdy napiszesz ciąg w swoim źródle, ten ciąg jest tylko do odczytu (w przeciwnym razie potencjalnie zmieniłbyś zachowanie pliku wykonywalnego - wyobraź sobie, że napisałeś, char *a = "hello";
a następnie zmieniłeś a[0]
na 'c'
. Potem napisał gdzieś indziej printf("hello");
. Gdybyś mógł zmienić pierwszy znak "hello"
, a Twój kompilator zapisał go tylko raz (powinien), a następnie printf("hello");
wyświetli cello
!)
Nie, nie możesz go modyfikować, ponieważ ciąg może być przechowywany w pamięci tylko do odczytu. Jeśli chcesz go zmodyfikować, możesz zamiast tego użyć tablicy np
char a[] = "This is a string";
Lub alternatywnie możesz przydzielić pamięć za pomocą malloc, np
char *a = malloc(100); strcpy(a, "This is a string"); free(a); // deallocate memory once you've done
źródło
Wielu ludzi jest zdezorientowanych różnicą między char * i char [] w połączeniu z literałami łańcuchowymi w C. Kiedy piszesz:
char *foo = "hello world";
... faktycznie wskazujesz foo na stały blok pamięci (w rzeczywistości to, co kompilator robi z „hello world” w tym przypadku, zależy od implementacji).
Zamiast tego użycie znaku [] mówi kompilatorowi, że chcesz utworzyć tablicę i wypełnić ją zawartością, „witaj świecie”. foo jest wskaźnikiem do pierwszego indeksu tablicy char. Oba są wskaźnikami do znaków, ale tylko znak [] będzie wskazywał lokalnie przydzielony i modyfikowalny blok pamięci.
źródło
Pamięć dla a & b nie jest przydzielana przez Ciebie. Kompilator może wybrać lokalizację pamięci tylko do odczytu do przechowywania znaków. Więc jeśli spróbujesz to zmienić, może to spowodować błąd seg. Proponuję więc samodzielnie stworzyć tablicę znaków. Coś jak:
char a[10]; strcpy(a, "Hello");
źródło
Wygląda na to, że udzielono odpowiedzi na twoje pytanie, ale teraz możesz się zastanawiać, dlaczego char * a = "String" jest przechowywany w pamięci tylko do odczytu. Cóż, w rzeczywistości jest niezdefiniowany przez standard c99, ale większość kompilatorów wybiera to w ten sposób w przypadku takich instancji, jak:
printf("Hello, World\n");
standard c99 (pdf) [strona 130, rozdział 6.7.8]:
Deklaracja:
char s[] = "abc", t[3] = "abc";
definiuje "zwykłe" obiekty tablicy znaków s i t, których elementy są inicjowane za pomocą literałów ciągu znaków. Ta deklaracja jest identyczna z char
s[] = { 'a', 'b', 'c', '\0' }, t[] = { 'a', 'b', 'c' };
Zawartość tablic można modyfikować. Z drugiej strony deklaracja
char *p = "abc";
definiuje p z typem „wskaźnik do znaku” i inicjuje go tak, aby wskazywał na obiekt typu „tablica znaków” o długości 4, którego elementy są inicjowane literałem ciągu znaków. Jeśli zostanie podjęta próba użycia p do zmodyfikowania zawartości tablicy, zachowanie jest niezdefiniowane.
źródło
Możesz również użyć
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).
Na przykład:
char *a = strdup("stack overflow");
źródło
strdup
. Nie jestem jednak pewien, kiedy chciałbym go użyć.var = malloc(strlen(str) + 1); strcpy(var, str);
, prawdopodobnie powinieneśstrdup
zamiast tego użyć .Wszystkie są dobrymi odpowiedziami wyjaśniającymi, dlaczego nie można modyfikować literałów łańcuchowych, ponieważ są one umieszczone w pamięci tylko do odczytu. Jednakże, gdy dochodzi do sytuacji, jest na to sposób. Sprawdź ten przykład:
#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; }
Napisałem to jako część moich nieco głębszych przemyśleń na temat stałej poprawności , które mogą Cię zainteresować (mam nadzieję :)).
Mam nadzieję, że to pomoże. Powodzenia!
źródło
Musisz skopiować ciąg do innego, nie tylko do odczytu bufora pamięci i tam go zmodyfikować. Użyj strncpy () do skopiowania ciągu, strlen () do wykrycia długości łańcucha, malloc () i free () do dynamicznego przydzielenia buforu dla nowego ciągu.
Na przykład (C ++ jak pseudokod):
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;
źródło
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);
źródło