БлогNot. Указатель на константу и константный указатель

Указатель на константу и константный указатель

Одна из частых проблем новичков при работе со строками Си (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 [3238 просмотров]


теги: c++ программирование ошибка

К этой статье пока нет комментариев, Ваш будет первым