Both void foo(int arr[])
and void foo(int arr[N])
are exactly equivalent. This is because an array as an argument to a function is adjusted to a pointer. So both of the above translate to:
void foo(int *arr)
This is specified in section 6.7.6.3p7 of the C standard regarding "Function declarators":
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.
Similar language exists in section 11.3.5p5 the C++ standard:
A single name can be used for several different functions in a single
scope; this is function overloading(Clause 16). All declarations for a
function shall agree exactly in both the return type and the
parameter-type-list. The type of a function is determined using the
following rules. The type of each parameter (including function
parameter packs) is determined from its own decl-specifier-seq and
declarator. After determining the type of each parameter, any
parameter of type “array of T” or of function type T is adjusted to be
“pointer to T”. After producing the list of parameter types, any
top-leve lcv-qualifiers modifying a parameter type are deleted when
forming the function type. The resulting list of transformed parameter
types and the presence or absence of the ellipsis or a function
parameter pack is the function’s parameter-type-list.[Note:This
transformation does not affect the types of the parameters.