When an expression of array type appears in most contexts1, it is implicitly converted ("decays") to an expression of pointer type and its value is the address of the first element in the array. Similarly, in the context of a function parameter declaration (but only in that context), declarations like T a[] and T a[N] are interpreted as T *a; despite the array notation, the parameter a is a pointer, not an array type.
So given code like
int arr[10]; ... foo(arr);
The type of the expression arr in the call to foo is "10-element array of int". In this context, the type of the expression is converted to "pointer to int", so foo will receive a pointer value.
Similarly, given a function definition
void foo(int a[10]) { ... }
the type of the parameter a is not "10-element array of int", but rather "pointer to int".
In short, you cannot pass an array argument to a function and have it received as an array type; all you get is a pointer value. As a result, you must either pass the array size as a separate parameter, or terminate the array with a sentinel value (such as using a 0 in an array of char to terminate strings).
1 The exceptions to this rule are when the array expression appears as an operand to either the sizeof or unary & operators, or if it is a string literal being used to initialize another array in a declaration.