SI204 Class 26: Combining What We Know

Lecture

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 (in class examples: grades and grades using functions)

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 other words 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:

         Add the ability to get a student number from the user and return the student's homework average.

         Add the ability to get a homework assignment number from the user and return the class average on that assignment.

         Add the ability to ability to read in a file like namedgrades.txt, which gives a last name for each student, and return student scores by name rather than number.

 

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. Your code only needs to call srand() one time.  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.      tic-tac-toe


Assoc Prof Christopher Brown

Last modified by LT M. Johnson 10/23/2007 08:59:49 AM