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.
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:
When designing a loop, the first question to ask is, "How many times will the loop repeat?" Here are examples of count loops.
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 }
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 }
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
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
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 }
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 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.
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;
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.
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;