Указатель на константу и константный указатель
Одна из частых проблем новичков при работе со строками Си (char *
) обычно формулируется примерно следующим образом:
Почему так
char* kk = "345345"; kk[1] = 0x00;компилятор ругается, а так
char* kk = new char[10]; kk[0] = 0xff;нет?
На самом деле, проблема уже описана вот здесь, но сделаю ещё одну маленькую заметку.
После присваивания
char* kk = "345345";
в kk
записан некий адрес, по которому хранится строка "345345"
. Компилятор обычно делает указатель константным, а строку размещает в памяти "read only" (конечно, теоретически туда можно писать, просто операционная система знает, что это неправильно и пресекает попытки записи). Но почему?
Так сделано, в основном, для оптимизаций и упрощения, а также в целях безопасности. Пусть в Вашей программе есть ещё десять мест, где встречается константа "345345"
. Компилятор не будет создавать 11 копий, а будет использовать один и тот же адрес. А теперь представьте, что вышеуказанное изменение разрешено...
Старые компиляторы (как правило, компилирующие C++ со многими соглашениями из классического Си) этого не делали и часто наблюдались интересные спецэффекты, когда константы изменяли свое значение.
Также нужно различать указатель на константу и константный указатель.
1) Указатель на константу: нельзя менять содержимое объекта, на который указывает указатель, но можно менять содержимое самого указателя (указатель — это переменная, содержащая адрес другой переменной).
/*const */ char * c = "123"; // Указатель на объект, который нельзя менять c[0] = '0'; // Нельзя, т. к. меняется содержимое указываемого объекта c = "456"; // Можно, т. к. меняется значение самого указателя
С закомментированным словом const
возникнет коварная ошибка времени исполнения программы, а с
раскомментированным нормальный компилятор не даст это откомпилировать.
2) Константный указатель: можно менять содержимое объекта, но нельзя менять значение самого указателя. Проще говоря, указатель нельзя переназначить на другой объект, но сами данные, на которые он указывает, менять можно.
char * const c = "123"; c[0] = '0'; // можно c = "345"; // нельзя, и не откомпилируется
Во втором же коде с new
всё понятно, мы выделяем новую память в "куче"
и можем делать с ней, что захотим.
Мнемоническое правило как различить const char * и char * const
Прочитайте определение указателя справа налево, читая слово const
как "константный" или "константа", а символ "*
" как "указатель". Например:
char * const p; //константный указатель на char (неизменяемый) char const * p; //указатель на константый char (указатель на константу) const char * p; //то же самое const char * const p; //константный указатель на константу
16.05.2018, 12:17 [3342 просмотра]