Arrays of any type

We can store any type of object we like in an array. We've seen ints, doubles, strings, etc. already. We could choose something more exotic, like ofstreams, even! For example, imagine a situation where we'd like a program that reads a list of file names from the user, creates those files, and then takes a sentence he types and writes it to each of those files. Can we do this? Well, let's try the following strategy:

  // Get number of files, call it N
  int N;
  cout << "Enter number of files: ";
  cin >> N;

  // Create an array of N ofstreams
  ofstream *FILE = new ofstream[N];
Now we have a problem, FILE points to M objects of type ofstream, but how do we tell each ofstream object what file they should point to? I mean usually we tell the object what file it should point to at the same time it is created, as in:
ofstream OUT("temp.txt");
When we create arrays of objects using new, those objects are uninitialized, so we have to go through and initialize each one individually. In this case, that means opening a file for each ofstream object. To do this, we need to use .open() to attach a stream to a file. For example, we can create OUT as above in this way:

ofstream OUT;
OUT.open("temp.txt");
In the case of our array, we can read in names and initialize this way:

cout << "Please enter " << N << " filenames: ";
for(int j = 0; j < N; j++)
{
  string s;
  cin >> s;
  FILE[j].open(s.c_str());
}
Having done this, we can write whatever we want to all the files, like this:

for(int k = 0; k < N; k++)
  FILE[k] << "Hello file number " << k << "!!!" << endl;    
You can take a look at this complete program that writes a sentence to a whole list of files.

Multi-dimensional Arrays

Since we can have arrays of any type of object, why not an array of arrays? For example, suppose we have a class of 10 students, each with 10 homework grades, and the grade info is stored in a file grades.txt. I might want to read in the data and store it, so that I can then answer questions for the user - questions like how did student 6 do on homework 3?

Clearly, I'd like an array of 10 objects, each object representing all the homework grades for a given student. But what type of object can I use to store the 10 homework grades that correspond to a given student? An array of 10 ints, of course! So, each object in my array of students is itself an array of ints, i.e. each object is an int*. Remember, we create an array of 10 objects of type T like this:
T* array = new T[10]
So, if the type of object that gets stored in the array is int*, we create our array like this:
int** array = new int*[10];
Now, having done that, we have an array full of uninitialized pointers, in otherwords we have an array of pointers that don't yet point to anything! Thus, for each of these 10 pointers we must allocate an array for them to point to! Remember, array[i] is an object of type int*. So wherever you see array[i] just think of it as being a normal old pointer:

int** array = new int*[10];
for(int i = 0; i < 10; i++)
  array[i] = new int[10];
What gets created and how you index elements in it are depicted in this diagram:

This is how you can create "multi-dimensional" arrays in C++. You just have arrays of arrays! Okay, now let's read the grade information and store it in our 2-dimensional array:


ifstream IN("grades.txt");
for(int s = 0; s < 10; s++)
  for(int g = 0; g < 10; g++)
    IN >> array[s][g];
With this, I can get the grade for student stu on homework assignment hwa as array[stu][hwa]. This program is a simple one that reads the grade info and allows the user to ask questions about grades. This version makes nice use of functions, and gives you an idea of how we pass multi-dimensional arrays around for this sort of thing. Here are three extensions of the functionality of this program you might like to consider:

Destroying Multidimeninsional Arrays

As we've mentioned before, arrays allocated with new live on until the end of your program, or until deleted with the delete [] command. With mutli-dimensional arrays, you have to remember to delete each array you created. That means, if we refer back to the grades problem from above, that all of the arrays pointed to by the elements of the array grade must be deleted before we can delete the array grade itself.

  for(int k = 0; k < 10; k++)
    delete [] grade[k];
  delete [] grade;

The rand() Function

Quite often in programming you need random numbers. How this is done is a science in and of itself, but the standard library cstdlib contains a function rand() that you can use. It returns a random int in the range 0,....,RAND_MAX, where RAND_MAX is a variable defined in cstdlib. So, if you need to print out 10 random numbers in the range [0,1], you could do the following:
    
  for(int i = 0; i < 10; i++)
    cout << double(rand())/RAND_MAX << " ";
  cout << endl;
If I run this, I get:

0.513871 0.175726 0.308634 0.534532 0.94763 0.171728 0.702231 0.226417 0.494766 0.124699
Unfortunately, if I run it again, I get the same sequence of numbers! As a matter of fact, every time I run it, I get the same 10 "random" numbers! The problem is this, the computer doesn't generate random numbers. Instead, it has a long sequence of numbers that it generates, which looks more or less random - i.e. there is no discernable pattern. But every time I run my program, I just start over again with that same sequence. To combat this, you can call srand(), which seeds the random number generator. Essentially, when you give srand a seed, it uses the seed to pick a starting point in this sequence of "random" numbers. With different starting points each time you run the program, you appear to be getting different sequences of random numbers. Typically, you use the time() function from ctime to seed your random number generator. Since the time changes each time you run the program, you should get different sequences of "random" numbers. The following program shows how this all works:

#include <cstdlib>
#include <ctime>
#include <iostream>
using namespace std;

int main()
{
  // Seed the random number generator based on the time
  srand(time(0));

  // Print out 10 random numbers in the range [0,1]
  for(int i = 0; i < 10; i++)
    cout << double(rand())/RAND_MAX << " ";
  cout << endl;

  return 0;
}

Problems

  1. Picking random teams. The file names.txt contains a list of names (the number of names is given on the first line of the file). Read those names in, and get from the user a number of teams to be made from those names. The number of teams must evenly divide the number of names. The program should randomly assign names to teams, and display the result. Here is a sample run of the program.
    ~/$ ./ex1
    There are 24 people.
    How many teams would you like? (make it evenly divide n) 3
    Team 0: Mike Dan Chris Joni Christy Seung-Geol Cathy Susan
    Team 1: Gavin Nate Paul Adina Jeff Carl Karen Eric
    Team 2: Phong Betty Madeline Marianne Don Shirley Tim Steve
  2. tic-tac-toe