Багато плутанини щодо вказівників на С походить від дуже поганого вибору, який спочатку був зроблений щодо стилю кодування, підтвердженого дуже поганим вибором у синтаксисі мови.
int *x = NULL;
правильний C, але це дуже оманливе, я б навіть сказав безглузде, і це заважає розумінню мови багатьом новачкам. Це змушує думати, що пізніше ми могли б зробити це, *x = NULL;
що, звичайно, неможливо. Розумієте, тип змінної не є int
, а ім’я змінної - ні *x
, а *
також декларація не відіграє жодної функціональної ролі у співпраці з =
. Це суто декларативно. Отже, набагато більше сенсу є ось що:
int* x = NULL;
що також є правильним C, хоча воно не відповідає оригінальному стилю кодування K&R. Це чітко дає зрозуміти, що тип є int*
, а змінна вказівника є x
, тому навіть для непосвячених стає очевидним, що значення NULL
зберігається x
, яке є вказівником на int
.
Крім того, це полегшує виведення правила: коли зірка знаходиться далеко від імені змінної, тоді це декларація, тоді як зірка, прикріплена до імені, є розмежуванням покажчика.
Отже, тепер стає набагато зрозумілішим, що далі ми можемо або робити, x = NULL;
або *x = 2;
іншими словами, новачкові легше бачити, як це variable = expression
веде до pointer-type variable = pointer-expression
та dereferenced-pointer-variable = expression
. (Для ініційованих, під виразом 'я маю на увазі' rvalue '.)
Невдалий вибір у синтаксисі мови полягає в тому, що при оголошенні локальних змінних ви можете сказати, int i, *p;
яке оголошує ціле число та вказівник на ціле число, тому це змушує вважати, що *
це корисна частина імені. Але це не так, і цей синтаксис - це просто химерний особливий випадок, доданий для зручності, і, на мій погляд, він ніколи не мав би існувати, оскільки він анулює правило, яке я запропонував вище. Наскільки мені відомо, ніде більше в мові цей синтаксис не має значення, але навіть якщо він є, це вказує на розбіжність у способі визначення типів покажчиків у C. Всюди, в оголошеннях з однією змінною, у списках параметрів, у членах struct та ін. Ви можете оголосити свої вказівники type* pointer-variable
замість type *pointer-variable
; це цілком законно і має більше сенсу.
int *x = whatever;
робить, і тим, щоint *x; *x = whatever;
робить.int *x = whatever;
насправді поводиться якint *x; x = whatever;
ні*x = whatever;
.