It’s said that arrays “decay” into pointers. A C++ array declared as
int numbers  cannot be re-pointed, i.e. you can’t say
numbers = 0x5a5aff23. More importantly the term decay signifies loss of type and dimension;
numbers decay into
int* by losing the dimension information (count 5) and the type is not
int  any more. Look here for cases where the decay doesn’t happen.
If you’re passing an array by value, what you’re really doing is copying a pointer – a pointer to the array’s first element is copied to the parameter (whose type should also be a pointer the array element’s type). This works due to array’s decaying nature; once decayed,
sizeof no longer gives the complete array’s size, because it essentially becomes a pointer. This is why it’s preferred (among other reasons) to pass by reference or pointer.
Three ways to pass in an array1:
void by_value(const T* array) // const T array means the same void by_pointer(const T (*array)[U]) void by_reference(const T (&array)[U])
The last two will give proper
sizeof info, while the first one won’t since the array argument has decayed to be assigned to the parameter.
1 The constant U should be known at compile-time.