Because when you pass an array to a function, it decays to a pointer, more precisely to a pointer to the first element.

In your example, the argument arr is actually a pointer and not an array (which is also why you can't use sizeof on the "array", that gets the size of the pointer and not what it points to). When you declare an argument such as int arr[X] (the value of X doesn't matter) it's actually equivalent to declaring int *arr. When you know that it's also very clear what the actual return type should have been: int*:

int* func(int* arr)
{
return arr;
}

One way to remove doubt or ambiguities would have been to use std::array instead:

std::array<int, 10>& func(std::array<int, 10>& arr)
{
return arr;
}

As a side-note, if you hade an actual array of integers, say

int arr[10] = { ... };

then to get a pointer to that (which would be of type int (*)[10]) then you would have to use the address-of operator as usual:

&arr;

Regarding your comment, lets say you had a static array inside the function, and what to return an actual pointer to the array, then you would have to use that "weird" return-type syntax.