I have been taught that v
is a pointer to the first element in the v
array.
You have been taught incorrectly. v
is not a pointer - no space for a pointer is materialized as part of the array. What you get is something like this:
+---+
v: | 1 | v[0]
+---+
| 2 | v[1]
+---+
| 3 | v[2]
+---+
| 4 | v[3]
+---+
| 5 | v[4]
+---+
and not this:
+---+
v: | |
+---+
|
|
V
+---+
| 1 | v[0]
+---+
| 2 | v[1]
+---+
| 3 | v[2]
+---+
| 4 | v[3]
+---+
| 5 | v[4]
+---+
Except when it is the operand of the sizeof
or unary &
operators, 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.
When you write something like foo( v )
, or printf( "%p\n", (void *) v)
, or even just v[i]
, the expression v
is converted from type "5-element array of int
" to "pointer to int
", and the value of the expression is the same as &v[0]
.
However, when you write sizeof v
, that conversion doesn't happen - sizeof
evaluates to the number of bytes in the entire array (5 * sizeof (int)
). Similarly, the type of the expression &v
is int (*)[5]
(pointer to 5-element array of int
), not int **
.
This is why sizeof v
yields 20, while sizeof (v + 0)
yields 4 - in the second case, v
is not the operand of sizeof
, the expression (v + 0)
is the operand of sizeof
. In the expression (v + 0)
, v
decays to type int *
. Note that you will get a different result if you write sizeof v + 0
- sizeof
has higher precedence than the addition operator +
, so that expression would be parsed as (sizeof v) + 0
.