|C Pointer Declaration And Dereferencing|
|Written by Harry Fairhead|
|Monday, 20 July 2015|
Pointers and pointer declarations in C cause beginners all sorts of strange problems that experienced C programmers find hard to understand. It all possibly comes from one small misunderstanding.
How it starts
When you are first learning C, or C++ for that matter, you generally encounter something like:
right at the start of your journey to be a programmer. You think of this as declaring an integer variable myint.
Soon after this is generalized to:
which you think of as declaring two integer variables.
This results in the pattern:
A little while later you learn about pointers and the address and dereference operator.
is the address of myvariable i.e. it is where myvariable is stored.
is the value stored at the address in mypointer.
That is it is the value in the location mypointer "points" at.
Notice that the value of mypointer is the address, but the value of *mypointer is what mypointer points at.
However, at about the same time you learn all of this you are also learning that you have to declare a pointer something like:
This declares a pointer to an integer type and there is a tendency to think that int* is a type - a pointer to int.
As a result the next step is to try something like;
which clearly, by the slightly wrong rules we have inferred, declares two pointers to int.
With this in mind the beginner tries:
and discovers an error message saying something like
"cannot convert from type int* to int".
Now this is mysterious because often, but not always, even the error message says that we have a type of int*.
So why is the declaration wrong?
What is going on?
* is always an operator
Beginners are often told to just treat the declaration of a pointer differently from everything else using something like:
"the asterisk binds to the variable not the type"
- and I have no idea what this means.
The simplest way to think about it is not to think in terms of type at all, but consider the dereferencing operator always acting as the dereferencing operator.
When you write:
you dereference the pointer and what you have is therefore an int.
to be an int it is obvious that myintpointer has to be a pointer and it has to be a pointer to an int.
Simple and perfectly logical.
This is a declaration that *myintpointer is an int.
As we have just worked out this means that myintpointer has to be a pointer to an int.
You don't have think about the dereferencing operator in any way that is different in a declaration - the declaration is simply giving the type of the variable after it has been dereferenced.
Now you can work out what
means without any need to invoke special cases. Declarations are still always of the form
only now you can apply allowed operators to the variables before they are assigned their type.
In other words:
declares that *myvar1 is an int and myvar2 is an int.
This is what the explanation that "the asterisk binds to the variable" is trying to tell the beginner, but not quite succeeding.
You can, of course write things like;
and so on and all of the things you are declaring are ints, but two of them are only ints after dereferencing.
This also brings us to expressions like:
Now we know it is clear that this is stating that **myvar is an int. So *myvar has to be a pointer to int and myvar has to be a pointer to a pointer to an int. And, of course, we can now write things like:
and so on and know that they are all ints but only after the indicated number of dereferencing.
Pushing on a little, this point of view (pun almost intended) helps with the dreaded const qualifier.
Easy, it is a declaration of a constant int and if you try to assign to it after the initial assignment in the declaration then your program will not compile. That is
will generate a compile time error.
Now what is:
As before, you are declaring that *myvar2 is a constant int.
So myvar2 has to be a pointer to a constant int.
That is, the int is constant but the pointer isn't. The pointer can change and point to something else but the thing it points at can't be changed via the pointer.
This means that:
is fine, but
There is a subtlety here that is worth making clear. The pointer to a constant int can be set to point at a non-constant int. For example:
is perfectly fine.
The fact that the pointer is to a constant int simply stops you from writing:
All declaring a pointer to a constant type does is to stop you changing something via a pointer dereference - there may be other legal ways to change the something.
It has to be admitted that different compilers react differently to any attempt to change a constant variable so you need to be careful.
Also, notice that you can write:
and they mean the same thing - that *myvar is a constant integer.
However, if you move the dereferencing operator you get a very different result.
Here things are almost as logical and we read this as myvar is a constant and *myvar is an int. Notice that the pointer now cannot change, but the value of the int it points at can.
is fine because the value 3 is stored in myvar2, which isn't constant, and myvar1 points at myvar2 i.e. is constant throughout the program.
is not allowed.
Finally, if you can stand it, what does:
The answer is that this is constant pointer to a constant integer. That is, *myvar1 is a constant int and myvar1 is a constant pointer.
You can't do
as that would change the pointer; and you can't do:
because that would change the int it is pointing at.
Once again, it is worth pointing out that you can still modify values if you use the variable directly rather than the pointer.
is legal because myvar2 isn't a constant int.
In other words if you have a pointer then either the thing the pointer points at can be constant, the pointer can be constant or both the pointer and the thing it points at can be constant.
To be informed about new articles on I Programmer, install the I Programmer Toolbar, subscribe to the RSS feed, follow us on, Twitter, Facebook, Google+ or Linkedin, or sign up for our weekly newsletter.
or email your comment to: firstname.lastname@example.org
|Last Updated ( Wednesday, 15 June 2016 )|