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.
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!
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.
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.
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.
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,
(x1, y1), 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
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;
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:
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;
}
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:
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:
Then move everybody down one slot in both the
highScore and highPlayer array
(which will force poor Moishe out of the list):
Then we will put the player’s score and name in the appropriate slot.
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;
}
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.