5

Both of the following are valid pointer declarations in C/C++:

int *x;
int* x;

The former seems to be preferred by seasoned C/C++ programmers. I personally find the latter to be easier to understand - it illustrates that pointer-ness is a factor of the variable's type, not its name. Furthermore, this unifies stylistically the declaration of pointers and functions returning pointers:

int* foo(); //foo returns an int*
int* x;     //x is an int*
int *foo(); //generally unused (in my experience)
int *x;     //feels wrong in this context

int *x seems counter-intuitive despite being the norm, so I feel I must be overlooking something.

What motivates syntactic preference regarding pointer declaration in C/C++?

Conduit
  • 159
  • 6
  • To me it's usually the latter with C++ devs, same with `int& x` instead of `int &x`. The reasoning is usually because there's a stronger emphasis on types in C++, and so C++ developers often want to look at `int*` as one indivisible thing -- a completely different data type from `int` with a different interface. Also helps to keep it uniform when you want to do like `vector` as opposed to `vector`. –  Dec 08 '17 at 03:53
  • @DrunkCoder Yeah! That's the conclusion I came to after reading some of the answers on the questions this was dupe-closed to. C: `int *x` - what's the int? \*x. C++: `int* x` - what's x? an int\*. – Conduit Dec 08 '17 at 04:02
  • I've settled on the latter style but started with the former in C, following K&R style originally... then worked with a bunch of C++ colleagues doing the latter way and that rubbed off on me after a while. It would be so much easier if, say, `int* x, y` defined two pointers instead of one pointer and one integer. That's really confusing when you want to think of `int*` as like an indivisible thing. That said, I got used to a coding standard where it was forbidden to define more than one variable per line. –  Dec 08 '17 at 04:06
  • `T *ptr;` reflects how the grammar actually works - the `*` is part of the declarator, not the type specifier. It’s the same reason we don’t write `T[N] array;` or `T() func`. Pointer-ness, array-ness, and function-ness are specified in the declarator. You can write `T* p` or `T *p` or `T * p` or even `T*p` - they will all be *parsed* as `T (*p)`. – John Bode Dec 13 '17 at 13:42
  • Secondly, this style only works for simple object pointers - it won’t work for array or function pointers - `T (*ap)[N]`, `T (*fp)(...)`, `T (*afp())[M]`, etc. Think about the prototype for the [signal](http://pubs.opengroup.org/onlinepubs/009695399/functions/signal.html) function, and how you would apply the `T*` convention to it cleanly (it would require at least one `typedef`, which, IMO, obscures more than it clarifies). – John Bode Dec 13 '17 at 13:52

1 Answers1

5

Both forms have exactly the same syntax. They differ only by spacing arrangements.

The first form is preferred because it reflects well the semantic: the pointer is only for the variable that immediately follows the star:

int *p, a; // p is pointer, a is plain int

The second form could be misleading, because it gives the impression that the pointer belongs to the type and would be applicable for all the variables in the same statement:

int* p, a; // still, only p is pointer, a is plain int despite impressions
Christophe
  • 74,672
  • 10
  • 115
  • 187
  • As a matter of style I never declare variables in this way for precisely the reasons you stated. – Robert Harvey Dec 07 '17 at 17:47
  • 1
    I agree with this answer for C, however, I'd point to this on Bjarne Stroustrup's page for C++ http://www.stroustrup.com/bs_faq2.html#whitespace – Ben Cottrell Dec 07 '17 at 17:58
  • @BenCottrell interesting point. However despite Stroustrup's preference for the emphasis on type, he did not change the syntactic precedence rules, because he wanted to stay as much compatible with the C heritage as possible (see his book "Design and evolution of C++"). So his style is not in line with semantic. Later, when template got introduced into the language, Stroustrup didn't either introduce a std::raw_ptr which would have had the advantage of type emphasis AND consistency with precedence, while preserving the heritage. Certainly because it's only a style question. – Christophe Dec 07 '17 at 18:18
  • I wasn't aware of that - good reasoning – Conduit Dec 07 '17 at 18:19
  • @RobertHarvey I fully agree ! One declaration per statement. And anyway, who needs raw pointers when we have containers, move semantics and smart pointers ? Nevertheless I didn't find a shorter way to explain the semantic issue related to the grammatical rule. Ultimately, it's just a question of style. But there's lot of legacy code out there that remains to be maintained with mixed styles, so I really wanted to make this semantic point to draw attention on this source of errors. – Christophe Dec 07 '17 at 18:29
  • @Conduit your edit has also some good points. Actually all the examples in the original K&R use the style `int *foo();` . The unix or posix function definitions also use this convention ([example](http://man7.org/linux/man-pages/man3/calloc.3.html) and [example](http://pubs.opengroup.org/onlinepubs/9699919799/) ). Many third party library also (ex: [SQLlite](https://www.sqlite.org/c3ref/column_blob.html, or even QT both for the few functions returning pointer, but also for all pointer arguments). But the most important is to be aware of the semantic. In the end it's only a style issue. – Christophe Dec 07 '17 at 19:01
  • That just feels odd to me - `int *foo()` looks like it *really* wants to be `int (*foo)()`, though I know it isn't. Looking at the linked questions it appears this is mainly due to a shift in perspective that occurred when C++ focused attention more heavily on variables' types... C: `int *x` - what's the int? \*x. C++: `int* x` - what's x? an int\*. Similar for functions: `int *foo()` whats the int? *foo(). – Conduit Dec 07 '17 at 19:22
  • @Conduit I can assure you that if you're used to it, this appears so natural that you wouldn't dream of writing something else. But as with human language, we tend to get used and comfortable with the styles that we've learned first or read most. Questions of style are also question of taste. Myself for example tend to use `int&` instead of `int &`, because this syntax didn't exist in C for declaration, and I've learned C++ from Stroustrup's book who used `int&`. Furthermore `&variable` was wired in my brain to the address operator of C's expressions. – Christophe Dec 07 '17 at 20:12