Contents  1-5  6-11  12-16  17-21  22-27   28-33  34 - 38  39-46  Projects   MFC

   Contact
   Search
   C
   C++
   Visual Basic
   Java
   JavaScript
   DHTML
   Style Sheets
   About
   Active X
   TDC Binding
   PHP
   Perl and CGI
   Flash
   XML
   SQL
   Messages
   Chat
   MCSE
   Linux
   Cabling   
   ActionScript
   Downloads
   E-Cards   
 
    
    


Note: Updated!  See top of introduction page c1.html for using a C++ .Net compiler for these standard C++ tutorials.

Pointers are a special type of variable that holds a memory address.  They are some of the most powerful tools in C++,
as they allow you to manipulate computer memory directly.  Every variable of every type is located at a unique location
in an address.  Pointers hold the addresses of objects in memory.
  To kick this lesson off, I highly recommend that you
watch the Binky Pointer Fun Video created by our beloved programming brethren at Stanford.  Simply click the link: 
Binky Pointer Fun Video .

"Reality is merely an illusion, albeit a very persistent one." - Albert Einstein

Some pointer basics:

  •  A "pointer" stores a reference to another variable, sometimes known as its "pointee".  The pointer points to the variable's address in memory.  Alternately, a pointer may be set to the value NULL which encodes that it does not currently refer to a pointee.
  • The dereference operation on a pointer accesses its pointee.  A pointer may only be dereferenced after it has been set to refer to a specific pointee.  A pointer which does not have a pointee is "bad" and should never be dereferenced, but initialized to "NULL".
  • A pointer which does not have an assigned pointee is "bad" and should not be dereferenced.  Doing so can crash the program or corrupt the data held within memory - these are common bugs to fix when using pointers.  A pointer without a pointee must be assigned the value of NULL.  Java does this for the programmer, but in C++ it needs to manually be done.

Address of operator - Note: Usually you don't need to know the particular address of any variable, but you can get it using the address of operator - &.  Example:

// The address of operator and addresses of local variables
#include <iostream.h>

int main()
{
    unsigned short ShortVariable=5;
    unsigned long LongVariable=65535;
    long SignedVariable = -65535;

    cout << "ShortVariable:\t" << ShortVariable;
    cout << "Address of ShortVariable:\t" << &ShortVariable << "\n";
 

    cout << "LongVariable:\t" << LongVariable;

    cout << " Address of LongVariable:\t" << &LongVariable << "\n";
 

    cout << "SignedVariable:\t" << SignedVariable
         << " Address of SignedVariable:\t"
         << &SignedVariable << "\n";

    return 0;
}

Output:
ShortVariable: 5        Address of ShortVariable: 0x8fc9:fff4
LongVariable: 655535    Address of LongVariable: 0x8fc9:fff2
SignedVariable: -65535       Address of SignedVariable: 0x8fc9:ffee

To declare a pointer, place an * before the variable name.   Example:   int *AgePointer = 0;
This says that *AgePointer is a pointer to an int and set up to hold an address.  *AgePointer is initialized to 0.

null pointer - a pointer that is initialized to 0.
wild pointer - a pointer that is not initialized is dangerous.  If you don't know what you want to assign to the pointer, assign 0 and make it null.

If you make *AgePointer a null pointer by initializing it to 0, you must specifically assign the address of HerAge to *AgePointer.   Using the address of operator "&" assigns the address.   Example:

unsigned short int HerAge = 25;            //make variable
unsigned short int *AgePointer = 0;        //make pointer
AgePointer = &HerAge;                      //assign AgePointer's address to HerAge

You could also write:

unsigned short int HerAge = 25;                  //make a variable
unsigned short int *AgePointer = &HerAge;        //make pointer and assign it

Indirection - Indirection refers to accessing the value at the address held by a pointer,  the pointer provides an indirect way to get a value held at an address.   This allows passing by reference rather than value.  We can avoid making an extra copy of the object.
 
Indirection operator - The asterisk, " * ",  used with pointers is known as the indirection operator.  It is also called the dereference operator when it is used the second time.  When a pointer is dereferenced, the value at the address stored by the pointer is retrieved rather than its address.  Let me rephrase that this operator is used in 2 distinct ways:  declaration vs. dereference.  When a pointer is declared, the "*" indicates it is not a normal variable.  When a pointer is dereferenced, however, the indirection operator indicates the value at the memory location stored in the pointer is to be accessed rather than the memory address itself.  

A pointer provides indirect access to the value of the variable whose address it stores.  To assign the value of HerAge to yourAge by way of the pointer AgePointer:

unsigned short int HerAge = 25;           //make variable
unsigned short int *AgePointer = 0;       //make pointer

AgePointer = &HerAge;

unsigned short int YourAge;
YourAge = *AgePointer;
               //copies value of HerAge to YourAge

The indirection operator "*" means "the value stored at".  The assignment says "Take the value stored at the address in AgePointer and assign it to yourAge."  Once a pointer is assigned the address of a variable you can use that pointer to access the data of that variable.   Example:
 

#include <iostream.h> 
typedef unsigned short int USHORT; 

int main()   { 

     USHORT MyAge;                            //a variable 
     USHORT * AgePointer = 0;                 //a pointer   
     MyAge = 5; 
     
     cout << "MyAge: " << MyAge << "\n"; 

     AgePointer = &MyAge;                     //assign address of MyAge to AgePointer 

     cout << "*AgePointer: " << *AgePointer << "\n\n";    //dereference the pointer
     cout << "*AgePointer = 7\n"; 

     *AgePointer = 7;                         //sets MyAge to 7 

     cout << "*AgePointer: " << *AgePointer << "\n"; 
     cout << "MyAge: " << MyAge << "\n\n"; 
     cout << "MyAge = 9\n"; 

     MyAge = 9; 

     cout << "MyAge: " << MyAge << "\n"; 
     cout << "*AgePointer: " << *AgePointer << "\n"; 

     return 0; 
} 
Output:
MyAge: 5
*AgePointer: 5
*AgePointer = 7
*AgePointer: 7
MyAge: 7
MyAge =9
MyAge: 9
*AgePointer: 9

Pointers enable you to manipulate addresses without ever knowing their real values. When you assign the address of a variable to a pointer it has the address of that variable as its value:

#include <iostream.h> 

typedef unsigned short int USHORT; 

int main() 
{ 
     unsigned short int MyAge = 34;
     unsigned short int YourAge = 21;

      //Declare pointer and assign it to address of MyAge 
     unsigned short int *AgePointer = &MyAge;  
  
     cout << "MyAge:\t" << MyAge << "\tYourAge:\t" << YourAge << "\n"; 
     cout << "&MyAge:\t" << &MyAge << "\t&YourAge:\t" << &YourAge <<"\n"; 
  
     cout << "AgePointer:\t" << AgePointer << "\n"; 
     cout << "*AgePointer:\t" << *AgePointer << "\n"; 
  
     //Reassign the pointer to another variable's address 
     AgePointer = &YourAge;   
  
     cout << "MyAge:\t" << MyAge << "\tYourAge:\t" << YourAge << "\n"; 
     cout << "&MyAge:\t" << &MyAge << "\t&YourAge:\t" << &YourAge <<"\n"; 
  
     cout << "AgePointer:\t" << AgePointer << "\n"; 
     cout << "*AgePointer:\t" << *AgePointer << "\n"; 
  
     cout << "&AgePointer:\t" << &AgePointer << "\n"; 

     return 0; 
} 
Output:
MyAge: 34       YourAge: 21
&MyAge: 0x355C      &YourAge: 0x355E
*AgePointer: 34
  
MyAge: 34
&MyAge: 0x355C      &YourAge: 0x355E
AgePointer: 0x355E
*AgePointer: 21
&AgePointer: 0x355A

Like any other variable, a pointer has an address that can be stored in another pointer, assigning the address of a pointer to another pointer.  In effect, it becomes something which points to something which points to something else.   Remember:

1) Use the indirection operator "*" to access the data stored at the address in a pointer.
2) Initialize all pointers to a valid address or to null (0).
3) Remember the difference between the address in a pointer and the value at that address.

Pointers are used most often for:

1) Managing data on the free store

2) Accessing class member data and functions
3) Passing variables by reference to functions instead of value

There are 5 Areas of Memory:

1 - Global name space (stores global variables)
2 - The free store (the heap, massive memory)
3 - Registers (internal housekeeping functions, keeping track of top of stack and instruction pointer)
4 - Code space (stores code)
5 - The stack (stores local variables and function parameters)

The problem with local variables is that they don't persist.  When functions return they are thrown away.  Global variables remain available but at the cost of hard to read and maintain code.  Placing data in the free store solves both of these problems.

Free store - The free store is a massive section of memory where thousands of tiny cubby holes lie waiting for data.  You can't label them as you can with the stack.  You must ask for the address of the cubby hole that you reserve and then stash that address address away in a pointer. The pointer gives you access to your data without bothering you with the details.  The stack is cleaned automatically when a function returns and local variables go out of scope.  The free store is not cleaned until your program ends. 

On the free store, y
ou must free any memory you have reserved when you are done with it. The advantage of the free store is that the memory you reserve remains available until you explicitly free it.  If you reserve memory on the free store while in a function the memory is still available when the function returns.  This is better than using global variables because only functions with access to the pointer have access to the data.  This provides a tightly controlled interface to the data and prevents a renegade function from changing and manipulating the data in unexpected ways.  For this to work you have to create a pointer to an area on the free store and pass that pointer among functions.

new - This keyword allocates memory on the free store (heap).  Followed by the type of object you want to allocate so the compiler knows how much memory is required.  The return value from new is a memory address and must be assigned to a pointer:

unsigned short int *APointer;
APointer = new unsigned short int;

Or you could initialize the pointer at its creation:

unsigned short int *APointer = new unsigned short int;

APointer now points to an unsigned short int on the free store.  You could assign a value into that area of memory by writing:

*APointer = 72;

This means "Put 72 at the value in APointer" or "Assign the value 72 to the area on the free store to which APointer points".  If new cannot create memory on the free store or none is available it returns the null pointer.  You must check your pointer for null each time you request new memory.

delete - returns memory to the free store.  The pointer itself is a local variable aside from the memory to which it points.  When the function declaring the pointer returns it goes out of scope and the pointer is lost.  The memory allocated with the pointer is not freed automatically, it becomes unavailable.  The memory becomes unavailable in a memory leak.  The "delete" command restores memory to the free store.   Example: delete APointer;

When you delete the pointer you are freeing the memory whose address is stored in the pointer.  You are saying "Return to the free store the memory that this pointer points to".  The pointer is still a pointer and it can be reassigned.  Be careful not to call "delete" on a pointer twice, it will crash the program.  When you delete a pointer, you should set it to null (0).  Calling delete on a null pointer is guaranteed to be safe:

Animal *pDog = new Animal;
delete pDog;                      //frees the memory
pDog = 0;                         //sets pointer to null
delete pDog;                      //now harmless

Allocating and deleting a pointer:

#include <iostream.h> 

int main()  { 

     int LocalStackVariable = 5; 
     int *StackPointer= &LocalStackVariable; 
     int *HeapPointer = new int;         //HeapPointer set up and points to new int on heap

     if(HeapPointer == NULL)  { 
        cout << "Error! No memory for HeapPointer!!"; 
        return 1;  }
 
     *HeapPointer = 7;
 
     cout << "LocalStackVariable: " << LocalStackVariable << "\n"; 
     cout << "*StackPointer: " << *StackPointer << "\n"; 
     cout << "*HeapPointer: " << *HeapPointer << "\n"; 

    delete HeapPointer; 
   
    HeapPointer = new int; 

    if(HeapPointer == NULL) { 
       cout << "Error! No memory for HeapPointer!!"; 
       return 1;  }
  
    *HeapPointer = 9; 
    cout << "*HeapPointer: " << *HeapPointer << "\n"; 

    delete HeapPointer; 

    return 0; 
} 

Output:
LocalStackVariable: 5
*StackPointer: 5
*HeapPointer: 7
*HeapPointer: 9

Memory leaks - Another way leaks are created is by reassigning your pointer before deleting the memory to which it points.   Example:

1 - unsigned short int *APointer = new unsigned short int;
2 - *APointer = 72;
3 - APointer = new unsigned short int;
4 - *APointer = 84;

Line 1 - creates APointer and assigns it address of an area on the free store. 
Line 2 - stores the value 72 in that area of memory.
Line 3 - reassigns APointer to another area of memory.
Line 4 - places value of 84 in that area. The original area that now holds 72 is unavailable because the pointer to that area of memory has been
             reassigned.  There is now no way to access that original area of memory, nor is there any way to free it until the program ends.  It has
             become a memory leak. 
It should have been written like:

unsigned short int *APointer = new unsigned short int;
*APointer = 72;
delete APointer;
APointer = new unsigned short int;
*APointer = 84;

In Summary:

  • Remember that for every time you call new, you should call delete in your programs.

  • Keep track of which pointer owns an area of memory and ensure that it is returned to the free store when you are done with it. 

  • Be careful not to call delete twice.

  • Set freed pointers to NULL.


©2004 C. Germany