The easiest and best way to learn the syntax is to not memorise specific cases but the grammar itself, which IMHO is no more difficult than the existing concept of operator precedence. Everyone using C should hopefully already know that multiplication has higher precedence than addition, so likewise function call (and array subscripting) has higher precedence than pointer dereference. Thus this table should make it clear that combining the two operators creates pointer-to-function:
T x; T *y;
T f(); T (*g)();
T pointer to T
function returning T pointer to function returning T
and the alternative, T h(); , is parsed as T (h()); and thus becomes "function returning pointer to T".
The apparent struggle I see with this syntax has always somewhat puzzled me, because I don't see the same level of complaints about e.g. arithmetic expressions (like 6+3*4/(2+1)) which are parsed with precedence in much the same way. K&R even has a section on writing a parser that recognises this syntax, so I suspect it's really not that hard, but the perception spread by those who didn't learn the syntax but only memorised the "easy cases" is making it appear more difficult than it really is.
What we need realize is that simple grammar does not always lead to simple comprehension. Nesting the grammar elements more than a few levels is always difficult for our current biology equipment.
You define a variable the same way you would use it.
int *a -> expression *a has type int.
int *a[10] -> *a[_] has type int.
int (*a)[10] -> (*a)[_] has type int.
int (*a)(int, int) -> (*a)(_, _) has type int.
No need for complicated things like "spiral rules", etc.
Nice explanation, thanks; your formatting got a little messy right after the code block, though, because things between asterisks are rendered cursive.
The apparent struggle I see with this syntax has always somewhat puzzled me, because I don't see the same level of complaints about e.g. arithmetic expressions (like 6+3*4/(2+1)) which are parsed with precedence in much the same way. K&R even has a section on writing a parser that recognises this syntax, so I suspect it's really not that hard, but the perception spread by those who didn't learn the syntax but only memorised the "easy cases" is making it appear more difficult than it really is.