If you declare an array as
char *array[N][M];
and pass it to a function as
test(array)
then the prototype to the function will need to be either
void test(char *(*arr)[M])
or
void test(char *arr[][M])
In either case, arr has type "pointer to M-element array of pointer to char". This is not the same type as char ***, and there's no really good or clean way to convert between the two.
Had you allocated dynamcally allocated array in the following manner, then the prototype would be correct:
char ***array = malloc(sizeof *array * N);
if (array)
{
size_t i;
for (i = 0; i < N; i++)
{
array[i] = malloc(sizeof *array[i] * M);
if (array[i])
{
size_t j;
for (j = 0; j < M; j++)
{
array[i][j] = some_initial_pointer_value();
}
}
}
}
Note that in this case, the type of array is char ***.
If you're working with arrays declared as T a[M][N], and you want to write a function that will accept arrays of different sizes, then you can either use the VLA syntax as suggested by Jens, or you could do something like this:
void test(char **a, size_t rows, size_t cols)
{
size_t i, j;
...
some_pointer_value = a[i * rows + j];
...
a[i * rows + j] = some_pointer_value;
}
...
test(&array[0][0], 50, 50);
In this case, we explicitly pass the address of the first element of the array and the array dimensions as separate parameters. Within the body of test we treat the array as having 1 dimension (char *a[rows * cols]) and compute the offset manually. Note that this only works for arrays that are contiguously allocated; this won't work with the version that does piecemeal allocation for each row in the array above.
test; triple pointers are a bit of a code smell.