In fact, there is an authoritative source: "The Development of the C Language" by the creator of the language, Dennis M. Ritchie :
A syntax accident contributed to the perceived complexity of the language. The indirection operator, written * in C, is syntactically a unary prefix operator , as in BCPL and B. This works well in simple expressions, but in more complex cases, brackets are required to direct the parsing. For example, to distinguish indirection from the value returned by a function from calling a function indicated by a pointer, *fp() and (*pf)() written, respectively. The style used in expressions is transferred to declarations, so names can be declared
int *fp(); int (*pf)();
In richer, but still realistic cases, things get worse:
int *(*pfp)();
is a pointer to a function that returns a pointer to an integer. There are two effects. Most importantly, C has a relatively rich set of ways to describe types (compared to, say, Pascal). For example, language declarations such as C-Algol 68 describe objects that are difficult to understand, simply because the objects themselves are complex. The second effect is related to syntax details. Ads in C should be read inside out, which many people find difficult to understand [ Anderson 80 ]. Sethi [ Sethi 81 ] noted that many nested declarations and expressions would become easier if the indirection operator was taken as a postfix instead of a prefix, but by then it was too late to change.
So the reason * is on the left in C is because it was on the left in B.
B was partially based on BCPL , where the dereference operator was ! . It was on the left; binary ! was an array index operator:
a!b
is equivalent to !(a+b) .
!a
- the contents of the cell whose address is given by a; he may appear to the left of the assignment.
However, the 50-year-old BCPL manual does not even mention operators ! , instead, the operators were words: unary lv and rv . Since they were understood as if they were functions, it was natural that they preceded the operand; later, a long rv a could be replaced with syntactic sugar !a .
Using this route, you can track many of the current practices of operator C. B had a[b] equivalent to *(a + b) to *(b + a) to b[a] , as in BCPL, you can use a!b < => b!a .
Please note that the B variables are untyped, so, of course, the similarity with the declarations could not be the reason for using * on the left there.
Thus, the reason for the unary * on the left in C is just as boring as "there was no problem with simpler programs with the unary * on the left in a position in which everyone is used to having an dereference operator in other languages ββthat no one I thought that in some other way it would be better until it was too late to change it. "