Мне недавно понравилось объяснять указатели начинающему программисту 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
(read: *ip
вернет int
и int
is 1
) не будет работать должным образом. Концептуальная модель просто не кажется последовательной. Я что-то пропустил?
Изменить: Он попытался обобщить ответы здесь.