A double pointer is nothing more than a pointer to another pointer. It’s possible to continue this pattern indefinitely having pointers to pointers to pointers, and so on. But you’ll rarely need more than a double pointer.
Previous episodes explained how you can use pointers to either point to a group of items or to individual items within a collection. Now you’ll learn how to use a pointer that points to another pointer.
Let’s say we have two items: ItemA and ItemB and they both live somewhere in memory. It doesn’t matter where or in what order they are to each other.
Now you have a pointer to each of them called pItemA and pItemB and for these pointers, you do want them positioned in a certain order. If you want ItemA to come before ItemB, then put pItemA in front of pItemB. Pointers are small and can be moved around in memory very easy. Maybe a lot easier than trying to move the actual ItemA and ItemB themselves.
Now that you have your two pointers to the items positioned in memory one right next to the other, you can refer to them both with another pointer. We’ll create another pointer called pItemCollection and make it point to whichever of the item pointers is first. In this case, pItemCollection will point to pItemA.
So far, you should be able to understand this if you take it one step at a time. It will help if you draw it on paper. Use boxes for each of the items and for each of the pointers and use arrows from each pointer that goes to whatever it points to.
The difficult part comes when trying to understand how to call a method that can modify your pItemCollection pointer. You can’t pass the pointer directly to the method because then it will get its own pointer value that also points to pItemA. So what you need to do is provide the method with the address of where your pItemCollection pointer lives in memory so that it can change it directly. You pass the address of something with another pointer.
We’ll talk about this again when I explain methods.
Listen to the full episode or you can also read the full transcript below.
Why would you ever need a double pointer in the first place? The example in episode 8 seems to solve everything already, right? I mean, you’ve got a bunch of items each sitting at some row and shelf address and by themselves, they are completely unorganized so that they can make the best use of available space. They used to be organized but as new shipments arrived, the items were put on shelves that had room. They were kept together at least but there is no longer any relation from one group of items to the other groups sitting to the left and right. All of this is okay because you use pointers to organize what would otherwise be a mess.
Imagine walking into Home Depot and finding light bulbs next to the concrete which is next to a refrigerator. And not even all the refrigerators, just one type. To browse all the refrigerators, you would have to walk back and forth through the whole warehouse.
The only reason the previous example worked at all is because there is no need to organize the items for direct customer browsing. The unorganized layout constantly changes and the only thing that brings it under control is the stack of index cards. The stack of index cards is organized for quick and efficient searching.
But I still haven’t described double pointers yet. I’m getting to that right now. Let’s say that this system works so well that the inventory grows and so does the stack of index cards. In fact it’s no longer just a stack of index cards. They occupy a large box and this box is getting too big to fit on your desk. You need to find someplace to keep the box of index cards when it’s not being used so why not use one of the empty shelves for this too. You soon discover though that just like the other items get moved around on the shelves sometimes your box of index cards gets in the way and also needs to be moved. So to remember where you last put the index cards, you decide to write down the location on another index card which you will keep with you at your desk.
You’ve just created a pointer to your box full of other pointers.
That’s a double pointer.
It’s quite useful really. Especially when other people need access to the box of pointers. When it’s time for you to go home, you can hand the single double pointer index card to the next person taking over your duties. And when you come back the next day and the other person returns your double pointer card, you know it will have the current location of the box of other item pointers. Even it it’s been changed. After all. that was the whole point.
As useful as this seems, in the normal course of programming, there’s another situation that’s also very common and maybe even more useful. It’s kinda similar to what I just described but I want to explain this scenario with the same warehouse that we’ve been talking about.
Let’s imagine it’s time for inventory. You’ve found that for whatever reason, it sometimes helps to just get rid of your box of index cards and start over. Since you’ve got this down to a system now, you don’t have to be the one walking through each row and recording and counting items anymore. In fact, everything’s gotten so much bigger because of your system that one person can’t do the job anymore. So once a year, you hire a group of several people to do this work. You can’t really help prepare an empty box either because you don’t even know how big of a box will be required. So you just give your single index card to one of the workers with the instructions to find an appropriate box that will hold the new recorded index cards and then find a place for the box on a shelf somewhere. Wherever the new box is placed, the workers are to record its location on the double pointer index card and return it to you.
Now how does this map to programming?
There will be times when you need to call a method that will help you create something. The problem is that you don’t know ahead of time where the method will find room in memory for the new object. Just like how the workers found a new box and a new location for the box. So what you do is create a single pointer to the new object type and set the pointer to point to null. That means you don’t really have this object yet. You only have a pointer that might eventually point to the object type you want. Then when you call on the helper method, you give the helper method a pointer to your single null pointer. The helper method creates the new object and gets it ready for your use, then stores the location of the newly created object in your single null pointer. This means your null pointer is no longer a null pointer but now points directly to the new object. The helper method can do this because you told it where to find your single pointer by giving it another pointer to your single null pointer. When the method finishes, all you have to do is look at your original null pointer and check if it still points to null. If it’s not null, then that’s where your new object lives in memory. If it’s still null, then you know that something went wrong and can take corrective action.
You might be wondering why at this point. That seems like an awful lot of extra steps to go through. It is and if you need to rewind and listen again, then go ahead. I know it’s easy to get lost. That’s why I described the scenario with the inventory workers preparing a new box of pointer cards. The helper method plays a similar role by creating an object for you and letting you know where in memory it placed the new object. But why not just have the helper method directly return the address of the new object that it created using the method return value? Sure you can do that and then you don’t need a double pointer.
Double pointers aren’t always needed because normally, you’ll have other options like using the return value. But what if you need the return value for another purpose? That’s when you need a double pointer. Because that’s when your only option is to provide information to the method. You can’t provide your single pointer directly because of the way methods will make a copy of anything you pass to them.
I know, we haven’t talked about methods yet. A lot of programming concepts are related to each other and it would be too much information to try to explain it all in one episode. But there’s also no clear line between each topic so sometimes, I’ll need to partially explain something and then come back to it later from a different angle. This is one of those times. If you want to come back to this episode after you learn more about methods, then you might get more understanding that you’re missing now.
You see, when you call a method, you can provide extra information if the method was written that way to require extra parameters. And the method can return to you a single value through its return value. Any extra parameters that you provide are your own and are off limits to the method. So when you want a method to be able to change your pointer, your can’t pass the pointer itself. You have to pass another pointer that points to your pointer. It’s the double pointer that’s now off limits but that’s okay because changing the double pointer is not the goal. The double pointer just tells the method where it can find the actual pointer. Once the method knows where to find the actual pointer, then it has the ability to update that pointer to point to the address of the newly created object.
Before ending this episode, I’d like to also say that trying to explain the concept of a double pointer through audio only is really demonstrating how difficult it is to program in English or any other spoken language. The precision just isn’t there. Using diagrams or actual programming examples is much better. This is one of the more difficult episodes. So let me know if you have any questions and I’ll explain further.