There are two quotes from the C Standard that makes using arrays more clear.
The first one is (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.
And the second one is (6.7.6.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.
What does this mean relative to function declaration?
If you declared a function like for example
void f( int a[100] );
then the compiler will adjust the function parameter the following way
void f( int *a );
So for example these function declarations are equivalent
void f( int a[100] );
void f( int a[10] );
void f( int a[1] );
void f( int a[] );
void f( int *a );
and declare the same one function. You nay even include all these declarations in your program though the compiler can issue a message that there are redundant declarations.
Within the function the variable a
has the the pointer type int *
.
On the other hand, you may call the function passing arrays of different sizes. Arrays designators will be implicitly converted by the compiler to pointers to their first element. You even may pass a scalar object through a pointer to it.
So these calls of the function are all correct
int a[100];
f( a );
int a[10];
f( a );
int a[1];
f( a );
int a;
f( &a );
As a result the function has no information what array was used as an argument. So you need to declare the second function parameter that will specify the size of the passed array (if the function does not rely on a sentinel value present in the array)
For example
void f( int a[], size_t n );
If you have a multidimensional array like this
T a[N1][N2][N3]...[Nn];
then a pointer to its first element will have the type
T ( *a )[N2][N3]...[Nn];
So a function declared like
void f( T a[N1][N2][N3]...[Nn] );
is equivalent to
void f( T ( *a )[N2][N3]...[Nn] );
If there N2, N3,..Nn are integer constant expressions then the array is not a variable length array. Otherwise it is a variable length array and the function may be declared like (when the declaration os not a part of the function definition)
void f( T ( *a )[*][*]...[*] );
For such a function there is also a problem of determining of sizes of sub-arrays. So you need to declare parameters that will specify the sizes.
For example
void f( size_t n1, size_t n2, size_t n3, ..., size_t nn, T a[][n2][n3]...[nn] );
As for C++ then variable length arrays is not a standard C++ feature. Also you can declare a function parameter as having a referenced type.
For example
void f( int ( &a )[10] );
within the function in this case a is not a
pointer. It denotes an array and the expression sizeof( a )
will yield the size of the whole array instead of the size of pointer.