Почему следующие выражения C, включающие указатели, не выдают ошибку?

#c #pointers

#c #указатели

Вопрос:

Я просматривал материалы, касающиеся языка Си, на предстоящий семестр и наткнулся на некоторые темы, связанные с указателями и памятью. Я не писал код, но я пытаюсь понять все это. Выражения следующие (для краткости я удалил int main()):

 int x = 5;
int y;
int *p = NULL;
p = amp;x;

y = *p   2; /* y is assigned 7 */
y  = *p;     /* y is assigned 12 */
*p = y;       /* x is assigned 12 */
(*p)  ;      /* x is incremented to 13 */
 

Я не понимаю 7-го утверждения, потому что оно не согласуется с тем, как оценивается 5-е утверждение. Насколько я был обеспокоен, *p используется для доступа к значению, на которое указывает p, равному x, что равно 5. В 5-м утверждении мы устанавливаем y = *p 2, что дает значение y = 5 2 = 7. Итак, почему в 7-м утверждении *p используется как указатель на x, а не значение 5? (т.е.. почему выражение не принимает значение 5 = 12 и не выдает ошибку?).

Спасибо за любую помощь, ценю это.

Комментарии:

1. Замените все экземпляры *p на x , не 5 . IOW, y = *p 2 эквивалентно y = x 2 и *p = y эквивалентно x = y .

2. По той же причине x=y; допустимо. *p=y указывает — присваивает значение y переменной / ячейке памяти p , на которую указывает.

Ответ №1:

*p = y; устанавливает *p значение y и не устанавливает 5 в значение y по той же причине, по которой x = y; устанавливается x значение y и не устанавливается 5 в значение y .

В частности, в большинстве мест, когда есть выражение, которое ссылается на объект, например x , или *p или y , оно автоматически преобразуется в значение, хранящееся в этом объекте. Вот почему, в x = y; , y преобразуется в 12. Это преобразование происходит из-за C 2018 6.3.2.1, в котором говорится:

… значение lvalue, которое не имеет типа массива, преобразуется в значение, хранящееся в указанном объекте (и больше не является значением lvalue)…

Но в полном предложении перечислены исключения:

За исключением случаев, когда это операнд sizeof оператора, унарного amp; оператора, оператора, -- оператора или левого операнда . оператора или оператора присваивания, значение lvalue, которое не имеет типа массива, преобразуется в значение, хранящееся в указанном объекте (и больше не является значением lvalue)…

В x = y; or *p = y; x or *p является левым операндом оператора присваивания. Таким образом, они не преобразуются в значения. Каждый из них остается значением lvalue. Значение lvalue — это ссылка на объект; оно обозначает сам объект, а не его значение.

Таким x = y; образом , помещает значение y в объект , на который ссылается x , и *p = y; помещает значение y в объект , на который ссылается *p .

Ответ №2:

почему выражение не вычисляется как 5 = 12

Можно выполнить запись в память, на которую указывает указатель.

Аналогично, x = y; допустимо, потому что вы можете читать из переменной y и можете записывать x . То же самое с указателями: *p = *p 1; , например, прочитает from p , добавит единицу к этому значению и запишет результат обратно p .