cs1ch9sec1.htm
 

CHAPTER 9

DYNAMIC MEMORY AND POINTERS

 


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

  


Table of Contents

Learning C++:
An Index of Entry Points


2. The

of C++

A reference document on the basic elements of C++.



3. The Patterns



Index!



A. Static and Dynamic Memory
In the last chapter we explored one way to implement a list - using arrays embedded inside a class structure. The basis of this approach was that one could use as little or as much of the array as one wanted - depending on the size of the list. But, what happens when the array fills up? In the case of the contract list, what happens when there are more than MAX_CONTRACTS contracts? If you recall, the code was written to output a warning message saying that it was not possible to add another contract.

Notice that the code outputs a 'fail' message, not when there is no more memory in the system, but when the memory set aside for the array is used up. Now we could always make the array huge, as big as RAM memory will allow, so it would be very unlikely that there would be too many contracts. However, consider a slightly more complex example. We have ten different kinds of contracts, each requiring its own list. And, we have no idea which of the lists will be large and which will be small. We can't make the arrays for all the lists huge, there is not enough memory. We are left with the ugly choice of guessing which lists will be huge and hoping we are right, or making the lists all the same size and potentially winding up in the ridiculous situation of having one list be practically empty while another is full and unable to take more contracts.

Be sure you understand the reason for this: when the program first begins, memory is set aside for each array - long before the program knows how big each array needs to be. And, once the program starts, there is no way to change the amount of memory allocated for any given array, unless one stops the program, changes the code, recompiles it, and starts again! This is an example of what we call static memory allocation, 'static' because the amount of memory allocated cannot change while the program is running.

In this chapter we are about to learn about a new kind of memory allocation - dynamic memory allocation. Using this, a program is able to request memory from the operating system as it needs it - up to the maximum amount of memory in the system. To handle the above situation, the program would start by allocating a small to medium size amount of memory for each list and then as any particular array filled up, it would ask for more memory JUST for that list. If the program was sophisticated enough, it might even look for lists that had extra room and allocate less space for them once the system as a whole ran out of memory.

B. The Pointer
To accomplish this, we need to introduce a new concept - the pointer. Remember each memory location has a unique address and that variables are really symbolic names for these memory addresses. A pointer is a memory location that contains the actual address of some other memory location, instead of containing an integer, a double, a character or the beginnings of some user-defined type

A picture might help:

Here we see two boxes representing memory locations. The box on the left, with the symbolic (variable) name 'ptrVar', contains what looks like a large integer. This integer is actually the address of the memory location represented by the second box. The arrow between the two boxes represents the idea that the address in the left hand box 'points to' the box/memory location on the right.

If we had two arrays, each pointed to by a pointer, we might have the following picture


Figure 9.2

This time, each memory location on the left points to the first memory location of an array with each array being of a different size.

Note that in both these figures, there is no variable name associated with the boxes on the right. The only way one gets to these memory locations is by 'following' the addresses (pointers) in the memory locations on the left. The memory locations on the left do have variable names associated with them and would be accessible to a program, if that program correctly declared the variables. We will see how to do so in a bit.

C. Declaring a Pointer
OK, so now you understand this at the conceptual level. It is time to get down to the details. As usual, we will start with a simpler goal - simply declaring pointers to some of the built-in types. Frankly, there is little value in doing so, but it is easier if we start this way, and it is always nice to begin slow and easy.

We know what

int x;

means to the computer - "set aside enough memory for an integer and give that memory the symbolic name 'x' ." We also know that this memory location initially contains garbage.

Above, we saw that a value that might look like an integer is interpreted differently if it is declared as a pointer. To declare a variable that is to hold a pointer to an integer, we write:

int* ptr;

The '*' is the new part. What this means to the computer is, "Set aside enough memory for a pointer to an integer and give that memory the symbolic name 'ptr'." In other words, whenever the system works with 'ptr', it knows that the contents of 'ptr' is not simply an integer but is an integer acting as a memory address.

One important point in C++ is that pointers point to a memory location holding a value of some specific type. Consider these declarations:

int* ptrInteger;     'ptrInteger' holds the address of a
                            memory location containing an integer;

double* ptrDouble; 'ptrDouble' holds the address of a memory location containing a double;

char* ptrChar; 'ptrChar' holds the address of a memory location containing a character;

Contract* ptrCont; 'ptrCont' holds the address of a memory location containing a contract;

This means, for example, that 'ptrInteger' can NOT point to a memory location containing a double.

In chapter two we said that each type takes up its own amount of memory. Thus characters might take up one byte, integers two bytes, doubles four bytes. The amount of memory required by a contract is a bit more complex, but it takes up at least the amount required for each of the individual data members in a contract. And, an array of 20 contracts will take up 20 times the memory required for one contract. 

The point (a pun?) of this is that, when it says above that some variable "holds the address of a memory location containing a ...", what it really means is that the variable holds the address of the first byte of the memory used for whatever type is being pointed to. That is one reason why a variable acting as a pointer must point to a specific type. The system needs to know how many bytes to handle as part of the data being pointed to.

Top of Section Main Menu Next Section