I’ve always been a fan of introducing new ideas through already perceived metaphors and logical equivalences. I find it easier relating to something one already knows, instead of forcing a yet unknown terminology onto the listener. So I am going to practice what I preach. I am going to try and convince you that pointers in low level computer languages aren’t as bad as they seem.
When students encounter the word “pointer” along with some pictures of stack implementation and lots of arrows, loaded with hex codes, it might intimidate more than it is supposed to. The concept in and of itself is quite simple, but it sometimes takes a while to get used to. We’ll try demystify what confused me, as a novice programmer and some other CS students that I’ve talked with.
So let’s play a game. If you’ve ever watched an episode of “Doctor Who”, you might be familiar with the “TARDIS”. It looks like a police phone booth from the outside. But when you open its door and step inside, the small cabin turns into a huge room full of engines and stuff. So, lets imagine something like the “TARDIS”. But instead of a phone booth we shall imagine a small box. A box no larger than a shoe box. Even better, a lot of small boxes. When you open the box and reach in, you might pull something much bigger than what the actual volume of the box might hold.
For example – I give you, the reader, a box with a small note on it which says “AIRPLANE!”. When you try to reach in and pull something out, BAM – you pull out an entire airplane! A full size Boeing 787!
Now, lets make a simple dictionary. Suppose you want to insert some object into a box. But the game is made for lazy people. Instead of writing the object’s description on the box, you should actually write a unique ID assigned to it. So, the dictionary is actually the set of IDs, matched with different object descriptions.
To make things clearer, let’s continue with the example provided above. So you received a box with a note. Instead of the note having
"AIRPLANE!" written on it, it will have
"0x1" written on it. And, the accompanying dictionary will have the following entry:
"0x1" is actually "AIRPLANE!".
Good. Now we’ve explained the rules of the game to the fullest. What is the objective you might ask? Pass other players objects as efficiently as possible. For instance, if you need to pass another player a single pen – it might be more efficient to pass the pen itself instead of putting it in a box and then passing it. This is because the pen is a lot smaller than the box you have and it makes no sense to use more space than necessary. But, if you have to pass another player a full size car, it might be more efficient to put it inside that magic box to save some space.
We shall write some basic C-like code to associate our game to something more concrete. Suppose we have a dedicated type for our object we want to pass. Let’s just call them – “Objects” (how convenient and original?). So, to declare what box you are going to use, and what the box is going to contain you might write something like the following:
Briefly explained –
Object* says that we initialized a new box (pointer – to be exact), containing an object of some sort. If you want to be more specific, you might even replace it with
Airplane*. Why the asterisk? That is just so you’d know that
airplane is not a real airplane, but rather a box containing one. The value of
airplane however, is that same unique ID we’ve talked about earlier.
To access what’s inside the box you might want to use
*airplane in context to our example above. This is the same as “opening the box and reaching in” as described earlier. However, to replace the object inside the box with another, you write something like seen in line 1 of the code snippet above.
Nevertheless, if you try and assign something to
airplane (mind the small asterisk is missing), you actually replace what is written on the box – which is the ID of the object behind it. But by doing so, you replace the content of the box with that assigned to the unique ID you’re replacing it with, according to the dictionary. You see, replacing the unique ID of the box doesn’t just change the ID. It also changes what you get when trying to “reach in and pull out” the object from the box.
So, in our little example in line 2 of the code above, we changed the ID of
airplane to be
0x152. Suppose that we had an entry in our dictionary that said:
"0x152 is actually "A GOAT!". What we’ve done is make the box itself point (you see the analogy now?) to another object, which is in our case – a goat.
(The box now points to another object, according to the assigned ID)
So now, when trying to access
*airplane what we actually get is not a huge real-life airplane, but a smaller rather cuter goat. It might seem confusing that
*airplane is now something else that isn’t an airplane. It is indeed, something you need to take into consideration when changing the pointer of the box.
In technical terms, our box is actually called a “pointer” and what is written on the box is called the “address” of the pointer. When accessing the object behind the pointer, this is called “dereferencing” the pointer. Furthermore, pointers provide no compression services whatsoever. It might seem intuitive through the analogies used above that somehow the pointer “shrinks” the data being passed. This is not the case with pointers, and one might claim that this is where the described analogy fails. They just point to something else, as the name suggests – so keep that in mind.
Consequently, if you want to pass an object to someone else, or pass an object to some function, it should be clear by now that it is much more efficient to do so by using a pointer. The larger the object, the more efficient the usage. There are other reasons to pass pointers to functions instead of copies of the objects themselves – however these reasons are outside the scope of this article.
If you want to elaborate some more on this topic – ask yourself what would happen if a pointer points to another pointer. Better yet, what a pointer pointing to another data structure containing multiple pointers will look like?
To summarize, I hope these examples clear a bit of the initial confusion of trying to grasp pointers and how to use them in C. If you encounter any confusions, have a question or have any suggestions please contact me via email or twitter.