As far as I know, the derefence operator
a an array of 4 elements, each of which is an array of 2
int elements. (A 2-dimensional array is nothing more or less than an array of arrays.)
An array expression is, in most contexts, implicitly converted to a pointer to the array object's initial (zeroth) element. (Note the assumption that there is an array object; that has caused some angst, but it's not relevant here.)
The cases where an array expression is not converted to a pointer are:
So in the expression
*a, the subexpression
a (which is of type
int) is implicitly converted to a pointer of type
int(*) (pointer to array of 2
ints). Applying unary
* dereferences that pointer, giving us an expression of type
But we're not quite done yet.
*a is also an expression of array type, which means that, depending on how it's used, it will probably be converted again to a pointer, this time of type
If we write
sizeof *a, the conversion doesn't occur, so the expression yields the size of the type
If we write
**a, the conversion does occur.
*a is of type
int(*), which is converted to
int*; dereferencing that yields an expression of type
Note that despite the fact that we can legally refer to
**a, using two pointer dereference operations, there are no pointer objects.
a is an array object, consisting entirely of 8
int objects. The implicit conversions yield pointer values.
The implicit array-to-pointer conversion rules are in N1570 section 220.127.116.11 paragraph 3. (That paragraph incorrectly gives
_Alignof as a fourth exception, but
_Alignof cannot be applied to an expression. The published C11 standard corrected the error.)
Recommended reading: Section 6 of the comp.lang.c FAQ.