Reading declarations is a must if not for anything than to pass interviews!
Two simple ways have been presented, Reading from right to left or converting the whole declaration to a normal left to right form. 
Enjoy. Any feedback is welcome!
Method 1:
Declaration Reading from Right to Left, Read as Locate the identifier, Read as identifier is
int p; p is an integer
int p[10]; p is an array of 10 integers See if we have hit the end of the road, i.e,    ;
unsigned int p; p is an unsigned integer If we have, start reading reverse, we have 2 possibilities, a pointer or a Reserved word
int p[5][12]; p is a 5 by 12 array of integers
int p();  p is a function returning an integer If not we have 3 possibilities, a pointer an array or a function
long int p(char); p is a function with a character as an input and returning a long integer A pointer is possible only if the identifier is immediately postfixed with a closing bracket
char *p; p is a pointer to a character A decision of pointer or an array or function is taken on the basis of a simple bracket ()
char **p; p is a pointer to a pointer to a character A bracket has the highest precedence.
char *p[10]; p is an array of 10 pointers to characters An array or function has the next precedence and they can never occur together
double (*p)[20]; p is a pointer to an array of 20 doubles A prefixed pointer has the least precedence.
int *(*p)[15]; p is a pointer to an array of 15 pointers to integers
char *(*p[])(); p is an array of pointers to  functions returning  pointers to  characters A pointer is always prefixed
void (*p())(); p is a function returninga pointer to a function returning void An array or function is always postfixed and never occur side by side
int (*p)();             p is a pointer to a function returning an integer Would have a bracket always seperating them
int *p();               p is a function returning a pointer to an integer
int (**p)[];           p is a pointer to a pointer to an array of integers identifier is read as: identifier is
int (**p)();           p is a pointer to a pointer to a function returning an integer Reserved words are read either in singular or plural,  a character or characters, 
int *(*p)[];           p is a pointer to an array of pointers to integers an integer, or an unsigned integer
int (*p)[][];          p is a pointer to a 2 dimensional array of integers [] : an array of
int *(*p)();           p is a pointer to a function returning a pointer to an integer (): a function returning  or functions returning 
int **p[];             p is an array of pointers to pointers to integers * a pointer to or pointers to
int (*p[])[];          p is an array of pointers to an array of integers
int (*p[])();          p is an array of pointers to functions returning  integers Illegal Declarations
int *p[][];            p is a 2 dimension array of pointers to integers Array and functions side by side without a bracket in between
int **p();             p is a function returning a pointer to a pointer to an integer int p[]();               array of functions
int (*p())[];          p is a function returning a pointer to an array of integers int p()[];                function returning an array            
int (*p())();          p is a function returning a pointer to a function returning an integer int p()();               function returning function
char *p[ 3 ][ 4 ]; p is a 3 by 4 array of pointers to characters int (*p)[]();         array of functions
int *(*p[ 10 ])(); p is an array of pointers to functions returning pointers to integers int (*p)()[];         function returning array
int (*p)()();          function returning function 
Method 2:
Start with the identifier
Write as is upto the semi colon
Replace brackets with their contents, pointer or pointers towards the closing bracket
Go in  reverse sequence after the semi colon.
Declaration Convert to Normal form, Left to Right 
                 
  Start with Proceed upto the end ( ;) End with Return  Home 
  Identifier Left to Right (Forward) ; Right to Left (Reverse)
int p; p       ; int    
  p is         an integer    
           
int p[10]; p [10]     ; int    
  p is an array of 10        integers    
           
unsigned int p; p       ; unsigned int    
  p is         an unsigned integer    
           
int p[5][12]; p [5][12]     ; int    
  p is a 5 by 12 array of        integers    
           
int p();  p ()     ; int    
  p is a function returning        an integer    
           
long int p(char); p (char)     ; long int    
  p is a function with a character as an input and returning        a long integer    
           
char *p; p       ; * char  
  p is          a pointer to  a character  
           
char **p; p       ; * * char
  p is          a pointer to   a pointer to  a character
           
char *p[10]; p [10]     ; * char  
  p is an array of 10       pointers to characters  
           
double (*p)[20]; p * [20]   ; double    
  p is  a pointer to  an array of 20     doubles    
           
int *(*p)[15]; p * [15]   ; * int  
  p is  a pointer to  an array of 15     pointers to integers  
           
char *(*p[])(); p [] * () ; * char  
  p is an array of  pointers to  functions returning    pointers to characters  
           
void (*p())(); p () * () ; void    
  p is a function returning   a pointer to  a function returning         
           
int (*p)();             p * ()   ; int    
  p is  a pointer to  a function returning      an integer    
           
int *p();               p ()     ; * int  
  p is a function returning         a pointer to  an integer  
           
int (**p)[];           p * * [] ; int    
  p is  a pointer to   a pointer to  an array of    integers    
           
int (**p)();           p * * () ; int    
  p is  a pointer to   a pointer to  a function returning    an integer    
           
int *(*p)[];           p * []   ; * int  
  p is  a pointer to  an array of      pointers to integers  
           
int (*p)[][];          p * [][]   ; int    
  p is  a pointer to   a 2 dimensional array      integers    
           
int *(*p)();           p * ()   ; * int  
  p is  a pointer to  a function returning       a pointer to  an integer  
           
int **p[];             p []     ; * * int
  p is an array of        pointers to pointers to integers
           
int (*p[])[];          p []  * [] ; int    
  p is an array of  pointers to an array of    integers    
           
int (*p[])();          p [] * () ; int    
  p is an array of  pointers to  functions returning    integers    
           
int *p[][];            p [][] *   ; int    
  p is  a 2 dimensional array  pointers to     integers    
           
int **p();             p ()     ; * * int
  p is a function returning         a pointer to   a pointer to  an integer
           
int (*p())[];          p () * [] ; int    
  p is a function returning   a pointer to  an array of    integers    
           
int (*p())();          p () * () ; int    
  p is a function returning   a pointer to  a function returning    an integer    
           
char *p[ 3 ][ 4 ]; p [3][4]     ; * char  
  p is a 3 by 4 array of       pointers to characters  
           
int *(*p[ 10 ])(); p [10] * () ; * int  
  p is an array of 10 pointers to  functions returning    pointers to integers  
           
 int (*p[])(); p [] * () ; int    
  p is an array of  pointers to  functions returning    integers    
Illegal Declarations Array and functions side by side without a bracket in between
int p[][]();           array of functions int p()[][];           function returning 2 dimensional  arrays
int *p[]();            array of functions int p()[]();           function returning array of functions
int p[]()[];           array of functions returning arrays int *p()();            function returning function
int p[]()();           array of functions returning functions
int *p()[];            function returning array
Reading C
Declarations
Introduction
Concept 1
Concept 2
Concept 3
Concept 4
Home
Contact
Links
Assembly
Reference