Q:

What's the difference between char *a[]={"hello", "world"}; and char a[][10]={"hello", "world"};?

When I tried out this code
char *a[] = {"hello", "world" };
char **p = a;
char a[][10]={"hello", "world"};

My compilation fails and I am told that there is a conflicting type error for the variable a. How is the top declaration, different from the bottom? 

A:

In the first declaration
char *a[] = {"hello", "world" };

the array a has the type char * [2]. Elements of the array have the type char *.
Used in expressions as for example as an initializer it is implicitly converted to pointer to its first element that has the type char **,
So this declaration
char **p = a;

is correct.
This declaration
char a[][10]={"hello", "world"};

declares an array of the type char [2][10]. Elements of the array have the type char[10].
Used in expressions it is implicitly converted to pointer to its first element of the type char ( * )[10].
So the correct declaration of the pointer will be
char ( *p )[10] = a;

Thus the two declarations of arrays declare arrays of different types.
Pay attention to that you may not change string literals using elements (pointers) of the first array.
In the second declaration the elements of the literal are copied into elements of the array. As the array does not have the qualifier const then you may change the stored strings.

A:

Here is a picture of memory layout. This corresponds to the code:
char *a[2] = { "hello", "world" };
char **p = a;
char b[][10] = { "hello", "world" };
char **q = b;   // Error

Red = character array, Green = pointer-to-char, Teal = pointer-to-pointer-to-char.
A char ** (i.e. a pointer to char *) can only point at char * variables, it cannot point at a char array . 
As you can see, the char ** called p is pointing to storage of a char *. 
But where can q point? There are no variables of the right type.  If you want to point directly at b, or at rows of b, then you need a pointer which points to char arrays (not a pointer which points to char pointers).

