Нещодавно я мав задоволення пояснювати покажчики початківцю програмування на С і натрапляв на наступні труднощі. Це може не здатися проблемою, якщо ви вже знаєте, як користуватися покажчиками, але спробуйте зрозуміти наступний приклад чітко:
int foo = 1;
int *bar = &foo;
printf("%p\n", (void *)&foo);
printf("%i\n", *bar);
Для абсолютного початківця вихід може бути дивовижним. У другому рядку він / вона щойно оголосив * bar для & foo, але у рядку 4 виявляється * bar насправді foo замість & foo!
Плутанина, можна сказати, випливає з неоднозначності символу *: У другому рядку він використовується для оголошення вказівника. У рядку 4 він використовується як одинарний оператор, який отримує значення, на яке вказує вказівник. Дві різні речі, правда?
Однак це "пояснення" зовсім не допомагає новачку. Він вводить нову концепцію, вказуючи на тонку невідповідність. Це не може бути правильним способом цього навчити.
Отже, як це пояснили Керніган та Річі?
Одинарний оператор * - це оператор опосередкування або перенаправлення; при застосуванні до вказівника він отримує доступ до об'єкта, на який вказує вказівник. […]
Декларація вказівника ip,
int *ipпризначена як мнемонічна; це говорить, що вираз*ipє цілим. Синтаксис оголошення для змінної імітує синтаксис виразів, у яких може відображатися змінна .
int *ipслід читати як " *ipповернеться int"? Але чому тоді призначення після декларації не відповідає цій схемі? Що робити, якщо новачок хоче ініціалізувати змінну? int *ip = 1(читайте: *ipповернеться intта intє 1) не буде працювати, як очікувалося. Концептуальна модель просто не здається узгодженою. Я щось тут пропускаю?
Редагувати: Тут спробували узагальнити відповіді .
*в декларації є лексемою, що означає "оголосити вказівник", у виразах - оператор перенаправлення, і що ці два репрезентують різні речі, які, мабуть, мають однаковий символ (те саме, що оператор множення - той самий символ, різний зміст). Це заплутано, але все, що відрізняється від фактичного стану справ, буде ще гіршим.
int* barробить більш очевидним, що зірка насправді є частиною типу, а не частиною ідентифікатора. Звичайно, це створює вам різні проблеми з такими неінтуїтивними матеріалами, як int* a, b.
*може мати два різних значення залежно від контексту. Так само, як та сама буква може вимовлятися по-різному, залежно від слова, в якому важко навчитися говорити на багатьох мовах. Якби кожна концепція / операція мала свій власний символ, нам знадобляться набагато більші клавіатури, тому символи переробляються, коли це має сенс.
int* p), попереджаючи свого учня проти використання кількох декларацій в одному рядку, коли задіяні покажчики. Коли студент повністю зрозумів поняття покажчиків, поясніть студенту, що int *pсинтаксис is є рівнозначним, а потім поясніть проблему декількома деклараціями.


