Подтвердить что ты не робот

Const и указатели в C

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

Например:

int a = 3;
const int* ptr = &a;
*ptr = 5;

не будет компилироваться. Но почему

*(ptr + 2) = 5;

тоже не компилируются? Я не изменяю то, на что указывает указатель.
Итак, мы должны сказать, что использование константы с указателем таким образом не только не модифицирует то, на что указывает указатель (путем разыменования указателя), но также что-нибудь еще, к которому мы получаем адрес, указатель?

Я знаю, что в примере я пытаюсь получить доступ к не выделенной памяти, но это только ради обсуждения.

4b9b3361

Ответ 1

ptr +2 просто имеет тот же тип, что и ptr, а именно - указатель на объект const.

Арифметика указателя предполагает, что объект, на который указывает, представляет собой массив всех одинаковых базовых типов. Этот тип включает квалификацию const.

Ответ 2

Немодифицируемость, введенная const, зависит от того, где написано const.

Если вы пишете

const int * ptr = &a;

(или int const * ptr = &a;), const относится к указателю, поэтому использование указателя для записи в пункт назначения запрещено.

(OTOH, если вы писали

int * const ptr = &a;

вы не можете изменить ptr.)

В вашем случае все, что связано с записью в пункт назначения, запрещено.

Это включает в себя *ptr и ptr[0] (которые эквивалентны), но также и все, что связано с изменением адреса назначения, например *(ptr + 2) или ptr[2].

Ответ 3

Хотя другие ответы объясняют технические вопросы, почему это не работает, я хотел бы предложить более общую причину: это единственное, что имеет смысл.

Проблема заключается в том, что для компилятора нет общего способа решить, является ли p + something таким же, как p, или нет, потому что something может быть сколь угодно сложным. Правило типа "Значения, на которые указывают p и p + 0, не подлежат модификации, но другие значения могут быть изменены" нельзя проверить во время компиляции: представьте, если бы вы написали:

*(p + very complex expression) = ...

должен ли ваш компилятор выяснить, равен ли very complex expression нулю? Что насчет

int s;
scanf("%d", &s);
*(p + s) = ...

Что должен делать компилятор в этом случае?

Единственный разумный выбор здесь заключался в том, чтобы сделать любую ценность доступной через p немодифицируемым.

Ответ 4

Так как указатель также можно использовать в качестве массива (подумайте о argv), компилятор ограничивает каждый доступ, в котором задействован указатель. Таким образом, весь массив доступен только для чтения.

Ответ 5

Подумайте о типе выражений.

const int* ptr = &a;

Тип ptr - const int*.

Таким образом, тип *ptr равен const int. Не поддается изменению.

Тип (ptr + 2) все еще const int*, поэтому тип *(ptr + 2) равен const int, который снова не модифицируется.