Nested Loops
You might remember the multiplication table, generally rendered as a 10 by 10 table containing the products of first 10 natural numbers. This is what it usually looks like:
1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 |
2 | 4 | 6 | 8 | 10 | 12 | 14 | 16 | 18 | 20 |
3 | 6 | 9 | 12 | 15 | 18 | 21 | 24 | 27 | 30 |
4 | 8 | 12 | 16 | 20 | 24 | 28 | 32 | 36 | 40 |
5 | 10 | 15 | 20 | 25 | 30 | 35 | 40 | 45 | 50 |
6 | 12 | 18 | 24 | 30 | 36 | 42 | 48 | 54 | 60 |
7 | 14 | 21 | 28 | 35 | 42 | 49 | 56 | 63 | 70 |
8 | 16 | 24 | 32 | 40 | 48 | 56 | 64 | 72 | 80 |
9 | 18 | 27 | 36 | 45 | 54 | 63 | 72 | 81 | 90 |
10 | 20 | 30 | 40 | 50 | 60 | 70 | 80 | 90 | 100 |
The primary task of this chapter is to output a multiplication table similar to the one above. It will not be a table with lines and cells, since the only intention is to output all the products and, if possible, to output them in a tabular form.
An easy way to complete the given task would be to write out each row of the table by using a literal string. For example, the first row could be written out by:
cout << "1 2 3 4 5 6 7 8 9 10" << endl;
Similarly, the sixth row could be written out by:
cout << "6 12 18 24 30 36 42 48 54 60" << endl;
Yet, such a solution to this problem would miss the intention of the given task. A solution like this would make us calculate and type in all the numbers that make up the table (i.e. all the products) ourselves, manually. We certainly do not want to do that, since we are trying to learn how to make a computer do all the calculations for us (however simple those calculations might be). Accordingly, let us add another requirement to our task: we want the computer to calculate all the products that make up the table.
This new requirement provides the benefit of preventing an error in calculating or typing in the results because if the computer does calculations for us, we should expect the results to be absolutely accurate and without any typing errors. Finally, what would the purpose of using a computer be if we had to calculate all the results manually?
Perhaps the task of printing out the entire
table is too complicated to deal with all at once, so let us simplify our
problem by focusing on printing out just the sixth row of the multiplication
table. The program has to print out 10 numbers that make up that row. After a
while, one may come up with an idea that a for
loop can be used to repeat
printing out a product 10 times:
for (int column=1; column<=10; column++) cout << 6*column << " ";
We have already done something similar in the chapter if and for Statements, except that here the program has to print out all the numbers in a single line. To separate each number from the next one, a string containing one space character is used. The output of this piece of code should look like this:
6 12 18 24 30 36 42 48 54 60
We have succeeded in printing out the sixth
row, but what about the other rows? We could use another for
loop to print
out a row ten times. Let us write that for
loop only:
for (int row=1; row<=10; row++) { // here we need to insert the code for printing out a row cout << endl; }
This for
loop ends with a cout
statement in order to move on to the next output line, after one row of the
table has been printed out. This causes each row of the table to be printed out
in its own output line.
So far, we have written two pieces of code: the piece that prints the sixth row and the piece that repeats printing a row. Let us now merge the two given code fragments together:
for (int row=1; row<=10; row++) { for (int column=1; column<=10; column++) cout << row*column << " "; cout << endl; }
As you can notice, a for
loop can
reside inside another for
loop. Together they are called nested for loops, while individually they are called the outer
for loop and the inner for loop. In
addition to this, there can even be a for
loop residing inside a second for
loop which resides inside a third for
loop, etc. This means that for
loops can in fact be nested many times inside each other.
Pay attention to a small change in a piece
of code for printing out a row: originally, we used a product 6*column
to
print out the sixth row. If we were to leave it like that, we would have
printed out the sixth row ten times. To print out each row of the table, we have
to use the product row*column
which does exactly what we want. The variable row
will assume a value of the row's number in each iteration of the outer for
loop.
The output of this piece of code should be exactly this:
1 2 3 4 5 6 7 8 9 10 2 4 6 8 10 12 14 16 18 20 3 6 9 12 15 18 21 24 27 30 4 8 12 16 20 24 28 32 36 40 5 10 15 20 25 30 35 40 45 50 6 12 18 24 30 36 42 48 54 60 7 14 21 28 35 42 49 56 63 70 8 16 24 32 40 48 56 64 72 80 9 18 27 36 45 54 63 72 81 90 10 20 30 40 50 60 70 80 90 100
As you might have noticed, some lines are longer and some are shorter than the others, so the table does not look well organized. It does not even look like a table, but at least all the products seem to be correct.
To remedy this problem, we need each
printed number to have equal "width", which can be accomplished by
using the setw
manipulator. We will soon look into it in more detail, but for the
time being two things have to be done:
a) change the line that prints out the products into:
cout << setw(3) << row*column << " ";
b) at the beginning of the program, add a line:
#include <iomanip>
Here is the code of the entire program:
You can run the programs given in this chapter by using an online service called C++ shell
#include <iostream> #include <iomanip> using namespace std; int main() { for (int row=1; row<=10; row++) { for (int column=1; column<=10; column++) cout << setw(3) << row*column << " "; cout << endl; } }
The exact output is:
1 2 3 4 5 6 7 8 9 10 2 4 6 8 10 12 14 16 18 20 3 6 9 12 15 18 21 24 27 30 4 8 12 16 20 24 28 32 36 40 5 10 15 20 25 30 35 40 45 50 6 12 18 24 30 36 42 48 54 60 7 14 21 28 35 42 49 56 63 70 8 16 24 32 40 48 56 64 72 80 9 18 27 36 45 54 63 72 81 90 10 20 30 40 50 60 70 80 90 100
It looks just as we wanted it to.
Let us explain the nested for
loops in a
slightly different manner. Think as if we were to execute the given program
manually. In that case, the variable row
is being assigned values from 1
to 10 by the outermost for
loop. However, for each iteration of outermost loop (and also for
each value of the row
variable), the innermost for
loop will iterate 10 times,
assigning a value from 1 to 10 to the column
variable. Thus, there will be
10 times 10 iterations of the innermost cout
statement, printing out one
hundred numbers. In this manner, the two nested loops make row
and column
variables assume all the possible combinations of two values from 1 to 10. If
you still have any uncertainties, try stepping through the program with a
debugger.
To solve this task, we had to use two
nested for
loops, which are together called a double loop. Generally speaking,
whenever we need to process data from a table, we are likely to require at
least a double loop in order to process all the table's values. What do we mean
by 'at least'? Well, three nested loops make a triple loop, four of them make a
quadruple loop and so on...
It goes without saying that you should not use the same variable name for inner and outer for loop. |