I’ve recently decided that I just have to finally learn C/C++, and there is one thing I do not really understand about pointers or more precisely, their definition.
How about these examples:
int * test;
int * test,test2;
Now, to my understanding, the first three cases are all doing the same: Test is not an int, but a pointer to one.
The second set of examples is a bit more tricky. In case 4, both test and test2 will be pointers to an int, whereas in case 5, only test is a pointer, whereas test2 is a “real” int. What about case 6? Same as case 5?
4, 5, and 6 are the same thing, only test is a pointer. If you want two pointers, you should use:
int *test, *test2;
Or, even better (to make everything clear):
int* test; int* test2;
White space around asterisks have no significance. All three mean the same thing:
int* test; int *test; int * test;
int *var1, var2” is an evil syntax that is just meant to confuse people and should be avoided. It expands to:
int *var1; int var2;
Use the “Clockwise Spiral Rule” to help parse C/C++ declarations;
There are three simple steps to follow:
Starting with the unknown element, move in a spiral/clockwise
direction; when ecountering the following elements replace them with
the corresponding english statements:
: Array X size of… or Array undefined size of…
(type1, type2): function passing type1 and type2 returning…
*: pointer(s) to…
- Keep doing this in a spiral/clockwise direction until all tokens have been covered.
- Always resolve anything in parenthesis first!
Also, declarations should be in separate statements when possible (which is true the vast majority of times).
Many coding guidelines recommend that you only declare one variable per line. This avoids any confusion of the sort you had before asking this question. Most C++ programmers I’ve worked with seem to stick to this.
A bit of an aside I know, but something I found useful is to read declarations backwards.
int* test; // test is a pointer to an int
This starts to work very well, especially when you start declaring const pointers and it gets tricky to know whether it’s the pointer that’s const, or whether its the thing the pointer is pointing at that is const.
int* const test; // test is a const pointer to an int int const * test; // test is a pointer to a const int ... but many people write this as const int * test; // test is a pointer to an int that's const
#include <type_traits> std::add_pointer<int>::type test, test2;
As others mentioned, 4, 5, and 6 are the same. Often, people use these examples to make the argument that the
* belongs with the variable instead of the type. While it’s an issue of style, there is some debate as to whether you should think of and write it this way:
int* x; // "x is a pointer to int"
or this way:
int *x; // "*x is an int"
FWIW I’m in the first camp, but the reason others make the argument for the second form is that it (mostly) solves this particular problem:
int* x,y; // "x is a pointer to int, y is an int"
which is potentially misleading; instead you would write either
int *x,y; // it's a little clearer what is going on here
or if you really want two pointers,
int *x, *y; // two pointers
Personally, I say keep it to one variable per line, then it doesn’t matter which style you prefer.
In 4, 5 and 6,
test is always a pointer and
test2 is not a pointer. White space is (almost) never significant in C++.
The pointer is a modifier to the type. It’s best to read them right to left in order to better understand how the asterisk modifies the type. ‘int *’ can be read as “pointer to int’. In multiple declarations you must specify that each variable is a pointer or it will be created as a standard variable.
1,2 and 3) Test is of type (int *). Whitespace doesn’t matter.
4,5 and 6) Test is of type (int *). Test2 is of type int. Again whitespace is inconsequential.
You can think of 4, 5, and 6 as follows:
declaring the type only has to be done once, but if you want to declare a pointer to that type (by adding an asterisk) you have to do so for each variable.
When declaring a pointer variable, I always add whitespace between the variable and asterisk, even if I’m declaring more than one in a line. Not doing so makes me confuse it for a dereferencing expression nearly every time.
A good rule of thumb, a lot of people seem to grasp these concepts by: In C++ a lot of semantic meaning is derived by the left-binding of keywords or identifiers.
Take for example:
int const bla;
The const applies to the “int” word. The same is with pointers’ asterisks, they apply to the keyword left of them. And the actual variable name? Yup, that’s declared by what’s left of it.
The rationale in C is that you declare the variables the way you use them. For example
*a will be a
a a char pointer. And thus
a is an array of char pointers.
This because the original compiler writers wanted to use the same parser for expressions and declarations. (Not a very sensible reason for a langage design choice)
I would say that the initial convention was to put the star on the pointer name side (right side of the declaration
in the c programming language by Dennis M. Ritchie the stars are on the right side of the declaration.
by looking at the linux source code at https://github.com/torvalds/linux/blob/master/init/main.c
we can see that the star is also on the right side.
You can follow the same rules, but it’s not a big deal if you put stars on the type side.
Remember that consistency is important, so always but the star on the same side regardless of which side you have choose.
Cases 1, 2 and 3 are the same, they declare pointers to int variables. Cases 3, 4 and 5 are the same, as they declare one pointer to, and one int variable respectively. If you want do declare two pointers in one line (which you shouldn’t), you need to put an asterisk in front of each variable name:
int *test, *test2;
There is no certain correct way that says where the asterisk goes.
int* test looks better because it is easier for us to imagine that appending
* to the end of a type means “pointer to” that type. However,
int *test makes more sense, because you can work with it like the minus sign in maths:
-(-x) = x
is analogous to
*(*test) = test
This has always helped me. Sadly, the upshot of it all is that sometimes I use
int* test and sometimes