Some more differences description looking it from memory addressing view as follows,
I. char **p; p is double pointer of type char
Declaration:
char a = 'g';
char *b = &a;
char **p = &b;
   p                    b                    a     
+------+             +------+             +------+
|      |             |      |             |      |              
|0x2000|------------>|0x1000|------------>|   g  | 
|      |             |      |             |      |
+------+             +------+             +------+
 0x3000               0x2000               0x1000
Figure 1: Typical memory layout assumption   
In above declaration, a is char type containing a character g. Pointer b contains the address of an existing character variable a. Now b is address 0x1000 and *b is character g. Finally address of b is assigned to p, therefore a is a character variable, b is pointer and p is pointer to pointer. Which implies a contains value, b contains address and p contains address of address as shown below in the diagram. 
Here, sizeof(p) = sizeof(char *) on respective system;
II. char *p[M]; p is array of strings
Declaration: 
char *p[] = {"Monday", "Tuesday", "Wednesday"};
      p
   +------+  
   | p[0] |       +----------+
0  | 0x100|------>| Monday\0 |              
   |      |       +----------+
   |------|       0x100
   | p[1] |       +-----------+
1  | 0x200|------>| Tuesday\0 |
   |      |       +-----------+
   |------|       0x200
   | p[2] |       +-------------+
2  | 0x300|------>| Wednesday\0 |
   |      |       +-------------+ 
   +------+       0x300
Figure 2: Typical memory layout assumption
In this declaration, p is array of 3 pointers of type char. Implies array p can hold 3 strings. Each string (Monday, Tuesday & Wednesday) is located some where in memory (0x100, 0x200 & 0x300), there addresses are in array p as (p[0], p[1] & p[2]) respectively. Hence it is array of pointers.
Notes: char *p[3];
1. p[0], p[1] & p[2] are addresses of strings of type `char *`.
2. p, p+1 & p+2 are address of address with type being `char **`.
3. Accessing elements is through, p[i][j] is char; p[i] is char *; & p is char **
Here sizeof(p) = Number of char array * sizeof(char *)
III. char p[M][N]; p is array of fixed length strings with dimensions as M x N
Declaration: 
char p[][10] = {Monday, Tuesday, Wednesday};
  p  0x1 2 3 4 5 6 7  8  9  10
    +-------------------------+
 0  | M  o n d a y \0 \0 \0 \0|     
 1  | T  u e s d a  y \0 \0 \0| 
 2  | W  e d n e s  d  a  y \0|
    +-------------------------+
 Figure 3: Typical memory layout assumption
In this case array p contain 3 strings each containing 10 characters. Form the memory layout we can say p is a two dimensional array of characters with size MxN, which is 3x10 in our example. This is useful for representing strings of equal length since there is a possibility of memory wastage when strings contains lesser than 10 characters compared to declaration char *p[], which has no memory wastage because string length is not specified and it is useful for representing strings of unequal length.      
Accessing elements is similar as above case, p[M] is M'th string & p[M][N] is N'th character of M'th string. 
Here sizeof(p) = (M rows * N columns) * sizeof(char) of two dimensional array;