The common C convention is to write T *p
, whereas the common C++ convention is to write T* p
. Both parse as T (*p)
; the *
is part of the declarator, not the type specifier. It's purely an accident of pointer declaration syntax that you can write it either way.
C (and by extension, C++) declaration syntax is expression-centric; IOW, the form of a declaration should match the form of an expression of the same type in the code.
For example, suppose we had a pointer to int
, and we wanted to access that integer value. To do so, we dereference the pointer with the *
indirection operator, like so:
x = *p;
The type of the expression *p
is int
; thus, it follows that the declaration of p
should be
int *p
The int-ness of p
is provided by the type specifier int
, but the pointer-ness of p
is provided by the declarator *p
.
As a slightly more complicated example, suppose we had a pointer to an array of float
, and wanted to access the floating point value at the i
'th element of the array through the pointer. We dereference the array pointer and subscript the result:
f = (*ap)[i];
The type of the expression (*ap)[i]
is float
, so it follows that the declaration of the array pointer is
float (*ap)[N];
The float-ness of ap
is provided by the type specifier float
, but the pointer-ness and array-ness are provided by the declarator (*ap)[N]
. Note that in this case the *
must explicitly be bound to the identifer; []
has a higher precedence than unary *
in both expression and declaration syntax, so float* ap[N]
would be parsed as float *(ap[N])
, or "array of pointers to float
", rather than "pointer to array of float
". I suppose you could write that as
float(* ap)[N];
but I'm not sure what the point would be; it doesn't make the type of ap
any clearer.
Even better, how about a pointer to a function that returns a pointer to an array of pointer to int
:
int *(*(*f)())[N];
Again, at least two of the *
operators must explicitly be bound in the declarator; binding the last *
to the type specifier, as in
int* (*(*f)())[N];
just indicates confused thinking IMO.
Even though I use it in my own C++ code, and even though I understand why it became popular, the problem I have with the reasoning behind the T* p
convention is that it just doesn't apply outside of the simplest of pointer declarations, and it reinforces a simplistic-to-the-point-of-being-wrong view of C and C++ declaration syntax. Yes, the type of p
is "pointer to T", but that doesn't change the fact that as far as the language grammar is concerned *
binds to the declarator, not the type specifier.
For another case, if the type of a
is "N-element array of T", we don't write
T[N] a;
Obviously, the grammar doesn't allow it. Again, the argument just doesn't apply in this case.
EDIT
As Steve points out in the comments, you can use typedefs to hide some of the complexity. For example, you could rewrite
int *(*(*f)())[N];
as something like
typedef int *iptrarr[N]; // iptrarr is an array of pointer to int
typedef iptrarr *arrptrfunc(); // arrptrfunc is a function returning
// a pointer to iptrarr
arrptrfunc *f; // f is a pointer to arrptrfunc
Now you can cleanly apply the T* p
convention, declaring f
as arrptrfunc* f
. I personally am not fond of doing things this way, since it's not necessarily clear from the typedef how f
is supposed to be used in an expression, or how to use an object of type arrptrfunc
. The non-typedef'd version may be ugly and difficult to read, but at least it tells you everything you need to know up front; you don't have to go digging through all the typedefs.