Edit: Here's my attempt at a more to-the-point answer as requested and based on your new example code:
Regardless of the array dimensions, what you pass is a "pointer to an array" - it's only a single pointer, though the type of the pointer can vary.
In your first example, int array[6] is an array of 6 int elements. Passing array passes a pointer to the first element, which is an int, hence the parameter type is int *, which can be equivalently written as int [].
In your second example, int array[3][3] is an array of 3 rows (elements), each containing 3 ints. Passing array passes a pointer to the first element, which is an array of 3 ints. Hence the type is int (*)[3] - a pointer to an array of 3 elements, which can be equivalently written as int [][3].
I hope you see the difference now. When you pass an int **, it is actually a pointer to an array of int *s and NOT a pointer to a 2D array.
An example for an actual int ** would be something like this:
int a[3] = { 1, 2, 3 };
int b[3] = { 4, 5, 6 };
int c[3] = { 7, 8, 9 };
int *array[3] = { a, b, c };
Here array is an array of 3 int *s, and passing this as an argument would result in an int **.
Original answer:
Your first example isn't really a 2D array, although it is used in a similar way. There, you're creating ROWS number of char * pointers, each of which points to a different array of COLS characters. There are two levels of indirection here.
The second and third examples are actually 2D arrays, where the memory for the entire ROWS * COLS characters is contiguous. There is only one level of indirection here. A pointer to a 2D array is not char **, but char (*)[COLS], so you can do:
char (*p)[SIZE] = arr;
// use p like arr, eg. p[1][2]