CIT020 Index > Lecture Notes - Chapter 3

Chapter 3

for loops

The while and do loops are meant for indeterminate loops; ones where we don’t know how many times the program will have to do the loop body. In, in the “Guess My Number” program, we have no idea how many guesses the player will need. for loops, on the other hand, are used for counting, when we know exactly how many times we want the loop body to be performed.

The book’s examples declare a counter variable in the initialization step of the loop.

for (int i=0; i < 10; ++i)

Why use a variable name like i? Why not use something like counter? The reasons are historical; in a language called FORTRAN, the letters i through n were used by convention as loop control variable names, and the practice has persisted. If you don’t need to use the counter variable outside the loop, then you should declare it in the initialization phase, just as the book does.

Using Empty Statements in for loops

Don’t you even think about leaving part of a for loop empty! This sort of nonsesnse invariably leads to code that is hard to read and debug. Bad programmer! Bad programmer!

Arrays

Let’s skip strings for now and continue with arrays. Up to now, all of our variables have been like mailboxes that have a name and can hold one item of data.

three variables in separate boxes

What if we had a game that allowed ten players, and we needed to keep track of their scores. We could create ten separate variables, score1, score2, score3, and so on, but that doesn’t reflect the reality. These are not ten unrelated items; these are ten “versions” of the same thing. Instead of ten mailboxes, we have one apartment building with ten numbered apartments.

ten variables in an array

As you see in the preceding illustration, the “apartment numbers” in an array begin with zero, not with one. This was not done for the purpose of confusing the enemy (or you); there are solid reasons for starting with an index of zero, but those reasons are best covered in a computer science course.

Initializing an Array

To set up the preceding array in a program, you would use code like the following. When declaring an array, always use a const for the number of items it holds. You will need that number when you are writing loops to march through the array.

const int N_SCORES = 10;
int score[N_SCORES] = { 150, 300, 450, 700, 600, 275, 175, 425, 650, 250 };

// print the value of the third element in the array (index number 2)
cout << score[2] << endl;

// set the value of the fourth element in the array (index 3) to 550
score[3] = 550;

The number in the square brackets is the index, or subscript, that tells you which element you want to work with. It’s called a subscript for historical reasons. In the days of FORTRAN, programmers needed to express math concepts like coordinate points, (x1y1), and the small numbers are called subscripts. Unfortunately, on a keypunch machine or a teletype there was no way to create those small numbers hanging slightly under the line, so they used the square brackets to indicate that the expression in between was a subscript. That is why you will hear people read score[4] as “score sub four.”

The subscript doesn’t have to be a number. It can be any arithmetic expression. The rule is: work out the expression in between the square brackets. Whatever number that works out to is the index number to be selected from the array.

int n = 5;

cout << score[n] << endl; // prints 275
cout << score[n + 1] << endl; // prints 175
cout << score[2 * n - 3] << endl; // prints 425

Arrays and for

Arrays and for loops were made for each other. When you need to go through an array one entry at a time, you will almost always use a for loop. Here is a loop that will find the maximum score from the array. The code first sets the maximum score (so far) to the first entry in the array. Then the for loop goes through every entry in the array one by one. If it finds an entry that’s bigger than the current maximum, that entry becomes the new maximum.

const int N_SCORES = 10;
int score[N_SCORES] = { 150, 300, 450, 700, 600, 275, 175, 425, 650, 250 };

int maximumScore = score[0];

for (int i = 0; i < N_SCORES; ++i)
{
    if (score[i] > maximumScore)
    {
       maximumScore = score[i];
    }   
}

cout << "Maximum score is " << maximumScore << endl;

Two-dimensional Arrays

Consider an array of characters in a role playing game. For each of them we have an amount of strength, agility, and intelligence. We want to calculate each character’s general power level by adding the strength, agility, and intelligence. We can set up the original data in a two-dimensional array that looks like this:

rows show per-character info; columns show an attribute for each character

Here is the code that will take the information from the two-dimensional array and fill in a one-dimensional array with the required power levels.

enum fields {STRENGTH, AGILITY, INTELLIGENCE, NUM_FIELDS};
const int N_CHARACTERS = 4;

double info[N_CHARACTERS][NUM_FIELDS] = {
    4.5, 2.5, 7.2,
    5.0, 12.0, 8.0,
    15.0, 3.2, 9.5,
    6.5, 14.0, 9.9
};

double powerLevel[N_CHARACTERS] = { 0.0 };

// do the calculations
for (int character = 0; character < N_CHARACTERS; character++)
{
    powerLevel[character] = 0;
    for (int powerCounter = 0; powerCounter < NUM_FIELDS; powerCounter++)
    {
        powerLevel[character] += info[character][powerCounter];
    }
}

// display the calculated results
for (int character = 0; character < N_CHARACTERS; character++)
{
    cout << "Character #" << character
        << " has a power level of " << powerLevel[character]
        << endl;
}

Parallel Arrays

An array can hold only one type of data. What if we want to store not only the players’ high scores but also their names? We can’t use a two-dimensional array with one row of int and one row of string. Instead, we need to use two arrays that always stay in step with one another, as shown in the following diagram:

two arrays each with six entries

In order to insert a new player’s score in the list, we need to first find the slot where the player’s score should go:

score belongs in slot 3

Then move everybody down one slot in both the highScore and highPlayer array (which will force poor Moishe out of the list):

slots 3 and 4 moved to positions 4 and 5

Then we will put the player’s score and name in the appropriate slot.

new score in slot 3

Please don’t get discouraged and think, “you need to do all that work just for that simple effect?!” It seems extremely complicated, but it’s not bad if broken down into steps. (There is a better way to approach this than parallel arrays, but it involves making our own objects, which we haven’t gotten to yet.)

Let’s set up the arrays and the other variables we need.

const int N_SCORES = 6;
int highScore[N_SCORES] = {
    900, 850, 740, 625, 600, 550
};

string highPlayer[N_SCORES] = {
    "Duc", "Marta", "Sarathy", "Cathy", "Joey", "Moishe"
};

int score = 675;
string player = "Juerg";

Here’s a variable that we will need when moving the scores to make room for the new score, the variable we need to find where the score goes, and the code to find it.

int moveCounter = 0;
int insertPlace = 0;

while (insertPlace < N_SCORES && score < highScore[insertPlace])
{
    insertPlace++;
}

If the score is too low to qualify, the first half of the condition will break out when we have processed all the items in the array. If the score we’re looking for is greater than or equal to one of the existing scores, the second half of the condition will stop the loop.

If the score does belong in the array, we have to move the scores from the insertPlace to the end one place “right.” This is the trickiest part of the whole process. The loop must count backwards from the end of the array. Item 4 moves into item 5’s place, then item 3 into item 4’s place, etc. If you count forwards, the loop will not work.

for (moveCounter = N_SCORES - 1; moveCounter > insertPlace; moveCounter--)
{
    highScore[moveCounter] = highScore[moveCounter - 1];
    highPlayer[moveCounter] = highPlayer[moveCounter - 1];
}

Finally, we insert the new score, then print out both arrays to confirm that everything was done correctly.

highScore[insertPlace] = score;
highPlayer[insertPlace] = player;

for (int i=0; i < N_SCORES; i++)
{
	cout << (i+1) << ". "
		<< highPlayer[i] << " scored "
		<< highScore[i] << endl;
}

Strings

The discussion of strings in the book is quite good. It’s important to remember that you may treat a string as if it were an array of individual characters. Other than that, let’s be honest. If you’re going to do anything beyond the simplest string manipulation, C++ is not the language for you unless you use some additional libraries with greater power than the built-in string member functions.