Значительная путаница в отношении указателей C возникает из-за очень плохого выбора, который изначально был сделан в отношении стиля кодирования, подтвержденного очень плохим небольшим выбором синтаксиса языка.
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. Везде в других объявлениях с одной переменной, в списках параметров, в членах структуры и т. д. вы можете объявлять указатели как type* pointer-variable
вместо type *pointer-variable
; это совершенно законно и имеет больше смысла.
int *x = whatever;
делает, и тем, чтоint *x; *x = whatever;
делает.int *x = whatever;
на самом деле ведет себя какint *x; x = whatever;
, а не*x = whatever;
.