Основные правила:
T *p; // p is a pointer to T
T *p[N]; // p is an array of pointer to T
T (*p)[N]; // p is a pointer to an array of T
T *p(); // p is a function returning a pointer to T
T (*p)(); // p is a pointer to a function returning T
T const *p; // p is a non-const pointer to const T
const T *p: // same as above
T * const p; // p is a const pointer to a non-const T
Деклараторы могут быть довольно сложными - этот список едва царапает поверхность.
Произвольно сложные деклараторы могут быть созданы путем подстановки:
T *p; // p is a pointer to T
|
+—————+
| |
v v
T *(*a)[N]; // a is a pointer to an array of pointer to T
|
+————+
| |
v v
T *(*f(int))[N]; // f is a function returning a pointer to an array of pointer to T
|
+—————+
| |
v v
T *(*(*g[M])(int))[N]; // g is an array of pointers to functions returning pointers to arrays of pointer to T
Функция signal
в стандартной библиотеке C, вероятно, имеет самое неприятное объявление, которое вы можете увидеть в дикой природе:
void (*signal(int sig, void (*func)(int)))(int);
, которое читается как
signal — signal
signal( ) — is a function taking
signal( sig ) — parameter sig
signal(int sig ) — is an int
signal(int sig, func ) — parameter func
signal(int sig, *func ) — is a pointer to
signal(int sig, (*func)( )) — a function taking
signal(int sig, (*func)( )) — unnamed parameter
signal(int sig, (*func)(int)) — is an int
signal(int sig, void (*func)(int)) — returning void
*signal(int sig, void (*func)(int)) — returning a pointer to
(*signal(int sig, void (*func)(int)))( ) — a function taking
(*signal(int sig, void (*func)(int)))( ) — unnamed parameter
(*signal(int sig, void (*func)(int)))(int) — is an int
void (*signal(int sig, void (*func)(int)))(int) — returning void