A two-dimensional array
char a[M][N];
can be declared using a typedef the following way
typedef char T[N];
T a[M];
So a pointer to the first element of the array a can be declared like
T *p = a;
where T is an alias for the type char[N]. Now making the reverse substitution we can write
char ( *p )[N] = a;
That is elements of a two-dimensional array are one-dimensional arrays.
This declaration
char ( *p )[N] = a;
is equivalent to
char ( *p )[N] = &a[0];
where a[0] has the type char[N]. So the pointer points to the first "row" of the array.
Dereferencing the pointer you will get an object of the type char[N].
Pay attention to that a two-dimensional array can be declared like
char ( a[M] )[N];
So substituting the one-dimensional array declarator a[M] for pointer you will get
char ( a[M] )[N];
char ( *p )[N] = a;
If you will declare a pointer like this
char *p1;
then you may write for example
p1 = a[1];
in this expression a[1] is a one-dimensional array of the type char[N]. Using the expression as an initializer the array is converted to pointer to its first element that has the type char *.
So this expression statement
p1 = a[1];
is equivalent to
p1 = &a[1][0];
Dereferencing this pointer you will get an object of the type char.