Here are the basic rules:
For any1 type T
, you can have any of the following:
T *p; // p is a pointer to T
T *a[N]; // a is an array of pointer to T
T (*a)[N]; // a is a pointer to an array of T
T *f(); // f is a function returning pointer to T
T (*f)(); // f is a pointer to a function returning T
The postfix []
and ()
operators have higher precedence than unary *
, so an expression like *p[i]
is parsed as *(p[i])
. If you want to index into what p
points to, then you need to explicitly group the *
operator with p
, or (*p)[i]
. This precedence rule applies to both expressions and declarations.
Except when it is the operand of the sizeof
, _Alignof
, or unary &
operator, or is a string literal used to initialize a character array in a declaration, an expression of type "N-element array of T
" will be converted ("decay") to an expression of type "pointer to T
" and the value of the expression will be the address of the first element of the array. So given the declaration
int a[4] = {10, 20, 30, 40};
all of the following are true:
Expression Type Decays to Equivalent value
---------- ---- --------- ----------------
a int [4] int * &a[0]
&a int (*)[4] n/a &a[0]
*a int n/a a[0]
The expression a
has type "4-element array of int
" (int [4]
). a
is not the operand of the sizeof
, _Alignof
, or unary &
operators, so the expression "decays" to type "pointer to int
" and the value of the expression is the address of the first element. The result of this expression is exactly equivalent to &a[0]
.
The expression &a
has type "pointer to 4-element array of int
" (int (*)[4]
). In this case, a
is the operand of the unary &
operator, so the decay rule doesn't apply.
All of the expressions a
, &a
, and &a[0]
yield the same value (the address of the first element of a
), but the types of the expressions are different (which may affect how the value is represented). The type of a
and &a[0]
is int *
, but the type of &a
is int (*)[4]
.
Type matters for things like pointer arithmetic. Assume the following declarations:
int a[4] = {0, 1, 2, 3};
int *p = a;
int (*ap)[4] = &a;
Both p
and ap
initially point to the same address. However, the expression p + 1
will yield the address of the next int
object following whatever p
is pointing to (IOW, &a[1]
), while ap + 1
will yield the address of the next 4-element array of int
following a
.
This is exactly how array subscripting works - the expression a[i]
is evaluated as *(a + i)
. Given a starting address a
, offset i
objects (not bytes) and dereference the result.
And this is why you get the errors in some of your assignments - the types int *
and int (*)[4]
are not compatible. For one thing, they don't have to be represented the same way (although on any system you're likely to use they will be), and they behave differently when using pointer arithmetic.
Pointers to different types are themselves different types, and are not normally interchangeable.
- Well, almost any - functions cannot return array or function types, and you cannot have an array of function type, so for
T (*a)[N]
T
cannot be a function type, and for T (*f)()
T
cannot be a function or array type.