Why is p = &a; and *p = a different?
p = &a stores the address of a into p.
*p = a stores the value of a into the thing p points to.
After writing p = &a, the following conditions are true:
p == &a; // int * == int *
*p == a; // int == int
and the statement
*p = 5;
is exactly equivalent to writing
a = 5;
The expression *p basically acts as an alias for the variable a.
In your code, the line
*p = a;
gave you a segfault because p had not yet been assigned to point to a writable location. Unless explicitly initialized, the contents of a local variable1 are indeterminate — it could be anything.
When int* p = &a; is declared, does p = &a, not *p = &a?
In a declaration the * is only there to indicate type; it does not dereference p, any more than int a[N]; indexes into a or void f(void) calls f. So the declaration initializes p with the result of the expression &a (which has type int *).
Declarations in C are composed of two main sections — a sequence of declaration specifiers followed by a comma-separated list of declarators.
Declaration specifiers include type specifiers (int, char, float), type qualifiers (const, volatile), storage class specifiers (auto, static, register), and a few others.
Declarators contain the name of the thing being declared, along with information about that thing's array-ness, function-ness, and/or pointer-ness. In the declaration
unsigned long a[N], *p, f(void);
the declaration specifiers are unsigned long and the declarators are a[N], *p, and f(void). The types of a, p, and f are specified by the combinations of the declaration specifiers and declarators, so the type of a is "N-element array of unsigned long, the type of p is "pointer to unsigned long", and the type of f is "function taking no parameters and returning unsigned long".
Remember that in a declaration the * operator is always bound to the declarator, not the type specifier. The declaration
T* p; // for any type T
is always parsed as
T (*p);
meaning if you write a declaration like
T* p, q;
only p will be declared as a pointer; q will be declared as a regular T. If both need to be declared as pointers, you'd write
T *p, *q;
- Strictly speaking, we mean something with
auto storage duration; declared within a block without the static keyword.