I'm confused as to how the dereference operator functions in pointer declarations.
Consider both these scenarios:
int y = 5;
int *x = &y;
int y = 5;
int *x;
x = &y;
The second scenario (separate declaration and initialization) makes sense to me. After reading through many similar questions, I've noted that declaration resembles usage. That is, *x
is an integer, so x
is a pointer to an integer. Therefore, the assignment of x
to a pointer of y
makes sense.
What confuses me is the first scenario (combined declaration and initialization). I struggle to understand why int *x = &y;
should work. *x
is not a pointer, so why should it be initialized with a pointer?
I've had a few attempts at rationalizing this first scenario. Mainly, I'm trying to determine whether declaration in C just has a special grammar where the value that is assigned with int *x = &y;
is x
, not *x
. Nothing else really makes sense to me.
One explanation that I've seen that I'm not very satisfied with is the higher level "treat int*
as a type" explanation. I'm not satisfied with it because it fails for int* x, z
.
A unary *
always represents a dereference.
This may feel familiar and intuitive in an expression: *x
means to get the value x
points to. In contrast, you may find a declaration less intuitive; what does *
mean in int *x
?
The way to think of this is that a declaration gives a picture of how something will be used. The declaration int *x
says *x
will be used as an int
. In other words, when we get the thing that x
points to, it is an int
. The *
in a declaration represents the same thing that happens in an expression: dereferencing the pointer.
Kernighan and Ritchie tell us this in The C Programming Language, 1978, page 90:
The declaration of the pointer
px
is new.
int *px;
is intended as a mnemonic; it says the combination
*px
is anint
, that is, ifpx
occurs in the context*px
, it is equivalent to a variable of the typeint
. In effect, the syntax of the declaration for a variable mimics the syntax of expressions in which the variable might appear.
As a more involved example, consider int (*p)[];
. This tells us that (*p)[]
is an int
. Since []
is used to access array elements, this means (*p)
must be an array of int
. And that means p
must be a pointer to an array of of int
. Just like *
, []
does not have a reversed meaning in declarations. It does not mean “is an array of” instead of “access an element of”; it is still an image of how the thing will be used in an expression.
In int *x = &y;
, the =
character does not mean assignment. It means initialization. And what is being initialized is not the expression on the left side of the =
, because there is no actual expression on the left side. In the declaration int *x
, *x
is not an expression; it is only an image of how x
would be used in an expression. In int *x = &y;
, int *x
is declaring x
, so it is x
that is being initialized, not *x
being assigned.