double *a[n]; is an array of n pointers
double (*b)[n]; is pointer to array of size n
The original rule, in C, was that the declaration mimics use.
This ceased to be true with the introduction of typedef, and of
course, const, volatile and class types positively wreck havoc
with the philosophy. But the fact remains that a C++
declaration reads a lot like an expression, with precedence,
which can be overridden by parentheses. In the case of such
"type expressions", precedence is simple: operators to the right
always have precedence over those to the left, and on any given
side, the operator closest to the center has precedence over the
one further out. The operators on the right may be "()"
(function) and "[]" (array). So you get:
double (*c[n])() ;
c[n] an array[n] of
*c[n] pointers to
(*c[n])() functions taking no arguments, returning
double (*c[n])() double
and
double (*d())[n] ;
d() a function taking no arguments, returning
*d() a pointer to
(*d())[n] an array[n] of
double (*d())[n] double
Note that it's generally best to avoid such complicated
declarations. They're even harder to get right when you write
then than they are to read.