Section 7 - Dynamic Arrays
2A.7.1 Arrays From Pointers
Think back a short distance. We introduced pointers along side simple variables and allocated them in pairs:
float x, *fp; fp = &x;
We could use either the x or the dereferenced *fp to access the same float object. Very shortly after that, I said, "forget the float x, just declare the pointer fp" and we used the new operator to create the float dynamically:
float *fp = new float;
Well, we are at a similar crossroad. Last section we declared a bracketed array alongside a pointer and used the pointer as an alternative to the array name to access the elements of the array. Compare this to two boxes up:
float dogs[100], *dogPtr; dogPtr = dogs;
We now want to lose the dog[] array entirely. We wish to only declare the pointer and then, whenever we feel like it, dynamically allocate a block of memory for dogPtr to point to. If we can do that, we really start to see the usefulness of dynamic memory allocation. Have a look:
double *temperature; long numCities; cout << "How many cities would you like to track? "; cin >> numCities; temperature = new double[numCities];
Voila! We have an array of doubles, exactly the right size.
If the user enters 100 in response to the query, we will have 100 doubles allocated for this dynamic temperature array. This is nothing more than the dynamic allocation we saw earlier except that before we were allocating only one variable at a time:
double *dp; dp = new double;
Now, however, we are allocating a large block of variables in a single new statement:
double *temperature; temperature = new double[1000];
As with dynamic allocation of single variables, allocating a block of variables requires that we eventually delete the memory. We do this with delete:
delete[] temperature;
at some point before the entire program terminates. We use brackets here because we want to delete the entire block that temperature points to, not just one object. When you have created a dynamic array like this, use brackets with delete to free up the entire array.
Here is one example of this.
int main() { double *temperature; long numCities, k; cout << "How many cities would you like to track? "; cin >> numCities; temperature = new double[numCities]; for (k = 0; k < numCities; k++) { cout << "High in city #" << k << "? "; cin >> temperature[k]; } for (k=0; k < numCities; k++) cout << "High in city #" << k << " is " << temperature[k] << endl; // do something useful with the temperatures (omitted here) delete [] temperature; temperature = NULL; // not required but good after deleting cout << "Now how many cities would you like to track? "; cin >> numCities; temperature = new double[numCities]; // program goes on and processes this // new array ... // ... return 0; }
With output:
/* ------------------- SAMPLE RUN --------------- How many cities would you like to track? 7 High in city #0? 56 High in city #1? 35 High in city #2? 87 High in city #3? 23 High in city #4? 56 High in city #5? 87 High in city #6? 23 High in city #0 is 56 High in city #1 is 35 High in city #2 is 87 High in city #3 is 23 High in city #4 is 56 High in city #5 is 87 High in city #6 is 23 Now how many cities would you like to track? 90 ... etc.
The point is that we can release the original array and resize it to fit the new data, mid-program. This is what puts the dynamic in dynamic memory allocation.
2A.7.2 Dynamic Array of Cards
From what we learned, we can now create a dynamic array of cards:
Card *deck; deck = new Card[52];
Then we can manually set individual elements:
deck[15].set('3', diamonds);
But this would be kind of silly since we are programmers and would never think of manually setting all 52 cards. One assignment I might have given you was to come up with a main() program that set the 52 Card values as efficiently as possible. I decided it was too much fun and I wanted to do it myself. So here it is. You can see the tricks and techniques I used. There is nothing fancy going on here -- except for the dynamic allocation of the array, this is something you might have done in a previous C++ course.
See if you can understand how it works. Can you find a more efficient algorithm for setting the cards?
Card *deck; Card::Suit st; int k, j; char val; deck = new Card[52]; for (k = 0; k < 4; k++) { // set the suit for this loop pass st = static_cast<Card::Suit>(k); // or old style: st = (Card::Suit)k; // now set all the values for this suit deck[13*k].set('A', st); for (val='2', j = 1; val<='9'; val++, j++) deck[13*k + j].set(val, st); deck[13*k+9].set('T', st); deck[13*k+10].set('J', st); deck[13*k+11].set('Q', st); deck[13*k+12].set('K', st); } for (k = 0; k < 52; k++) cout << deck[k].toString() << endl; cout << endl; delete[] deck;

Here are some very interesting questions for you to ponder:
- What do we gain by using dynamic memory allocation compared to using a fixed-size array? Don't try to come up with an answer you think I want to hear, but analyze the situation and see what you find.
- What do we gain by deleting the deck just before the program ends? What would happen if we didn't? Why do you think I bothered to do it?
- Since initializing a deck of cards is such a common operation in a program like this, what should we do to make this code more re-usable? Where should such an algorithm go? It would help if you actually did what you are suggesting to see if it makes sense and is easily used by a client. This is not as simple a question as you might first think. [Big Note: This last bullet was written before I created the latest Lab Assignment #2, so I think you will all know the answers after you do the assignment.]