Почему я могу изменить значение переменной const char *?

Почему следующий код на C работает?

const char* str = NULL;
str = "test";
str = "test2";

Поскольку str является указателем на постоянный символ, почему нам разрешено назначать ему разные строковые литералы? Кроме того, как мы можем защитить str от изменения? Похоже, это может быть проблемой, если, например, мы позже назначили str более длинной строке, которая в конечном итоге записала поверх другой части памяти.

Я должен добавить, что в своем тесте я распечатал адрес памяти str до и после каждого из моих назначений, и он никогда не менялся. Итак, хотя str является указателем на const char, память фактически модифицируется. Я задавался вопросом, может быть, это устаревшая проблема с C?


person Chris    schedule 13.01.2009    source источник
comment
Связанный: stackoverflow.com/questions/162480/const-in-c   -  person Ates Goral    schedule 13.01.2009
comment
Я предполагаю, что вы на самом деле распечатываете адрес переменной str, которая не меняется, ее значение меняется.   -  person Greg Rogers    schedule 13.01.2009


Ответы (6)


Вы меняете указатель, который не является константой (то, на что он указывает, является константой).

Если вы хотите, чтобы сам указатель был константным, объявление выглядело бы так:

char * const str = "something";

or

char const * const str = "something";  // a const pointer to const char
const char * const str = "something";  //    same thing

Константные указатели на неконстантные данные обычно менее полезны, чем указатели на константы.

person Michael Burr    schedule 13.01.2009
comment
Однако я сделал тест. Я назначил str строке и распечатал строку и ее адрес в памяти. Затем я назначил str другой строке и снова распечатал строку и ее адрес в памяти. Строковый литерал изменился, а адрес - нет. - person Chris; 13.01.2009
comment
Вы распечатали адрес указателя или адрес, на который он указывает? - person mipadi; 13.01.2009
comment
Всем спасибо. Да, я распечатывал адрес указателя, а не данные! В этой проблеме меня сбило с толку то, как C работает со строковыми литералами. Вы можете присвоить строковый литерал char *, но вы не можете, например, таким же образом присвоить целое число int *. - person Chris; 13.01.2009
comment
@Chris: это потому, что строковый литерал на самом деле является char [], который может быть неявно преобразован в указатель на его первый элемент - person Christoph; 14.01.2009
comment
Хорошо, это имеет смысл. Спасибо! - person Chris; 14.01.2009

Кроме того, как мы можем защитить str от изменения?

char * const str1; // str1 cannot be modified, but the character pointed to can
const char * str2; // str1 can be modified, but the character pointed to cannot
const char * const str3 // neither str3 nor the character pointed to can be modified.

Самый простой способ прочитать это - начать с имени переменной и читать налево:

  • str1 - это константа и указатель на символ.
  • str2 - это указатель на char acter const ant.
  • str3 - это const ant указатель на char acter const ant.

ПРИМЕЧАНИЕ: чтение справа налево не работает в общем случае, но для простых объявлений это простой способ сделать это. Я нашел java-апплет на основе кода из "Языка программирования C" который может расшифровать объявления с полным объяснением того, как это сделать.

person Matthew Crumley    schedule 13.01.2009
comment
Кто-то мог бы отбросить константу, если бы они действительно были определены, но если компилятор поместит символы на страницу, доступную только для чтения, то их изменение вызовет ошибку во время выполнения. - person marklam; 05.08.2009
comment
Технически компилятор и компоновщик вместе. Переключатели зависят от инструментов, которые вы используете. - person marklam; 05.08.2009

В связи с этим обязательно взгляните на "указатель const по сравнению с указателем на const ". Это помогает с тем, что некоторые люди называют константной корректностью. Я храню его в своих закладках, чтобы время от времени обращаться к нему.

person Community    schedule 13.01.2009
comment
Эта ссылка переместилась сюда: voidnish. wordpress.com/2004/08/01/ - person Wilson F; 26.02.2016

То, что вы ищете, может быть синтаксисом ...

const char* const str = NULL;
str = "test";
str = "test2";

Обратите внимание на «const» после символа *, что приводит к ошибке компилятора при попытке компиляции / сборки.

person Rob Segal    schedule 13.01.2009

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

person Joel Coehoorn    schedule 13.01.2009
comment
строковые литералы, размещенные в стеке? э ... Они размещены в разделе данных. - person Serge Wautier; 13.01.2009

Кроме того, объявление переменной как константы означает, что переменная доступна только для чтения; это не означает, что значение постоянно!

person Community    schedule 13.01.2009