Loop Management and Controls
There are times that you have to work in two or more dimensions when you are implementing program repetition. Many of these times have to do with data access and arrays, but since you have not arrived at that point yet, you will be looking at some simpler, but still appropriate examples.
Suppose you were asked to create a program that outputs mathematical multiplication tables. You might not know in advance what the highest value is, but you can get that from the user.
The specifications might appear as follows.
- The highest value to be calculated (i.e., the limit) will be entered by the user; it should be limited to 15 so that it will fit on the screen
- The program will display a row of digits across the top of the output; these will be called the column digits, and a row of digits from top to bottom along the left side of the output; these will be called the row digits
- The program will then show the results of multiplying the column digits by the row digits in matrix form. Example: at the intersection of 2 and 2, the result is 4; at the intersection of 3 and 4, the result is 12
- The highest value displayed in the rows and columns is limited by the user input value. An example of the display might be as follows.
This kind of process will require nesting loops so that you can display both row and column components of a set of data.
Consider the pseudo code description of the above specifications.
// get number from user
// check for number within limits
// print table header
// loop across given number of rows
// show row leader
// loop across given number of columns
// calculate value
// print value, right justified
// end column loop
// print end of row
// end row loop
This doesn't sound very hard, and in truth, it is not. If you think your way through the process, and especially if you write it in English before you jump into the coding, you will enjoy great success. If you don't, this kind of problem can take quite a bit of time.
The following shows the code for this. A function printTableHeader is used to abstract the table title numbers with the underline, but the rest of the code is shown. This operation also uses the printInteger function that prints integers justified within a specified width. Note that the following only shows the code needed to conduct the operations; this is only a code segment, not a function or a program.
// prompt user
// function: printString, printInteger
printString( "Enter a number between " );
printInteger( MIN_NUM_ALLOWED );
printString( " and " );
printInteger( MAX_NUM_ALLOWED );
// acquire number
// function: promptForInteger
number = promptForInteger( ": " );
// check for number within limits
if( number >= MIN_NUM_ALLOWED && number <= MAX_NUM_ALLOWED )
{
// print table header
// function: printTableHeader
printTableHeader( number );
// loop across given number of rows
for( rowCounter = 1; rowCounter <= number; rowCounter++ )
{
// show row leader
// printIntegerJustified, printChar
printIntegerJustified( rowCounter, ROW_LEADER_WIDTH, "RIGHT" );
printChar( COLON );
// loop across given number of columns
for( colCounter = 1; colCounter <= number; colCounter++ )
{
// calculate value
printValue = rowCounter * colCounter;
// print value, right justified
// function: printIntegerJustified
printIntegerJustified( printValue, COLUMN_VALUE_WIDTH, "RIGHT" );
}
// end column loop
// print end of row
// function: printEndline
printEndline();
}
// end row loop
}
The key to conducting nested loop situations is to NOT try to figure it all out at once. Figure out exactly what you want your row iteration to look like and design that. Then figure out what your column iteration should look like and then design that. Finally, figure out what you want to have happen every time you get to a certain row and column location, and design that; this part will almost always be trivial as long as you worked through your rows and columns first.
As you can see, nice looking tables and displays can be presented with just a small amount of code, but again, this requires some thinking and planning. Nested loops are a powerful way to manage multi-dimensional circumstances and you will definitely be using them when you start working with two-dimensional arrays. One key point is that you will never want to nest more than three loops, and you are usually better not to go more than two loops deep. If you find an apparent need for a third (or more) nested loops, critically review your logic and design. It may be time for a function to take care of part of the problem, or it may just require a different logical approach.
Watch this video to observe the nested loop example shown on this page.