Недавно я имел удовольствие объяснять указатели новичку в программировании на C и наткнулся на следующую трудность. Это может показаться не проблемой, если вы уже знаете, как использовать указатели, но постарайтесь внимательно рассмотреть следующий пример:
int foo = 1;
int *bar = &foo;
printf("%p\n", (void *)&foo);
printf("%i\n", *bar);
Для абсолютного новичка результат может быть неожиданным. В строке 2 он / она только что объявил * bar как & foo, но в строке 4 оказалось, что * bar на самом деле foo, а не & foo!
Путаница, можно сказать, проистекает из двусмысленности символа *: в строке 2 он используется для объявления указателя. В строке 4 он используется как унарный оператор, который выбирает значение, на которое указывает указатель. Две разные вещи, правда?
Однако новичку это «объяснение» совершенно не помогает. Он вводит новую концепцию, указывая на небольшое несоответствие. Это не может быть правильным способом учить это.
Итак, как это объяснили Керниган и Ричи?
Унарный оператор * - это оператор косвенного обращения или разыменования; при применении к указателю он обращается к объекту, на который указывает указатель. […]
Объявление указателя ip
int *ip
задумано как мнемоника; он говорит, что выражение*ip
- это int. Синтаксис объявления переменной имитирует синтаксис выражений, в которых может присутствовать переменная .
int *ip
следует читать как " *ip
вернет int
"? Но почему тогда присвоение после объявления не следует этому шаблону? Что, если новичок захочет инициализировать переменную? int *ip = 1
(читать: *ip
вернет int
и int
есть 1
) не будет работать должным образом. Концептуальная модель просто не кажется последовательной. Я что-то упустил?
Изменить: он попытался обобщить ответы здесь .