О указателях символов в C - PullRequest
4 голосов
/ 15 апреля 2009

Рассмотрим это определение:

char *pmessage = "now is the time";

На мой взгляд, pmessage будет указывать на непрерывную область в памяти, содержащую эти символы и '\0' в конце. Таким образом, из этого я могу использовать арифметику указателей для доступа к отдельному символу в этой строке, пока я нахожусь в пределах этой области.

Так почему же они говорят (K & R), что изменение отдельного персонажа не определено?
Более того, почему, когда я запускаю следующий код, я получаю «Ошибка сегментации»?

*(pmessage + 1) = 'K';

Ответы [ 7 ]

17 голосов
/ 15 апреля 2009

Строковые литералы в C не могут быть изменены. Строковый литерал - это строка, определенная в исходном коде вашей программы. Компиляторы часто хранят строковые литералы в доступной только для чтения части скомпилированного двоичного файла, поэтому ваш указатель pmessage действительно находится в этой области, которую вы не можете изменить. Строки в буферах, которые существуют в модифицируемой памяти, могут быть изменены с использованием приведенного выше синтаксиса.

Попробуйте что-то вроде этого.

const char* pmessage = "now is the time";

// Create a new buffer that is on the stack and copy the literal into it.
char buffer[64];
strcpy(buffer, pmessage);

// We can now modify this buffer
buffer[1] = 'K';

Если вам нужна строка, которую вы можете изменить, вы можете избежать использования строкового литерала со следующим синтаксисом.

char pmessage[] = "now is the time";

Этот метод напрямую создает строку в виде массива в стеке и может быть изменен на месте.

9 голосов
/ 15 апреля 2009

Строка является константой и не может быть изменена. Если вы хотите изменить его, вы можете сделать:

char pmessage[] = "now is the time";

Это инициализирует массив символов (включая \ 0) вместо создания указателя на строковую константу.

1 голос
/ 16 апреля 2009

Литеральное значение pmessage входит в код, и в большинстве случаев они помещаются в память кода. Который только для чтения

1 голос
/ 15 апреля 2009

Литерал "string" определен в постоянной памяти, поэтому его не следует изменять.

1 голос
/ 15 апреля 2009

Вы можете использовать арифметику указателя для чтения строкового литерала, но не для записи в него. Стандарт C запрещает изменять строковые литералы.

0 голосов
/ 16 апреля 2009

Если вы определите литерал вида:

char* message = "hello world";

компилятор будет обрабатывать символы как константы и вполне может поместить их в постоянную память.

Поэтому рекомендуется использовать ключевое слово const, чтобы любая попытка изменить литерал помешала компиляции программы:

const char* message = "hello world";

Я предполагаю, что причина const для литерала не применяется, поскольку часть языка предназначена только для обратной совместимости с предстандартными версиями C, где ключевое слово const не существует. Кто-нибудь знает лучше?

0 голосов
/ 15 апреля 2009

Когда вы пишете: char * pmessage = "сейчас время";

Компилятор обрабатывает это так, как если бы вы написали:

 const char internalstring[] = "now is the time";
 char *pmessage = internalstring;

Причина, по которой вы не можете изменить строку, заключается в том, что если вы напишите:

 char *pmessage1 = "now is the time";
 char *pmessage2 = "now is the time";

Компилятор будет обращаться с ним так, как будто вы написали:

 const char internalstring[] = "now is the time";
 char *pmessage1 = internalstring;
 char *pmessage2 = internalstring;

Итак, если бы вы поменяли один, вы бы поменяли оба.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...