Проблемы с указателями: присвоение 'int *' из несовместимого типа 'int - PullRequest
0 голосов
/ 08 февраля 2020

Я читал книгу "Прыжок в C ++" и сейчас читаю указатели. Это упражнение из книги:

"Каковы окончательные значения в x, p_int и p_p_int в следующем коде:

int x = 0;
int *p_int = & x;
int **p_p_int = & p_int;
*p_int = 12;
**p_p_int = 25;
p_int = 12;
*p_p_int = 3;
p_p_int = 27;

И я получаю ошибку:

"Назначение int * из несовместимого типа int"

В последних трех строках.

Я не знаю, почему это происходит, и был бы признателен за любую информацию.

Кроме того, предполагая, что этот код каким-то образом работает, я думаю, что, поскольку все указатели просто указывают на одну память (**p_p_int -> *p_int -> x), последнее присвоение значения будет определять конечное значение ячейки памяти. Однако в книге ответ таков:

x = 25, p_p_int = 27, p_int = 3

Это правильно? Если да, может кто-нибудь объяснить мне это?

Ответы [ 4 ]

3 голосов
/ 08 февраля 2020

Эта часть:

p_int = 12;
*p_p_int = 3;
p_p_int = 27;

Нет способа компилирования с любым подтверждающим компилятором C ++. Это просто плохо сформировано. Даже если вы использовали приведение, чтобы заставить его работать, вы бы вызвали неопределенное поведение. Попробуйте другую книгу .

2 голосов
/ 08 февраля 2020

Как вы можете видеть, p_int имеет как stati c тип int *, а в последних трех строках вы делаете что-то вроде

p_int = 12;

, где 12 - это int, и поэтому не может быть назначен указателю (то же самое относится и к другим 2 строкам)

Однако x p_int p_p_int имеют разные значения, поскольку x содержит целочисленное значение, p_int адрес x и p_p_int адрес p_int.

Также имейте в виду, что это код "" "" скомпилируемый "" "" C, не C ++, но вы также получит 3 предупреждения на C компиляторе, сообщающем, что вы назначаете указателю несовместимый тип

1 голос
/ 08 февраля 2020
int *p_int = & x;
int **p_p_int = & p_int;

Все эти строки указывают на одну и ту же память в местоположении (переменная x).

0 голосов
/ 08 февраля 2020

В вашем фрагменте кода есть три переменные. Вот таблица, показывающая значение, которое каждая переменная будет иметь после выполнения каждой из строк (если код должен был на самом деле компилироваться).

                         |  x | p_int | p_p_int |
-------------------------+----+-------+---------|
int x = 0;               |  0 | undef |  undef  |
int *p_int = & x;        |  0 |   &x  |  undef  |
int **p_p_int = & p_int; |  0 |   &x  |  &p_int | <-- begin: all variables lead to x
-------------------------+----+-------+---------|
*p_int = 12;             | 12 |   &x  |  &p_int |
**p_p_int = 25;          | 25 |   &x  |  &p_int |
-------------------------+----+-------+---------| <-- end: all variables lead to x
p_int = 12;              | 25 |   12  |  &p_int | <-- p_int now points to garbage
*p_p_int = 3;            | 25 |    3  |  &p_int |
-------------------------+----+-------+---------|
p_p_int = 27;            | 25 |    3  |    27   | <-- p_p_int now points to garbage
------------------------------------------------/

Я использовал undef, чтобы указать, что переменная еще не существует (т.е. не определено); &x и &p_int для представления адресов этих переменных (поскольку точное значение неизвестно).

Это упражнение на мысль, чтобы понять, понимаете ли вы различные уровни косвенности, если понимаете, что *p_int и p_int относятся к разным значениям в памяти. Как вы заметили, он не компилируется. Назначение литерального числового значения c для указателя почти наверняка является ошибкой, бесполезной вне такого мысленного эксперимента. В реальном коде строка типа p_int = 12, вероятно, является опечаткой (вероятно, она должна быть *p_int = 12), и компилятор предупредит вас об этом.

К счастью, автор, кажется, знает о нецелесообразности пытаясь получить доступ к памяти по адресам 12, 3 и 27, поскольку ни p_int, ни p_p_int не были отменены при сохранении поддельного адреса. Тем не менее, было бы неплохо, если бы автор признал эти ограничения или еще лучше разработал упражнение, в котором такой отказ от ответственности не требуется. (Надеюсь, это был отдельный отрывок. В отличие от некоторых людей, я бы не стал осуждать целую книгу на основе одного упражнения. Книги длинные, С ++ сложный, и ошибки случаются . )

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...