A crash course in pointers

OK, so a crash course on pointers. This will be a long email. But it’s at least a month worth of classes crushed into a couple of pages.

A pointer is a variable literally pointing to an address (any address) in memory.

for instance:

int nVar = 12; //This is a regular variable!
int * pVar = 0; //This is a pointer variable!

the variable nVar contains a the number 12. This is located somewhere in the heap. It doesn’t matter where. We don’t really care. nVar is an integer an can only take things that are 4 bytes on size.

the variable pVar is a pointer. This is a variable that takes an address, any address! However, it expects that the address will point to an integer (that bit is important). Right now, it’s just a zero, meaning that it’s not pointing to anything at all. It’s empty, and sad…

we know pVar is a pointer, and takes an address. So we can give it an address:

pVar = &nVar; //now pVar is pointing to nVar.

If you remember & gets the address of a variable. So we’re giving pVar, the addresss to nVar. This is important… We’re not giving pVar the number 12. We’re just telling pVar where 12 is located. In other words, if you tried to do a cout on pVar, you would not get 12. Instead, you’ll see something like: 0x0025fe. If you went inside your computer, and went to this place in memory, you’d see 12 there.

This presents a problem. You know where something is, but sometimes you point to something and want to know the value! Knowing where 12 is, is pretty useful, but what if you wanted to know what nVar minus 5 is and you only had the address.

That’s when dereferencing comes into play. Dereferencing is a way to tell the pointer to give you the value of the address it has. In other words, It’s asking google, who lives at 4275 Solar Circle? This is accomplished by putting a star right before the variable.

int newVar = 0; //Lets create a new variable
newVar = *pVar; //newVar is now 12!

There is something even more interesting than this… How about if i have the address to nVar, and want to change the value of nVar?

cout << “The value is: ” << nVar << endl; //”The value is: 12″
*pVar += 5;
cout << “The new value is: ” << nVar << endl; //”The new value is: 17″

Why? Well, I went into the address for nVar, and changed the value. nVar is still pointing to the same location. That never changed. But now I changed the value of that specific box.

Enter Arrays:

Arrays, as we talked, are just addresses to a location. So what makes them different from pointers?

int arrayVar[4]; //arrayVar is an address to a place that can contain 4 integers.
int *pVar; //pVar is an address to a location.

The difference is very succinct. The different lies in that an array is pointing to a location which has a specific number of slots allocated, while a pointer is pointing to any location. It doesn’t care about size either, which is what makes them great when you’re allocating memory dynamically! No longer are you held back by that ugly 4… If you need more space, just ask for it!

int *pVar = new int[whatever]; //and by whatever, i mean 3000 if i want!

This is called, dynamic memory allocation. That “new” keyword means: “give me a brand new location where i can store this many items”. It’s then allocated for you on the fly and will stay in memory for as long as you tell it to. However, the rules for arrays still apply. After all, arrays are just pointers. So pointers are also just arrays. What if i need index 4?

pVar[4] = 15; //Lets put a 15 in the 4th space!
cout << “Index 4: ” << pVar[4] << endl; //Show me what’s in index 4 -> “Index 4: 15″

So why i didn’t dereference it here? Well, the answer is fairly simple. Remember how a pointer is just an address that expects something the size of the data type? the brackets [] are actually a function in a sense. They say quite literally “move this many positions”. But how does it know how far to move… after all, what if I have a array of very large objects! 4 bytes wouldn’t be enough. how far each step is, is defined by the data type (int in this case).

Now when you see arrayVar[0], you get the first element because you never moved from the first location! You moved zero steps. Equally with the pointer. pVar[4] is asking the pointer to tell you what’s contained 4 steps ahead. Each step the size of the data type (int in this case). Now, I lied, it doesn’t move in reality. Notice that i said “to tell you what’s contained 4 steps ahead”. That’s because the pointer is still pointing at the beginning of the array. It’s just “pretending” to move, so it can tell you what’s in the location you asked.

So, what if you moved ahead for reals?

pVar += 4; //oh no… What’s going to happen?

First, notice that I didn’t dereference the point. This time, i’m actually moving the address. This is a little deceptive. I’m not moving the address 4 locations. It’s not going from 0×000001 to 0×00004. The answer is above. When i move, the pointer moves each step the distance of the data type. In this case, the data type is int which is 4 bytes. So the address goes from 0×000001 to 0×000017 (4 steps by 4 bytes). You can go ahead and check it out if you feel ever so skeptical.

Even more interesting is this… I moved 4 steps, so where exactly am I?

cout << “My value is: ” << pVar[0] << end; //”My value is: 15″

What?! Well, think about it. pVar[4] value is 15. So instead of peaking using brackets [], I actually moved to the location and got the first index.

Now, the fancy math is very dangerous, so DO NOT use it, unless you know what you’re doing. Otherwise, kaboom goes the system! Stick with the brackets. After all, you just want to know what’s ahead. You don’t need to change the location.

Finally and before the grand finale, it brings us to dereferencing a pointer or an array. The answer by now should be fairly obvious. You don’t need to dereference a pointer when you’re using it as an array. After all, arrays are just pointers, and pointers can be arrays.

Lastly, and perhaps more important than any other thing: Uncle Ben once told me while driving to the library: “With great power comes great responsibility”. He got killed by a robber shortly after… This lesson cannot be any truer with pointers. Pointers are addresses to locations. So when you allocate memory dynamically (using the “new” keyword), it’s then allocated for you on the fly and will stay in memory for as long as you tell it to.

pVar = new int[3000]; //I created a new array for 3000 elements.
pVar = new int[2]; //I create another array of 2 elements.

This is bad! Why? Because you first allocated a big array, and then a small one. But what’s the big deal? you might think. Well, that big array is still in memory. Some where. Just waiting to be used, discarded, or something. Anything! It won’t disappear until you told it to. Even worse… You just lost the address to it because you allocated a new one! You don’t even know where this huge “memory leak” is at. Congratulations, you have ruined your computer forever… Or until you turn it off since the stack memory is wiped out.

But the lesson to be learned is important. Doing this is bad. You need to be responsible with memory. It’s not free, it’s not safe, and needs to be managed carefully.

pVar = new int[3000]; //I created a new array for 3000 elements.
delete [] pVar; //and thus, i release thee from my memory.
pVar = 0; // and this for good measure to indicate it’s empty. Do it! don’t be lazy!
pVar = new int[2]; //and new life is reborn.
delete [] pVar; //Ashes to ashes, and so on.
pVar = 0; //you’re ready to rise again… like a phoenix!

May the force, be with you…

Comments are closed.