Well, it's certainly not well understood by the C community as can be seen by glancing over SO. The magic is, all of the following are totally, 100%, equivalent:
void foo(int (*array)[10]);
void foo(int array[][10]);
void foo(int array[10][10]);
void foo(int array[42][10]);
It is very important to draw the distinction of a pointer and an array. An array is not a pointer. An array can be converted to a pointer to its first element. If you have a pointer you have this:
--------
| ptr | -------> data
--------
However, if you have an array, you have this:
---------------------------
| c1 | c2 | c3 | ... | cn |
---------------------------
With the pointer, the data is at a whole other planet, but linked to by the pointer. An array has the data itself. Now, a multi-dimensional array is just an array of arrays. The arrays are nested into a parent array. So, the sizeof of your array is:
(sizeof(int) * 10) * 10
That is because you have 10 arrays, all of which are arrays of 10 integers. Now, if you want to pass that array, it is converted. But to what? A pointer to its first element. The element type is not a pointer, but an array. As a consequence, you pass a pointer to an array of 10 int:
int (*)[10] // a pointer to an int[10]
It is neither a array of int*
, nor a int**
. You may ask why the array is not passed as an int**
. It's because the compiler has to know the row-length. If you do an array[1][0]
, the compiler will address a place sizeof(int) * 10
bytes apart from the begin of the 2 dimensional array. It decodes that information in the pointer-to-array type.
So, you have to chose among one of the above fully equivalent function prototypes. Naturally, the last one is just confusing. The compiler just silently ignores any number written in the most outer dimension if a parameter is declared to be an array. So i would also not use the second last version. Best is to use the first or second version. What is important to remember is that C has no (real) array parameters! The parameter will be a pointer in the end (pointer to array in this case).
Note how the multi-dimensional case of above is similar to the degenerate, one dimensional case below. All of the following 4 versions are fully equivalent:
void foo(int *array);
void foo(int array[]);
void foo(int array[10]);
void foo(int array[42]);