|< Free Open Study >|
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:
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.)
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 - α
takes the address of alpha and stores it into intPointer. If alpha is at address 33, memory looks like this:
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:
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:
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.
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.
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.
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.
The second statement copies the value in money into myMoney, giving the following configuration:
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:
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.
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!
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 ; char* alphaPtr; char* letterPtr; void Process(char ); . . alphaPtr = alpha; letterPtr = &alpha; Process(alpha);
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.
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.
|< Free Open Study >|
|Converted from CHM to HTML with chm2web Pro 2.85 (unicode)|