Previous Section Main Menu Next Section

CHAPTER 9

DYNAMIC MEMORY AND POINTERS


Section II: Using Pointers Section I: Memory Allocation and the Pointer Section III: Arrays and Pointers Section IV: Strings

A. Assigning Values to Pointers
So we know that pointer variables hold memory addresses and that they point to memory locations containing some specific type. Now, how do we put the addresses into pointer variables? One thing we don't do is:

int* ptr;
ptr = 324; // wrong!!!

This would be extremely dangerous if, it were allowed. It would be saying you want to be able to access memory location 324 or, as we will see in a bit, be able to put a value into this memory location. But, what if address 324 is part of the operating system or part of your program. If you could change it, you would be changing the code for the operating system or the program, and it is most unlikely that the change would be for the better. So, we are, in general, not allowed to choose which memory locations we have direct access to. Instead, we ask the system to provide us with memory that it knows is free. We can then do what we want with that memory without worrying about possible bad effects.

C++ provides an instruction for making such a request. If you want to ask for enough memory for a double and store the address of that memory location in 'ptrDouble', you write:

double* ptrDouble;
ptrDouble = new double ;

If you want to ask for enough memory for a contract and store the address of that memory location in 'ptrContract' you write:

Contract* ptrContract;
ptrContract = new contract;

The same is true for any other pointer type.

Although 'new' was referred to above as an instruction, it really is an operator - the same as '+', '-', etc. At this point, however, that is not very important. What is important is what this 'new' operator does. When the operator is called, two things happen:

  1. The system goes out to the heap - a portion of unused memory maintained by the operating system - and requests the amount of memory required of the type to be pointed to. If enough memory is available, it is set aside and 'new' is given the address of the first byte of this allocated memory.

  2. Assuming that there is enough free memory, 'new' then returns the address of the beginning of this memory and the assignment operator places this address into the variable on the left side of the statement.

Consider again the code:

double* ptrDouble;
ptrDouble = new double ;

When the 'new' operator is called here, the system allocates enough memory for a double. Assume that the allocated memory begins with the byte address 54,366. This value is then placed in the variable 'ptrDouble' and we get the usual picture:


Often, programmers do not include the type in variable names so one might write:

char* ptr1;
ptr1 = new char;

or even:

char* ptr1 = new char;

This is legal, just as any other declaration/initialization is legal. What is not legal is, for example:

char* ptr1 = new int; // illegal

In this case, you are trying to put the address of an integer into a variable that has been declared to hold a pointer to a character. As we said above, a pointer variable can only hold the address of the type it was declared to hold.

To request enough memory for an array of some type, a slightly different form of the 'new' operator is used. Since the address returned will point to the first byte of the array, the pointer declaration remains the same. Thus, if you want a pointer to an array of integers, you can declare your pointer as:

int* arrayPtr;

The change is that you must include the size of the array in the 'new' statement. Thus, if you want to request enough memory for ten integers, you write:

arrayPtr = new int[10];

To declare and assign a pointer to twenty contracts, one could write:

Contracts* contractArray;
contractArray = new Contracts[20];

********************

There are two other ways to assign a value to a pointer. First, it is also legal to write:

ptr1 = 0;

This means that, for the moment, 'ptr1' points to nothing; it holds the null pointer. (If the 'new' operator fails in its attempt to allocate enough memory for whatever is to be pointed to, it returns the null pointer.) Later, we will see a number of uses for this null pointer value.

The third legal way to assign a value to a pointer is by assigning the value of one pointer variable to another - as long as they are both of the same type. Therefore, it is legal to write:

int* ptrInt1;
int* ptrInt2;
ptrInt2 = new int;
ptrInt1 = ptrInt2;

Now both 'ptr1' and ptr2' point to the same memory location.


This also can be quite useful as we will see.

B. Accessing Memory Via Pointers
The key to these memory address assignment rules is that we, as programmers, do not have the ability to explicitly say that we want to use memory location 'X'. However, once the system has given us a memory location to use, we can trust that it is safe, and we can pass that memory location on to other pointer variables and use it for our own purposes. The next step is to learn how to access the addresses (or memory locations) being pointed to by variables.

In the code:

int* ptrInt1;
ptrInt1 = new int;

we first declare 'ptrInt1' to be a pointer to an integer and we can think of memory as looking as shown in figure 9.5. (The question mark inside the memory cell indicates that this memory location holds garbage.)


Figure 9.5

Then we ask the system to provide enough memory to hold an integer and to assign the address of the first byte of that memory to 'ptrInt1'. Now memory can be considered to have the form:


Figure 9.6

Note how the left memory cell now contains an address. The function 'new' set aside the memory with this address and returned this address, whereupon it was stored in 'ptrInt1'. This new memory (the memory cell on the right) has not had anything placed in it yet, so it holds garbage.

To store the value five into the memory made available, we would write:

*ptrInt1 = 5;

This brings up the distinction between

ptrInt1
and

*ptrInt1

The first acts like any other variable name and refers to the memory symbolized by the variable 'intPtr1'. It, thus, refers to the box labeled "ptrInt1" in figure 9.6, the box containing the address 54366. In contrast, '*ptrInt1' refers to the address pointed to by the memory location symbolized by 'ptrInt1'. In other words, '*ptrInt1' refers to the second box in the figure.

When a system sees an asterisk followed by a variable declared to point to some type, it looks in the variable for an address and follows that address to a memory location. Therefore,

*ptrInt1 = 5;

means "Go to the memory location symbolized by the variable 'ptrInt1' and get the address stored there. Then go to the memory location with that address and put the value five in it. After this code is executed, the picture changes to:


Figure 9.7

Now consider this code:

The semantics of the last line here are as follows:

When the instructions are finished, the 5 in the memory location pointed to by ptrInt1' has been added to the 4 and the result has been placed in the memory location pointed to by 'ptrInt2'. The results are shown in figure 9.8. Notice that in this figure the memory addresses are not included. This is the way these figures should be drawn, indicating that we do not know the actual memory locations used.


This process of 'following a pointer' to get to a memory location is called dereferencing the pointer and a dereferenced pointer can be used anywhere a variable can be used. For example, consider the following code:

We will see code similar to this in a bit. For the moment, just remember that:

  1. Since pointers point to (hold the address of) memory locations that hold values of some specific type, the memory locations pointed to can be used anywhere variables can be used;

  2. To dereference a pointer is to get access to the memory location pointed to by the pointer and this in turn means that you can use the contents of that memory location or store something in it.

Topics Covered in the "Essentials of C++"

Pointers: Declarations and Accessing

Top of Section Main Menu Next Section