Unless it is the operand of the sizeof
, _Alignof
, 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, or "decay", to an expression of type "pointer to T
" and its value will be the address of the first element of the array.
So when you call a function with an array expression as a parameter:
T arr[N];
...
foo( arr );
what the function actually receives is a pointer to the first element of the array - it's equivalent to calling the function as
foo( &arr[0] );
There is a reason for this behavior. Ritchie derived C from an earlier language called B, and when you created an array in B the compiler set aside an extra word to store an offset to the first element. The subscript operation a[i]
was defined as *(a + i)
- given the starting address stored in a
, offset i
words from that address and dereference the result.
Ritchie wanted to keep that subscript behavior (a[i] == *(a + i)
), but he didn't want to keep the explicit pointer that behavior required, so instead he created the rule that any time the compiler saw an array expression it would convert that expression to a pointer to the first element, except in the cases listed above.
No more need to store a separate pointer, but now arrays lose their "array-ness" under most circumstances, including when they are passed as function arguments.
In the context of a function parameter declaration, T a[N]
and T a[]
are "adjusted" to T *a
. Most of the time we just declare it as a pointer, since that's what we actually receive.