Karl Norum answered the legal question on this question (and received my eminence on it), here is the answer to the implementation details:
To a computer, any object in memory is just a range of bytes and, with respect to memory processing, is uniquely identified by the address for the first byte and the size in bytes. Even if you have an int in memory, its address is not more or less than the address of its first byte. The size is almost always implicit: if you pass a pointer to an int , the compiler knows its size because it knows that the bytes at this address should be interpreted as int . The same goes for structures: their address is the address of their first byte, their size is implicit.
Now, language developers could implement similar semantics with arrays, as was the case with structures, but they werenβt for a good reason: copying was even more inefficient then than now, compared to just passing a pointer, structures were most often using pointers, and arrays are usually large. Prohibitively large to force semantics of meaning on them by language.
Thus, arrays were simply forced to be memory objects at all times, indicating that the name of the array would actually be equivalent to a pointer. In order not to violate the similarity of arrays with other memory objects, the size was again considered implicit (for the implementation of the language, and not for the programmer!): The compiler could just forget about the size of the array when it was accepted somewhere else and rely on the programmer to find out how many objects were inside the array.
This had the advantage that access to the array is overly simple; they break up into pointer arithmetic, multiplying the index by the size of the object in the array and adding this offset to the pointer. This is the reason why a[5] exactly matches 5[a] , it is short for *(a + 5) .
Another aspect related to performance is that to simplify the creation of a submatrix from an array, you just need to calculate only the starting address. There is nothing that would force us to copy data to a new array, we just have to remember to use the correct size ...
So yes, it has deep reasons, in terms of ease of implementation and performance, that array names decay into pointers the way they do, and we should be glad about that.