#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
.