Previous Section
 < Free Open Study > 
Next Section

4.3 Pointer Types

Logical Level

Pointers are simple-not composite-types, but they allow us to create composite types at run time. We describe the creation process, accessing function, and one use of pointers in this chapter. In Chapter 5, we discuss another use in detail and use pointers in alternative implementations of the abstract data types defined in Chapters 3 and 4.

A pointer variable does not contain a data value in the ordinary sense; rather, it contains the memory address of another variable. To declare a pointer that can point to an integer value, you use the following syntax:

int* intPointer;

The asterisk (*) as a postfix symbol on the type says that the variable being defined is a pointer to an object of that type: intPointer can point to a place in memory that can contain a value of type int. (Alternatively, the asterisk may serve as a prefix symbol on the variable name.) The contents of intPointer, as with all newly defined variables, are undefined. The following diagram shows memory after this statement has been executed. (For illustrative purposes, we assume that the compiler has allocated location 10 to intPointer.)

Click To expand

How do we get intPointer something to point to? One way is to use the prefix & operator, which is called the address-of operator. Given the declarations

int alpha;
int* intPointer;

the assignment statement

intPointer - &alpha;

takes the address of alpha and stores it into intPointer. If alpha is at address 33, memory looks like this:

Click To expand

We have a pointer, and we have a place to which the pointer points, but how do we access that place? An asterisk (*) as a prefix to the pointer name accesses the place to which the pointer points. The asterisk is called the dereference operator. Let's store 25 in the place to which intPointer points.

*intPointer = 25;

Dereference operator An operator that, when applied to a pointer variable, denotes the variable to which the pointer points

Memory now looks like this:

Click To expand

Because intPointer points to alpha, the statement

*intPointer = 25;

represents indirect addressing of alpha; the machine first accesses intPointer, then uses its contents to find alpha. In contrast, the statement

alpha = 10;

involves direct addressing of alpha. Direct addressing is analogous to opening a post office box (P.O. Box 15, for example) and finding a package, whereas indirect addressing is analogous to opening P.O. Box 15 and finding a note telling you that your package is sitting in P.O. Box 23.

A second method for getting intPointer something to point to is called dynamic allocation. In the previous example, the memory space for both intPointer and alpha was allocated statically (at compile time). Alternatively, our programs can allocate memory dynamically (at run time).

Dynamic allocation Allocation of memory space for a variable at run time (as opposed to static allocation at compile time)

To achieve dynamic allocation of a variable, we use the C++ operator new, followed by the name of a data type:

intPointer = new int;

At run time, the new operator allocates a variable capable of holding an int value and returns its memory address, which is then stored into intPointer. If the new operator returns the address 90 as a result of executing the preceding statement, memory looks like this:

Click To expand

Variables created by new reside on the free store (or heap), a region of memory set aside for dynamic allocation. A dynamically allocated variable has no name and cannot be directly addressed. It must be indirectly addressed through the pointer returned by new.

Free store (heap) A pool of memory locations reserved for dynamic allocation of data

Sometimes we want a pointer to point to nothing. By definition in C++, a pointer value of 0 is called the null pointer; it points to nothing. To help distinguish the null pointer from the integer value 0, <cstddef> contains the definition of a named constant NULL that we use instead of referring directly to 0. Let's look at a few more examples.

bool* truth = NULL;
float*  money = NULL;

When drawing pictures of pointers , we use a diagonal line from the upper right to the lower left to indicate that the value is NULL.

Click To expand

Let's examine memory after a few more pointer manipulations.

truth = new bool;
*truth = true;
money = new float;
*money = 33.46;
float* myMoney = new float;

When drawing pictures of pointers and the objects to which they point, we use boxes and arrows.

Click To expand

Any operation that can be applied to a constant or a variable of type int can be applied to *intPointer. Any operation that can be applied to a constant or a variable of type float can be applied to *money. Any operation that can be applied to a constant or a variable of type bool can be applied to *truth. For example, we can read a value into *myMoney with the following statement:

std::cin >> *myMoney;

If the current value in the input stream is 99.86, then *myMoney contains 99.86 after the execution of the preceding statement.

Pointer variables can be compared for equality and assigned to one another as long as they point to variables of the same data type. Consider the following two statements:

*myMoney = *money;
myMoney = money;

The first statement copies the value in the place pointed to by money into the place pointed to by myMoney.

Click To expand

The second statement copies the value in money into myMoney, giving the following configuration:

Click To expand

At this point, the location that holds the second copy of 33.46 cannot be accessed; no pointer points to it. This situation is called a memory leak, and the memory cells that can no longer be accessed are called garbage. Some programming languages, such as Java, provide garbage collection; that is, the run-time support system periodically goes through memory and reclaims the memory locations for which no access path exists.

Memory leak The loss of available memory space that occurs when memory is allocated dynamically but never deallocated

Garbage Memory locations that can no longer be accessed

To avoid memory leaks, C++ provides the operator delete, which returns to the free store a memory location allocated previously by the new operator. This memory may then be allocated again if necessary. The following code segment prevents our memory leak:

delete myMoney;
myMoney = money;

The location originally pointed to by myMoney is no longer allocated. Note that delete does not delete the pointer variable, but rather the variable to which the pointer points.

Click To expand

Notice the difference between assigning one pointer to another (myMoney = money) and assigning the pointed-to locations (*myMoney = *money). Always be careful to distinguish between the pointer and the object to which it points!

Application Level

Have you passed an array as a parameter? If so, you have used a pointer constant. The name of an array without any index brackets is a constant pointer expression-namely, the base address of the array. Look at the following code segment:

char alpha [20];
char* alphaPtr;
char* letterPtr;
void Process(char []);
alphaPtr = alpha;
letterPtr = &alpha[0];

Here alphaPtr is assigned the constant pointer expression alpha; letterPtr is assigned the address of the first position in the array alpha. alphaPtr and letterPtr both contain the address of the first position in the array alpha. When the prototype for the function Process says that it takes a char array as a parameter, it means that it expects a pointer expression (the base address of the array) as an actual parameter. The calling statement, therefore, sends the name of the array without any index brackets to the function.

Pointers can be used with other composite types as well.

struct MoneyType
  int dollars;
  int cents;
MoneyType* moneyPtr = new MoneyType;
moneyPtr->dollars = 3245;
moneyPtr->cents = 33;

The arrow operator (->) provides a shortcut for dereferencing a pointer and accessing a struct or class member. That is, moneyPtr->cents is shorthand for (*moneyPtr) .cents. (The dereferencing operator has lower precedence than the dot operator, so the parentheses are necessary.)

In Chapter 5, we will use the idea of a pointer pointing to a variable of a composite type in which one of the data members is a pointer to another variable of the same composite type. Using this technique, we can build linked structures. One named pointer acts as the external pointer to the structure, and the structure is chained together by having a data member in each variable in the chain act as a pointer to the next one in the chain. The last variable in the chain has NULL in its pointer member.

Implementation Level

A pointer variable simply contains a memory address. The operating system controls memory allocation and grants memory to your program on request.

Previous Section
 < Free Open Study > 
Next Section
Converted from CHM to HTML with chm2web Pro 2.85 (unicode)