Types of loops

When you are programming with loops, it helps to understand that there are only a few basic formats that are used repeatedly. If you can master these variatons and recognize when they are needed, then programming will become much easier. All loops have a basic structure. There will be a variable (at least one) that will control how many times the loop runs. It is necessary to do the following to this variable in each loop that you write.

If you do not do all three of these steps in every loop that you write, then you will be writing incorrect loops that will either never loop, or will loop forever. If you create a loop that runs forever, press CTRL-C to stop your program.

Count Loops

These are loops that everyone seems to love. People love them so much that they try to use them inappropriately. The only time to use a count loop is when the program can determine ahead of time how many times the loop will repeat. This is not always possible. There are generally two ways that the number of repetitions of a loop will be know ahead of time:

  1. The loop always repeats the same number of times.
  2. The program calculates the number of repetitions based upon user input.

When designing a loop, the first question to ask is, "How many times will the loop repeat?" Here are examples of count loops.

  1. Always repeats the same number of times. Notice the use of a constant to control the loop.
    const int ListSize = 10;
    int NumbersEntered = 0;              	//Initialize
    int TotalEven = 0;
    int Value;
    while (NumbersEntered < ListSize) {  	//Test
      cin >> Value;
      if (Value % 2 == 0) {			//Loop Process
        TotalEven++;
      }
      NumbersEntered++;                  	//Update
    }
    
  2. The program calculates the number of repetitions from user input.
    int ListSize;
    int NumbersEntered = 0;              	//Initialize
    int TotalEven = 0;
    int Value;
    cout << "How many numbers will be entered? ";
    cin >> ListSize;
    while (NumbersEntered < ListSize) {  	//Test              
      cin >> Value;
      if (Value % 2 == 0) {			//Loop Process
        TotalEven++;
      }
      NumbersEntered++;                 	//Update
    }
    

Sentinel Loops

Often, it will be necessary to write loops that repeat until a certain value is entered. These are know as sentinel loops. Think of a sentinel as a red flag. The loop will continue until you wave a red flag at it. The sentinel can be a single value or it can be an entire range of values. Sentinel loops are more useful than count loops, since they allow for an undetermined amount of repetitions. There are two common places for using a sentinel loop

  1. Reading an unknown amount of input from the user. This is the most flexible way to read data from the user. The program will be able to accept any amount of input from the user.
  2. Validating input. If it is necessary to verify that a user's input falls within a certain range, then a sentinel loop is required. It is now known ahead of time how many times the user will enter an invalid number. It is not enough to validate the first input from the user. What if the user types another invalid input?

Sentinel loops still have three steps for the loop control variable: initialize, test and update. However, with sentinel loops, the initialize and update staements look the same. This can be a little confusing the first time it is seen, but if you remember that one statement is being used to initialize the loop control variable and that the other is being used to update it, then it may make a little more sense.

Here are a couple of examples of sentinel loops

  1. Reading an unknown amount of numbers in the range from 0 through 10.
    int Value;
    cout << "Enter a list of numbers in the range 0 through 10 (any other number to quit): "
    cin >> Value;              		//Initialize
    while (Value >= 0 && Value <= 10) {	//Test
      if (Value % 2 == 0) {			//Loop Process
        TotalEven++;
      } 
      cout << "Enter a list of numbers in the range 0 through 10 (any other number to quit): "
      cin >> Value;              		//Update
    }
    
    
  2. Validating input
    char Upper;
    cout << "Please enter an upper case letter: ";
    cin >> Upper;				//Initialize
    while (Upper < 'A' || Upper > 'Z') {	//Test
      cout << "Error: " << Upper << " is not an upper case letter." << endl;	//Loop Process
      cout << "Please enter an upper case letter: ";
      cin >> Upper;				//Update
    }
    

Notice that the sentinel loops can be used to test for good values, or to test for bad values. It is important to remember the abstractions: initialize, test and update. Initialize before the loop, test in the while statement parenthesis, update inside the loop (usually at the bottom).

Conditional Loops

Conditional loops have common traits with sentinel and count loops. They are like sentinel loops in that it is unknow before time how may times they will repeat. They are like count loops in that they terminate as the result of a calculation, instead of based upon user input. A count loop uses a simple calculation to determine when the loop should end. Count loops can use very complicated calculations.

  1. Calculating the years to accumulate an amount of money.
    const float Invest = 100.0;
    const float Goal = 1000000.00;
    const float Rate = 0.06;
    int Years = 0;
    float Total = Invest;			//Initialize
    while (Total < Goal) {			//Test
      Years++;				//Loop Process
      Total = Total * (1 + Rate);		//Update
    }
    cout << "It will take " << Years << " years to accumulate $" << Invest << endl;
    cout << "to the total of $" << Goal << " at " << Rate*100 << "% interest."<< endl;
    
    
  2. Calculating the Greatest Common Divisor of two numbers. The algorithm is explained on page 41 of the text.
    int first;
    int second;
    int remainder;
    cout << "Enter two integers: ";
    cin >> first >> second;
    cout << "The greatest common divisor of " << first << " and " << second << " is ";
    remainder = first % second;		//Initialize
    while (remainder != 0) {		//Test
      first = second;			//Loop Process
      second = remainder;
      remainder = first % second;		//Update
    }
    cout << second << "." <, endl;
    

As you can see from these loops, conditional loops combine qualities of both the sentinel and the count loops. The exit from the loop depends on some initial input from the user and a cacluation based upon that input.

Special sentinel loop

There is a special sentinel loop that can be used with cin. There is a special character that terminates all text files: CTRL-Z. Whenever C++ encounters this character when reading a file, it terminates all input from that file. The cin stream is considered a text file. So it is possible to use the CTRL-Z character to indicate to a program that no more input is available.

What makes this type of loop so appealing is that the initialization, test, and update are all in the same place. The statement cin >> first returns a value of  true if a valid input is entered. It will return false if an invalid input, like CTRL-Z, is entered.

	int Value;
	int Count = 0;
	cout << "Please enter number " << Count+1 << " (CTRL-Z to exit): ";
	while (cin >> Value) {	//Initialze, Test, Update
		Count++;
		cout << "Please enter number " << Count+1 << " (CTRL-Z to exit): ";
	}

There is a problem with using the CTRL-Z character: once an invalid input is encountered, no more valid input can be received. In the following example, after pressing CTRL-Z to end the loop, the program will fail when trying to read the letter after the loop. The program will always display the intial value of the letter ('A') to the screen.

	int Value;
	int Count = 0;
	cout << "Please enter number " << Count+1 << " (CTRL-Z to exit): ";
	while (cin >> Value) {
		Count++;
		cout << "Please enter number " << Count+1 << " (CTRL-Z to exit): ";
	}
	char Letter = 'A';
	cout << "Enter a letter: ";
	cin >> Letter;
	cout << "You entered " << Letter << endl;

This can be remedied by resetting the state of the cin stream to a valid state. This is done with the cin.clear() statement. Here is the same example again, but this time the program will wait to read a letter from the user and will display it properly.

	int Value;
	int Count = 0;
	cout << "Please enter number " << Count+1 << " (CTRL-Z to exit): ";
	while (cin >> Value) {
		Count++;
		cout << "Please enter number " << Count+1 << " (CTRL-Z to exit): ";
	}
	cin.clear();
	char Letter = 'A';
	cout << "Enter a letter: ";
	cin >> Letter;
	cout << "You entered " << Letter << endl;