Previous Page TOC Next Page



- 12 -
Controlling Loops and Branching


goto


What You'll Learn


This unit offers a variation on a theme. Because loops are themselves C++ statements, you'll find that loops can contain other loops. You'll see how to use the break statement to make an early exit from a for or while loop. With a new command, continue, you'll also learn about the opposite of break. The continue statement tells Visual C++ to continue with a loop a little earlier than it normally would iterate the loop.

In addition to the looping control that you've mastered, Visual C++ also includes another command named goto. Many veteran C++ programmers agree that goto isn't useful when it's overused, but you need to know how to code goto statements in case you run across them someday.

Nested Loops




When you nest loops, one loop can control another, amplifying the power of loops.

Whenever you need to repeat a loop several times, put the loop inside another loop. Many newcomers to programming often find nested for loops to be a little tricky, but there is really nothing to them.

Perhaps an analogy to the real world would help introduce the concept of nested for loops. Your car's odometer is similar to five or six nested for loops, each going from 0 to 9. The far-right number iterates the fastest, visibly moving from 0 to 9 as you drive down the road. A for loop that tracked that right number would be nothing more than this:


for (tenth = 0; tenth <= 9; tenth++)

  { cout << tenth << endl; }

The far-right number (either a tenth-of-a-mile indicator or a tenth-of-a-kilometer indicator, depending on your country) isn't the only number that moves. All the others do so, but at a slower rate. For every 10 values that move in the tenth-of-a-mile indicator, one of the mile indicators moves. In other words, a nested loop that looks something like this controls the two far-right numbers:


for (miles = 0; miles <= 9; miles++)

  {

    for (tenth = 0; tenth <= 9; tenth++)

      { cout << miles << tenth; }

  }

What about the number that is third from the right? The tens indicator, which tells you how many tens of miles you've traveled, is yet another loop that iterates once for each of the miles iterations, like this:


for (tens = 0; tens <= 9; tens++)

  {

    for (miles = 0; miles <= 9; miles++)

      {

        for (tenth = 0; tenth <= 9; tenth++)

          { cout << tens << miles << tenths << endl; }

      }

  }

However many digits your odometer contains is the number of nested loops required to imitate the odometer.



When you nest for loops, the outside loop always loops slower than the inside loops, just as the far-right digits of your odometer change faster than the far-left ones. The outer loop changes only after the inner loop completely finishes.

Figure 12.1 shows how you can picture inside and outside loops. The nested loop at the bottom actually contains two separate for loops nested inside an outer loop. Both of the two nested loops completely finish their respective iterations before the outside loop iterates again. When the outside loop changes, the two inner loops start from the beginning to loop again.

Figure 12.1. Two kinds of nested loops.


The program in Listing 12.1 contains two nested loops.



Embedding one loop in another produces a nested loop. Nested loops let you execute a loop more than once (a loop of loops).

Input Listing 12.1. Two nested loops.

  1:// Filename: NESTFOR.CPP

  2:// Two nested loops

  3:#include <iostream.h>

  4:void main()

  5:{

  6:  int inner, outer;

  7:

  8:  // One loop nested in another

  9:  cout << "Showing the loop control variables:" << endl;

 10:  cout << "Outer   Inner" << endl;

 11:  for (outer = 0; outer < 2; outer++)

 12:    {

 13:      for (inner = 0; inner <= 3; inner++)

 14:        {

 15:          // The '\t' outputs a tab character

 16:          cout << outer << '\t' << inner << endl;

 17:        }

 18:    }

 19:

 20:  cout << endl;   // Blank line between loop outputs

 21:

 22:  cout << "Here is a loop from 1 to 10, printed three times:" << endl;

 23:  for (outer = 0; outer < 3; outer++)

 24:    {

 25:      for (inner = 1; inner <= 10; inner++)

 26:        {

 27:          cout << inner << ' ';

 28:        }

 29:      cout << endl;   // Executes once each outer iteration

 30:    }

 31:

 32:  return;

 33:}

OUTPUT


Showing the loop control variables:

Outer   Inner

0       0

0       1

0       2

0       3

1       0

1       1

1       2

1       3

Here is a loop from 1 to 10, printed three times:

1 2 3 4 5 6 7 8 9 10

1 2 3 4 5 6 7 8 9 10

1 2 3 4 5 6 7 8 9 10

ANALYSIS

By seeing printed loop control variable values in line 16, you can see how the outer loop variable changes (from 0 to 1) more slowly than the inner loop variable changes (from 0 to 3). The reason that the inner loop changes more rapidly is that the inner loop always completes all its iterations before the outer loop has a chance to iterate again.

The second half of the output shows the values from 1 to 10 being printed. A simple for loop in lines 25 through 28 controls the numbers. However, to print that set of 10 numbers three times, an additional outer loop that iterates three times appears, beginning on line 23.

Note carefully the indentation. This makes it easy to follow where each loop begins and ends. For example, it becomes clear that the end of line marker in line 29 belongs to the outer for loop and only gets executed once for each list of 10 numbers.



A clock for football makes a useful analogy for nested loops. The quarter clock moves from 15 minutes down to 0. That countdown happens once each quarter. The quarter count from 1 to 4 increments much more slowly than the minute count within each quarter.


Take a break?




The break statement lets you terminate loops before their natural conclusion.

The break command exits the current loop in progress. You use break only inside a loop such as a while, do-while, or for loop. The break exits the execution of the loop only, not the entire program. return exits the entire program (when used in main()) regardless of the loop. Therefore, you can now exit a loop in two ways:

No matter how your program's loop finishes, the rest of the program will continue as usual.



In DOS programs, there is another function you can call, exit(), which immediately stops the program wherever it is. (You need to include STDLIB.H to use exit(). return and break are C++ commands that do not need headers). Figure 12.2 shows the actions of return, exit(), and break.

Figure 12.2. The actions of return, exit(), and break.

break terminates only loops and switch statements, not if statements.

You'll almost always enclose break code in if blocks. You simply don't write code that always executes break. A break inside a while or for loop invalidates the whole use of the loop unless the break appears in an if. The if's relational test lets the loop continue looping until the conditions are right for breaking out of the loop early.


Listing 12.2 contains both a break and a return. The execution of either depends on the user's response.



break terminates the current loop and return terminates the current function.

Input Listing 12.2. Demonstrating break and return.

  1:// Filename: BREXIT.CPP

  2:// Demonstrates both break and return

  3:#include <iostream.h>

  4:

  5:void main()

  6:{

  7:  int count=0;

  8:  char ans;

  9:

 10:  // The following loop prints "Hi" five times only

 11:  // as long as the user keeps requesting the word.

 12:  // Whether the user terminates the loop early or

 13:  // not, the program continues executing.

 14:  while (count < 5)

 15:    {

 16:      cout << "Hi" << endl;

 17:      cout << "Do you want to see it again (Y/N)? ";

 18:      cin >> ans;

 19:      if ( ans == 'N' || ans == 'n')

 20:        {

 21:          break;

 22:        }

 23:      count++;

 24:    }

 25:

 26:  cout << endl;

 27:

 28:  // The following loop prints "Bye" five times only

 29:  // as long as the user keeps requesting the word.

 30:  // The difference here from the previous section

 31:  // is that the entire program, not just the loop,

 32:  // terminates if the user requests termination.

 33:

 34:  count = 0;

 35:  while (count < 5)

 36:    {

 37:      cout << "Bye" << endl;

 38:      cout << "Do you want to see it again (Y/N)? ";

 39:      cin >> ans;

 40:      if (ans == 'N' || ans == 'n')

 41:        {

 42:          return; // Exit current function

 43:        }

 44:     count++;

 45:    }

 46:

 47:  // The following cout executes ONLY if the user let

 48:  // the previous loop execute to its natural termination

 49:  cout << "That's all, folks!" << endl;

 50:

 51:  return;   // Return to QuickWin

 52:}

Output


Hi

Do you want to see it again (Y/N)? y

Hi

Do you want to see it again (Y/N)? Y

Hi

Do you want to see it again (Y/N)? y

Hi

Do you want to see it again (Y/N)? y

Hi

Do you want to see it again (Y/N)? y

Bye

Do you want to see it again (Y/N)? y

Bye

Do you want to see it again (Y/N)? y

Bye

Do you want to see it again (Y/N)? N

Analysis

The top of the output shows the user letting the while loop continue until its natural conclusion (after five iterations). The test in lines 19 and 40 allows users to answer in upper or lowercase, although if they type anything but an n, the program will continue. If the user enters n or N in response to the question, the break executes, terminating the while loop on line 24. (The if being placed after the output keeps the break from executing the first time through the loop.)

The second part of the program contains a similar set of lines that print Bye until the user enters n or N (line 40), or until the loop finishes execution after five iterations. If the user terminates the loop early, the return in line 42 makes sure that the program terminates completely and the cout in line 49 never gets a chance to execute. If the user doesn't terminate the loop early in response to the question in line 40, line 49's cout executes because the return never executes.



The break statement also forces an early exit from a for loop.

In Unit 11, you saw how the for statement controls loops a specific number of times via the loop's control variable. The for statement does a lot for you. It initializes the control variable, tests the condition, and updates the control variable each time through the loop. You often use the for loop when you want a loop to execute a specific number of times. Depending on the data or the user's input, however, your program might have to terminate the for loop a little early. Using break inside an if statement gives you that early termination in the same way as in the while statement.

Although the following for loop appears to execute 10 times, the first iteration doesn't even complete due to the break:


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

  {

    break;   // Tell Visual C++ to ignore the remaining iterations

    cout << i << endl;

  }

break terminates for loops in the same manner that it terminates while loops. When you write nested loops, a break statement terminates only the loop it resides in, not any surrounding outer loops. In other words, break forces Visual C++ to break out of the current loop, reentering the body of the next-outermost loop:


for (out = 0; out < 10; out++)

  { for (in = 0; in < 5; in++)

    { if ((in * out) % 2)

        { break; }   // Terminate inner loop if product is odd

      cout << "Looping" << endl;

    }

  }

When the product of the inner loop control variable (in) and the outer loop control variable (out) is an even number, the break statement doesn't force Visual C++ to terminate both loops because break terminates only the current loop. Because the break resides in the innermost loop, the innermost loop is the one that terminates as a result of the break. Figure 12.3 shows how the break works.

Figure 12.3. Breaking out of the current loop.


Listing 12.3 contains a simple program that asks the user for his or her dog's name. The program then prints the name 10 times. The user can terminate the loop early by triggering the break.



break causes the current loop to quit early.

Input Listing 12.3. Using break if the user wants to quit the loop early.

  1:// Filename: FORBREAK.CPP

  2:// Prints a dog's name 10 times

  3:// (or less if the user dictates)

  4:#include <iostream.h>

  5:void main()

  6:{

  7:  char ans;         // Will hold a Y or N answer

  8:  int count;        // The loop control variable

  9:  char dName[25];   // Will hold the dog's name

 10:

 11:  cout << "What is your dog's name? ";

 12:  cin >> dName;

 13:

 14:  cout << "I'll now print the name ten times (maybe)..." << endl;

 15:

 16:  for (count = 0; count < 10; count++)

 17:    { cout << dName << endl;

 18:      cout << "Do you want to see the name again (Y/N)? ";

 19:      cin >> ans;

 20:      if ((ans == 'N') || (ans == 'n'))

 21:        {

 22:          break;  // Terminate early

 23:        }

 24:    }   // Iterate again if not broken out of the loop

 25:

 26:  cout << "That's a nice dog!";

 27:  return;

 28:}

Output


What is your dog's name? Luke

I'll now print the name ten times (maybe)...

Luke

Do you want to see the name again (Y/N)? Y

Luke

Do you want to see the name again (Y/N)? Y

Luke

Do you want to see the name again (Y/N)? Y

Luke

Do you want to see the name again (Y/N)? N

That's a nice dog!

Analysis

This program is fairly simple. It asks the user for his or her dog's name in lines 14 and 15. Due to cin's limitations, make sure that you enter only a single name and not a name such as Bow Wow.



You can get more than one word at a time using the cin.getline() function call. You'll see examples of this starting in Lesson 7.

As soon as the user enters the dog's name, the program loops 10 times, with the loop control variable count moving from 0 to 9 before the for loop terminates. Line 16 controls the loop. Inside the loop, however, a question on line 18 asks the user if he or she wants to see the name again. If the user tires of seeing the dog's name before the 10 iterations print, the break on line 22 terminates the loop early and the program ends.

continue as Opposed to break




The continue statement tells Visual C++ to iterate once again, even if the body of the loop hasn't completed.

Visual C++ contains a continue statement, which performs a job that is virtually the opposite of that of the break statement. Whereas break terminates a loop early, continue causes an immediate and new iteration of the current loop. The continue always checks the for or while condition so that the loop will end properly.

Here's a simple example. In the following code fragment, the loop iterates only once due to the break statement, and the second cout never executes:


for (i = 0; i < 5; i++)   // Seems to loop five times

  {

    cout << "Adam " << endl;

    break;

    cout << "Eve " << endl;   // Never executes

}

The next code fragment contains the same code, except that a continue statement replaces the break. Of the two couts, only the first one prints. Unlike the preceding code fragment, however, the continue keeps the loop iterating through all of its cycles, unlike break, which tells Visual C++ to forget the rest of the iterations:


for (i = 0; i < 5; i++)   // Does loop five times

  {

    cout << "Adam " << endl;

    continue;

    cout << "Eve " << endl;   // Never executes

  }

This second code fragment prints Adam five times, but Eve never prints. The continue tells Visual C++ to iterate the loop once again. Of course, on the loop's final iteration (when i is 4), the continue causes the loop to iterate once again, but the loop doesn't iterate because the control variable is used up or past its final value. Figure 12.4 shows the difference between break and continue using these code fragments.

Figure 12.4. continue iterates the loop again, unlike break.



You also can use continue on while loops, just as you can with break.

There might be times when the body of your loop processes data (through calculations and I/O) and—depending on the values of the data—you don't want to process each data value completely. An early continue statement can make sure that the second part of the loop's body doesn't always execute for every data value.

If you place a break or continue outside an if body, Visual C++ displays a warning message telling you that there is unused code in your program if any code follows the break or continue. Therefore, programs you compile with loops, such as the ones contained in the previous code fragments, result in compiler warnings because Visual C++ knows that the second cout never executes. If, however, you place the break or continue statement inside an if's body, Visual C++ doesn't display the warnings because the break and continue will change the loop's execution only when the if's conditional is true.



As with break, if you place a continue inside a nested loop, the continue executes another iteration of the current innermost loop, not the outer loop.


Listing 12.4 contains a program that asks the user for five values that represent each day's sales. A for loop ensures that only five values are asked for. As the user enters the five values, the body of the for loop totals the sales for the week. Not all weeks will have five days' worth of sales, however. If the week had a holiday, the user should enter -99 for that day's sales, which triggers the continue statement.



continue forces an early iteration of the loop.

Input Listing 12.4. continue lets the program control the execution of the second part of a loop.

1:// Filename: CONTINUE.CPP

  2:// Uses continue when data is missing

  3:#include <iostream.h>

  4:

  5:

  6:void main()

  7:{

  8:  int count;          // Loop control variable

  9:  float dSales;       // Will hold each day's sales

 10:  float wSales = 0;   // Weekly total

 11:

 12:  // Set up the loop for a possible five iterations

 13:  for (count = 0; count < 5; count++)

 14:    {

 15:      cout << "Enter the sales for day #" << (count + 1)

 16:           << " (-99 for none): ";

 17:      cin >> dSales;

 18:      if (dSales < 0.0)

 19:        { continue; }

 20:

 21:      // The following statement executes ONLY if a

 22:      // valid daily sales total was just entered

 23:      wSales += dSales;

 24:    }

 25:

 26:  // Print the week's total

 27:  cout.precision(2);

 28:  cout.setf(ios::showpoint);

 29:  cout.setf(ios::fixed);

 30:  cout << endl << "The weekly total is $"

 31:       << wSales << endl;

 32:  return;

 33:}

Output


Enter the sales for day #1 (-99 for none): 546.77

Enter the sales for day #2 (-99 for none): -99

Enter the sales for day #3 (-99 for none): 434.56

Enter the sales for day #4 (-99 for none): 886.31

Enter the sales for day #5 (-99 for none): 905.42

The weekly total is $2773.06

Analysis

This program's continue statement lets the for loop process very intelligently. The for loop in lines 13 through 24 normally executes five times due to the loop control. Each iteration represents a day of the week. The user is to enter each day's sales value when prompted by the cout in lines 15 and 16.

Line 15 adds 1 to count when printing the prompt for each day's sales because line 15's for loop begins at 0, not 1. However, if there is no sales figure for the user to enter (as would be the case for holidays), the user enters -99 and the loop iterates again, getting another value.

As soon as the user enters all the values for the week, the program prints the total weekly sales value on lines 27 through 31 with extra code that ensures that two decimal places will always print.

Moving Around with goto




goto lets your program execute in any order you desire.

Many Visual C++ programmers write all kinds of Visual C++ programs and never use the goto statement. Old programming languages, especially FORTRAN and the pre-QBasic BASIC languages, don't have enough rich control commands such as while and do-while to eliminate goto entirely.



In today's world of modern programming languages, goto is rarely used, except when a programmer writes programs in low-level assembly language where goto-like statements are mandatory for many operations.

definition

A branch occurs when one section of a program triggers the execution of a different section.

Visual C++ includes a goto just in case you need one. Before studying goto, keep in mind that you can write any program without goto. Use goto only when its meaning is obvious. goto branches the current program's execution to a different part of the program. In other words, instead of executing a program sequentially, line by line, goto tells Visual C++ what line of your program to execute next.



goto and Maintainability

If you put too many goto statements in your programs, you will soon find that your programs are virtually impossible to follow. Until you learn about goto, all your programs execute in one of two ways:

Both of these execution orders are easy to follow, especially if you indent the bodies of your loops. It's very easy to spot where a loop begins and ends. If your program doesn't contain a loop, but instead executes sequentially from top to bottom, it's even easier to follow.

Once you insert goto statements in a program, the program's execution is at the mercy of the goto statements. The execution might jump from one part of the program to another and do so several times. The "need" to use a goto is usually a symptom of bad code.


Here is the format of the goto statement:


goto statementLabel;

statementLabel follows the same naming rules that variables follow (see Lesson 3 for a review of variable-naming conventions). Here is a sample goto:


goto getInput;

When Visual C++ encounters this goto, it looks from the top of the current function to the bottom for a statement label named getInput. If Visual C++ doesn't find a statement label named getInput, you get an error message.

A statement label always appears to the left of an executable Visual C++ statement. For example, all of the following statements have statement labels in front of them:


getInput: cin >> amount;


here: for (i = 0; i < 10; i++)

Notice that a colon (:) always separates a statement from its label.

Never put a colon after the label's name in the goto statement. Use a colon only after the label name when the label appears before code, as shown in the preceding two statements.

Without the colon, Visual C++ would be confused by a label that is directly before a legal Visual C++ statement. The colon tells Visual C++, "Here is a label, and it appears before a statement." Never put more than one label with the same name in the same function.

When Visual C++ encounters a goto statement, it doesn't continue executing the program on the line following the goto. Instead, Visual C++ transfers control (branches) to the statement label and then continues from there. Unlike loops that always repeat again at the top of the loop, a goto might never come back to its point of origin.



continue, break, and return provide safe methods of implementing a goto in a program. When you use the correct commands, together with sensible use of compound statements (blocks), there is really no need to ever use a goto.



There is no Stop and Type for this section due to the author's dislike of the goto statement.


Homework



General Knowledge


  1. How can you terminate a for loop early?

  2. How can your program force an early execution of the loop's next cycle?

  3. What's the difference between break and continue?

  4. Will break and continue work for while, do-while, and for loops?

  5. Which kind of loop—while, do-while, or for—is usually the one that uses continue?

  6. What's the difference between return and break?

  7. Why should a break fall within an if block instead of residing as regular lines of a Visual C++ program?

  8. Why does continue rarely appear without an if preceding it?

  9. What does goto do?

  10. Why is goto considered a bad programming statement?

  11. Which variable controls the inner loop and which controls the outer loop in the following code?

    
    for (ctr1 = 10; ctr1 > 5; ctr1-)
    
      { for (ctr2 = 1; ctr2 < 4; ctr2++)
    
          { cout << ctr1 << "  " << ctr2; }
    
      }

  12. Does the outer loop of two nested loops iterate faster or slower than the inner loop? Why?

  13. True or false: There can be more than one label with the same name, but only one goto to that label.

  14. True or false: You can't use continue in nested loops.

  15. True or false: You can't use break in nested loops.

  16. True or false: The break statement requires a header file.

  17. True or false: Visual C++ displays a warning message when you compile a program that has a break or continue.

  18. True or false: When you nest loops, continue terminates the execution of the inner loop only.

    What's the Output?


  19. How many times does X print?

    
    for (count = 0; count < 5; count++)
    
      {
    
        cout << 'X';
    
        break;
    
      }

  20. How many times does X print?

    
    for (count = 0; count < 5; count++)
    
      { cout << 'X';
    
        continue;
    
      }

  21. Here's some spaghetti code! What's the output?
    
    #include <iostream.h>
    
    void main()
    
    {
    
      goto a;
    
    e:
    
      goto f;
    
    c:
    
      cout << "a" << endl;
    
      goto d;
    
    b:
    
      cout << "d" << endl;
    
      goto c;
    
    d:
    
      cout << "c" << endl;
    
      goto b;
    
    a:
    
      cout << "b" << endl;
    
      goto e;
    
    f:
    
      return;
    
    }

  22. How many times will an X appear in the following nested for loop?

    
    for (outer = 0; outer < 5; outer++)
    
      { for (inner = 0; inner < 3; inner++)
    
          { cout << 'X'; }
    
      }

    Find the Bug


  23. Mary Jo Beth can't get her program working. It seems to be hung up on this statement:


    
    goto calcPayroll:

  24. Help Mary fix the problem.

  25. The following three lines appear together in a program. Although there is nothing technically wrong with the statements, something is unnecessary. What is unnecessary and why?

    
      cin >> rate;
    
      goto here;
    
    here: pay = rate * hours;

  26. When Pete's program gets to the following statement, it seems to hang up. Pete has studied the code for several hours without figuring out the problem. Tell him what he's doing wrong (and why he should consider a different career).


    
    makeLoop: goto makeLoop;   // Transfer control

  27. Foster Forsythe is nesting for loops, but they don't seem to be working properly. Will you please help him? Here is the part of the program that is giving him trouble:

    
    for (ctr1 = 1; ctr1 <= 10; ctr1++);
    
      { for (ctr2 = 1; ctr2 <= 5; ctr2++)
    
        { value = ctr1 * ctr2;
    
          cout << value << endl;
    
        }
    
      }

  28. Rewrite the following code using a do-while statement:

    
    AskAgain:
    
      cout << "What is your first name? ";
    
      cin >> fName;
    
      if ((fName[0] < 'A') || (fName[0] > 'Z'))
    
        { goto AskAgain; }   // Make sure user enters a word
    
                             // and not special characters

    Write Code That. . .


  29. Write a program that asks the user for four weekly sales values. Add to a sales total as the user enters a new value and print the total sales after the user enters all four values. Just in case the store closes for repairs one week, see whether the user enters a negative value for a sales figure. If so, terminate the sales entry early and average the number of weeks the user actually entered.

  30. Rewrite Listing 12.4 (CONTINUE.CPP) so that the loop terminates completely when the user enters -1 for a daily sales figure. The loop will now have both a break and a continue, and the weekly total will update only if neither the break nor the continue executes. Don't check for an exact match for -1 or -99 because the user enters the daily values as floating-point numbers and you can't accurately test for floating-point equality.


    Extra Credit


  31. Write a program with two nested loops that produces the following output:

    
    ABCD
    
    ABC
    
    AB
    
    A

  32. Write a program that asks the user for test scores. Enter all test values as integers to keep things simple. The program is to continue until the user enters -99 in order to obtain the average or until she enters five values (there were only five tests this term). If the user enters -99, it means that she took fewer than five tests and is ready for the average early. (Hint: break might help with the early loop termination.) As the user enters each test average, add the average to a total variable and increment a counter variable (the loop's counter variable will work for the test count). As soon as the user enters five values or -99 (indicating that there are no more test scores), compute a floating-point average and print the result. Be sure that you congratulate the user for an average of more than 90 percent!

  33. Write a program that asks the user for temperature readings for the last 10 days. Compute the average temperature. If the user enters a temperature below freezing, make sure that a continue causes the program to ignore the reading (average in only temperatures above freezing). Keep track of how many above-freezing temperatures the user enters (via a counter variable) and compute the average based on the number of valid values entered.

Previous Page Page Top TOC Next Page