Когда вы пишете «строку» в исходном коде, она записывается непосредственно в исполняемый файл, потому что это значение должно быть известно во время компиляции (существуют инструменты, позволяющие разобрать программное обеспечение и найти в них все простые текстовые строки). Когда вы пишете char *a = "This is a string"
, местоположение «Это строка» находится в исполняемом файле, а местоположение, на которое a
указывает, находится в исполняемом файле. Данные в исполняемом образе доступны только для чтения.
Что вам нужно сделать (как указывали другие ответы), так это создать эту память в месте, которое не только для чтения - в куче или в кадре стека. Если вы объявляете локальный массив, то в стеке выделяется пространство для каждого элемента этого массива, а строковый литерал (который хранится в исполняемом файле) копируется в это пространство в стеке.
char a[] = "This is a string";
вы также можете скопировать эти данные вручную, выделив некоторую память в куче, а затем используя strcpy()
для копирования строкового литерала в это пространство.
char *a = malloc(256);
strcpy(a, "This is a string");
Всякий раз, когда вы выделяете место с помощью, не malloc()
забудьте позвонить, free()
когда вы закончите с ним (читай: утечка памяти).
По сути, вы должны отслеживать, где находятся ваши данные. Всякий раз, когда вы пишете строку в своем источнике, эта строка доступна только для чтения (в противном случае вы потенциально изменили бы поведение исполняемого файла - представьте, если бы вы написали, char *a = "hello";
а затем изменили a[0]
на 'c'
. Затем написали где-то еще printf("hello");
. Если бы вам разрешили изменить первый символ "hello"
, и ваш компилятор сохранил его только один раз (должен), а затем printf("hello");
выведет cello
!)
Нет, вы не можете изменить его, так как строка может храниться в постоянной памяти. Если вы хотите изменить его, вы можете вместо этого использовать массив, например
char a[] = "This is a string";
Или, альтернативно, вы можете выделить память с помощью malloc, например
char *a = malloc(100); strcpy(a, "This is a string"); free(a); // deallocate memory once you've done
источник
Многие люди не понимают разницу между char * и char [] в сочетании со строковыми литералами в C. Когда вы пишете:
char *foo = "hello world";
... вы фактически указываете foo на постоянный блок памяти (на самом деле, то, что компилятор делает с "hello world" в этом случае, зависит от реализации.)
Использование char [] вместо этого сообщает компилятору, что вы хотите создать массив и заполнить его содержимым, «привет, мир». foo - это указатель на первый индекс массива char. Оба они являются указателями char, но только char [] будет указывать на локально выделенный и изменяемый блок памяти.
источник
Память для a и b не выделяется вами. Компилятор может выбрать доступную только для чтения область памяти для хранения символов. Поэтому, если вы попытаетесь изменить, это может привести к ошибке сегмента. Поэтому я предлагаю вам создать массив символов самостоятельно. Что-то вроде:
char a[10]; strcpy(a, "Hello");
источник
Кажется, что на ваш вопрос ответили, но теперь вы можете задаться вопросом, почему char * a = "String" хранится в постоянной памяти. Что ж, на самом деле он не определен стандартом c99, но большинство компиляторов выбирают его таким образом для таких случаев, как:
printf("Hello, World\n");
Стандарт c99 (pdf) [стр. 130, раздел 6.7.8]:
Декларация:
char s[] = "abc", t[3] = "abc";
определяет "простые" объекты массива символов s и t, элементы которых инициализируются литералами символьной строки. Это объявление идентично char
s[] = { 'a', 'b', 'c', '\0' }, t[] = { 'a', 'b', 'c' };
Содержимое массивов можно изменять. С другой стороны, декларация
char *p = "abc";
определяет p с типом «указатель на char» и инициализирует его, чтобы указать на объект с типом «массив символов» с длиной 4, элементы которого инициализируются литералом строки символов. Если попытаться использовать p для изменения содержимого массива, поведение не определено.
источник
Вы также можете использовать
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).
Например:
char *a = strdup("stack overflow");
источник
strdup
. Я не уверен, когда я захочу его использовать.var = malloc(strlen(str) + 1); strcpy(var, str);
, тогда вам, вероятно, следует использоватьstrdup
вместо.Все это хорошие ответы, объясняющие, почему вы не можете изменять строковые литералы, потому что они помещаются в постоянную память. Однако, когда дело доходит до дела, есть способ сделать это. Посмотрите этот пример:
#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; }
Я написал это как часть моих более глубоких мыслей о корректности констант , которые могут вас заинтересовать (я надеюсь :)).
Надеюсь, поможет. Удачи!
источник
Вам нужно скопировать строку в другой буфер памяти, а не только для чтения, и изменить ее там. Используйте strncpy () для копирования строки, strlen () для определения длины строки, malloc () и free () для динамического выделения буфера для новой строки.
Например (псевдокод типа C ++):
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);
источник