The key to understanding the seemingly strange syntax cases of function parameters is to understand array decay. This is all about one rule in C that says, whenever you pass an array as parameter to a function, it decays into a pointer to the first element of that array (*).
So when you write something like
void func (int a[5]);
then at compile-time, the array gets replaced with a pointer to the first element, making the above equal to:
void func (int* a);
This rule of pointer decay applies recursively to multi-dimensional arrays. So if you pass a multi-dimensional array to a function:
void func (int a[5][3]);
it still decays to a pointer to the first element. Now as it happens, a 2D array is actually an array of arrays. The first element is therefore a one-dimensional array, with size 3 in this example. You get an array pointer to that array, the type int(*)[3]
. Making the above equivalent to
void func (int (*a)[3]);
And this is actually the reason why we can omit the left-most dimension of the array parameter, and only that dimension. Upon doing so we make an array of incomplete type, which you normally wouldn't be able to use: for example you can't write code like int array[];
inside a function's body. But in the parameter case, it doesn't matter that the left-most dimension isn't specified, because that dimension will "decay away" anyway.
(*) Source, C11 6.7.6.3/7:
A declaration of a parameter as ‘‘array of type’’ shall be adjusted to
‘‘qualified pointer to type’’, ...