The second innovation that most clearly distinguishes C from its predecessors is a more complete type structure and especially its expression in the syntax of declarations ... taking into account an object of any type, it should be possible to describe a new object that collects several into an array, returns it from a function or a pointer to it ... [This] led to declaration syntax for names duplicating the syntax of an expression in which names usually appear. In this way,
int i, *pi, **ppi; declare an integer, a pointer to an integer, a pointer to a pointer to an integer. The syntax of these declarations reflects that i, *pi, and **ppi all give an int type when used in an expression.
Similarly, int f(), *f(), (*f)(); declare a function that returns an integer, a function that returns a pointer to an integer, a pointer to a function that returns an integer. int *api[10], (*pai)[10]; declare an array of pointers to integers and a pointer to an array of integers.
In all these cases, the declaration of a variable resembles its use in an expression, the type of which is the one named at the head of the declaration.
A syntax accident contributed to the perceived complexity of the language. The indirection operator, written * in C, is a syntactically unary prefix operator, as in BCPL and B. This works well in simple expressions, but in more complex cases, parentheses are required to guide the analysis. For example, to distinguish indirection through the value returned by the function from the call, the function indicated by the pointer writes *fp() and (*pf)() respectively. The style used in expressions is declarations, so names can be declared
int *fp(); int (*pf)();
In richer, but still realistic cases, things get worse: int *(*pfp)(); - a pointer to a function returning a pointer to an integer.
There are two effects. Most importantly, C has a relatively rich set of description methods (compared, say, to Pascal). Ads in languages ββsuch as C-Algol 68, for example, describe objects equally hard to understand, simply because the objects themselves are complex. the second effect is related to the details of the syntax. C declarations must be read inside out, which many people find difficult to understand. Sethi [Sethi 81] noted that many of the nested declarations and expressions would become easier if the indirection operator was accepted as a postfix operator instead of a prefix, but by then it was too late to change.