First, some standardese:
6.7.5.3 Function declarators (including prototypes)
...
7 A declaration of a parameter as ‘‘array of type’’ shall be adjusted to ‘‘qualified pointer to
type’’, where the type qualifiers (if any) are those specified within the [
and ]
of the
array type derivation. If the keyword static
also appears within the [
and ]
of the
array type derivation, then for each call to the function, the value of the corresponding
actual argument shall provide access to the first element of an array with at least as many
elements as specified by the size expression.
So, in short, any function parameter declared as T a[]
or T a[N]
is treated as though it were declared T *a
.
So, why are array parameters treated as though they were declared as pointers? Here's why:
6.3.2.1 Lvalues, arrays, and function designators
...
3 Except when it is the operand of the sizeof
operator or the unary &
operator, or is a
string literal used to initialize an array, an expression that has type ‘‘array of type’’ is
converted to an expression with type ‘‘pointer to type’’ that points to the initial element of
the array object and is not an lvalue. If the array object has register storage class, the
behavior is undefined.
Given the following code:
int main(void)
{
int arr[10];
foo(arr);
...
}
In the call to foo
, the array expression arr
isn't an operand of either sizeof
or &
, so its type is implicitly converted from "10-element array of int
" to "pointer to int
" according to 6.2.3.1/3. Thus, foo
will receive a pointer value, rather than an array value.
Because of 6.7.5.3/7, you can write foo
as
void foo(int a[]) // or int a[10]
{
...
}
but it will be interpreted as
void foo(int *a)
{
...
}
Thus, the two forms are identical.
The last sentence in 6.7.5.3/7 was introduced with C99, and basically means that if you have a parameter declaration like
void foo(int a[static 10])
{
...
}
the actual parameter corresponding to a
must be an array with at least 10 elements.