Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations TouchToneTommy on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

Complete Layman's Guide to Pointers

Pointers

Complete Layman's Guide to Pointers

by  qednick  Posted    (Edited  )
I decided to write this FAQ because I have answered this same question a few times now (the latest time I spent about 45 minutes writing my response to a student only to discover the student's post red-flagged the day after!). Hopefully, this FAQ will make pointers a little clearer and help students to understand them without running the risk of making a "homework" related post and getting that post red-flagged.

Pointers are one of the most powerful features of C and C++. Unfortunately, they are also one of the hardest things to learn and understand about these languages. Hopefully, I can throw some light on the subject for anyone who is serious about learning C/C++ from a layman's perspective.

What is a pointer?
A pointer is not really a tangible object like your regular run-off-the-mill variables such as [tt]int[/tt] and [tt]double[/tt], etc. A pointer is simply an address in memory where a variable is stored.
Picture this scenario: you create a simple program in C/C++ and declare a single [tt]int[/tt] which stores a value. That int will [usually] make your program use an extra 4 bytes of random access memory (RAM). Therefore, the more variables you declare in your program, the more RAM your program needs to keep running.
By declaring that [tt]int[/tt] in the program, your computer allocates those 4 bytes of RAM to your program. Those 4 bytes in memory is where your program stores the value of the [tt]int[/tt]. While that [tt]int[/tt] variable is valid (ie. in 'scope' within a function), your program will keep that unique memory address linked to your [tt]int[/tt]. Once the [tt]int[/tt] goes out of scope (eg. at the end of the function containing it), those 4 bytes of memory are then released and can be re-allocated to other variables your program may declare.

Now that you understand about your program's memory, it's time to answer the first question: a pointer is an item that 'points' to a certain address in memory. Knwoing this address means that you can retrieve the 'real' value of the original item that the memory was allocated for in the first place.

How do I use a pointer?
Taking our [tt]int[/tt] example one step further, let's examine a short program:[tt]

int main(void)
{
[color red]// declare an int and set a value[/color]
int someInt = 18;

[color red]// declare an int 'pointer'[/color]
int* somePtr = NULL;

[color red]// set out pointer to point to the
address in memory of someInt[/color]
somePtr = &someInt;

[color blue].. <- check value of somePtr here with debugger![/color]

return (0);
}[/tt]

In the above simple example, we first declare out [tt]int[/tt] and give it a value of 18. We then declare an [tt]int[/tt] pointer by using the 'splat' operator (as I like to call it!). This operator after a variable type name declares the type to be a pointer rather than the actual type itself.
Notice also the ampersand '&' we placed before [tt]someInt[/tt] when we were allocating the address of [tt]someInt[/tt] to [tt]somePtr[/tt]. Placing the ampersand before an object like this is like saying "this is the address in memory of this object - not the value of the object".
One more thing to notice is that when we declared ourr pointer, we allocated a value of [tt]NULL[/tt] to it. The [tt]NULL[/tt] means "address zero" (a 'none address') in computeresque! It is usually a very good idea to "initialize" your pointers to NULL when you declare them if you're not using them immediately! Otherwise, it could be certifiable very bad thing!

What the 'point' in using pointers?
Many beginners (and many Java coders) will be asking this question. Why use pointers at all when you pass the objects themselves as parameters and so? Well, one simple example for use of pointers is that you can only [tt]return[/tt] one value from a function:[tt]

int swapValues(int a,int b)
{
int temp = a;
a = b;
b = temp;
[color red]// <- return a or b here???????[/color]
}[/tt]

You can see from this simple example that we successfully 'swap' the values of [tt]a[/tt] and [tt]b[/tt] but we reach a stumbling block when it comes to the return value. We can only return 1 value from the function!

By using pointers, we could swap the two values in a separate function without having to return anything at all! For example:[tt]

int main(void)
{
int a = 27; [color red]// declare our ints and
int b = 53; // assign values

// now call our 'swap' function[/color]
swap(&a,&b);

[color red]// <-check values of a and b here with debugger! [/color]

return (0);
}

void swap(int* x,int* y)
{
int temp = *x;
*x = *y;
*y = temp;
}[/tt]

The first thing to notice is that we used the ampersand '&' sign before the variable names when we passed to our [tt]swap[/tt] function. This is because our [tt]swap[/tt] function is expecting the parameters to be 'pointers' (or the addresses in memory) of [tt]int[/tt]s.
You can see by looking at the parameters of the [tt]swap[/tt] function that this is, indeed, the case because the parameter types are followed by the 'splat' symbol (ie. [tt]int*[/tt]).
However, look inside the function and you'll notice something rather perculiar. We use the 'splat' symbol before the two parameters to get the 'real' value of the two [tt]ints[/tt]! Using this method, we successfully swap over the real values of the two variables.

We do not need a [tt]return[/tt] statement. This is because we are using 'pointers' to objects rather than the real objects themselves. We can do this because the 'real' original [tt]ints[/tt] still exist in memory in the calling function (in this example the calling function is [tt]main[/tt]).

Try pasting the above code into your compiler and you will see that the values are in fact 'swapped' after the call of the function [tt]swap()[/tt].

So why are pointers so powerful?
The above example is just one simple method of using pointers. In the real world, programmers will use pointers to all kinds of objects, structures and classes. You can even use pointers to functions and pass those as parameters - for example, as a "call back" type function.
A prime example of pointer use is in Window messaging. If you've ever come across the Windows API functions [tt]PostMessage()[/tt] or [tt]SendMessage()[/tt] you will have noticed two extra parameters you can use called wParam and lParam. These two parameters are basically [tt]void*[/tt] (void pointers) and this enables you to pass complete structures, objects, text strings or anything you like from one window to another without the need for global variables. This means you can do all this without the memory (RAM) requirements you would otherwise need. It also makes your code look neater!

Another classic example is the Windows call [tt]AfxBeginThread()[/tt] - because a separate thread/process cannot share objects you need to pass in pointers to "prime" the thread with the information necessary. In this case, you first pass the name of the thread function you have written to handle the thread and then you pass a [tt]void*[/tt] of some structure you have created to pass into the thread the information required to control it:[tt]

struct myThreadStruct
{
char str[100];
bool exitThread;
};

void SomeFunction(void)
{
[color red]// our structure is already declared
// somewhere else (needs to be in scope!)
// but let's initialize the values so we can
// retrieve them within our thread function[/color]
strcpy(myInfo.str,"qednick is cool!");
myInfo.exitThread = false;

[color red]// my info, by the way, is an object of
// type myThreadStruct[/color]

[color red]// spawn a thread here[/color]
CWinThread* myThread = ::AfxBeginThread(myThreadFunct,(LPVOID)&myInfo);
}

[color red]// here's the definition of the myThreadFunct function[/color]
UINT myThreadFunct(LPVOID lp)
{
[color red]// use a typecast to turn the pointer back
// to type myThreadStruct*[/color]
myThreadStruct* info = (myThreadStruct*)lp;

[color red]// we can use our myThreadStruct pointer
// (called "info") to retrieve or even change the
// values in the original object "myInfo"[/color]
while(!info->exitThread)
{
printf(info->str);
printf("\n");
}

[color red]// in this case, the thread will print
// "qednick is cool!" all over your screen - how fitting![/color]

return (0);
}[/tt]

The thread example is incomplete but it shows how you can pass in a pointer (of any kind) as a parameter and then retrieve it or change it at the other end through the use of typecasting.
We also note something else interesting in our thread function - the [tt]->[/tt] operator. This is the pointer dereferencing operator. Usually, when you decalre a structure such as our [tt]myThreadStruct[/tt] struct, you access and/or change it's member's values using the '.' (period) operator like so:[tt]

myInfo.exitThread = false;[/tt]

When you are using a 'pointer' to the structure, you use the dereferencing operator in place of the period like this:

[tt]myInfoPtr->exitThread = true;[/tt]

Summary
So there you have it - a layman's guide to C/C++ pointers. You've learned what a pointer is (an address in RAM or memory), what the syntax is (the splat, ampersand and dereferencing operator) and you've also learned a couple of small examples as to why pointers are so useful. :)
Register to rate this FAQ  : BAD 1 2 3 4 5 6 7 8 9 10 GOOD
Please Note: 1 is Bad, 10 is Good :-)

Part and Inventory Search

Back
Top