5: Getting Loopy

What We Will Cover


Continuations

Questions from last class?

Homework Questions?

Homework Discussion Questions (Thursday)

  1. Did anyone use pair programming?
  2. What are the 4 rules of pair programming?

Review Question

  • What is displayed by running the following code?
    bool bb;
    if (bb || !bb) {
        cout << "That is the question!";
    }
    
    1. That is the question!
    2. Nothing
    3. Does not compile
    4. Compiles but causes an error when it runs

5.1: Counting Loops

Learner Outcomes

At the end of the lesson the student will be able to:

  • Design and implement counting loops
  • Apply counting loops to solve a number of problems
  • Translate these designs into C++ code

5.1.1: Using Loops to Count

  • Assume we want to write an application that writes a list of numbers
  • We want to start at the number 1 and let the user choose the ending number
  • Thus the program output will look something like:
    This program writes lists of numbers.
    Enter the maximum number: 5
    1
    2
    3
    4
    5
    
  • We cannot simply write five numbers with cout because the user chooses the maximum number
  • Since we understand our problem, our next step is to write our algorithm
  • We can create an algorithm for this task using two variables and a loop
  • When designing with a loop, we need to consider these things:
    1. Loop body -- which statements to repeat
    2. Loop test condition -- when to loop and when to stop
    3. Loop test update -- must change something to exit the loop
    4. Initialization code -- how to get started correctly
  • We start with the first task and decide which statements need to repeat inside the loop
  • To count using a loop we need to use a variable to keep track of the count
  • This variable is often called a counter or stepper
  • We decide to use a variable named counter and to increment the counter variable each time the loop repeats:
    write the counter
    increment the counter
    
  • Now we need to design the loop test condition
  • We need a test condition for ending our loop when the count reaches the maximum number
  • Working through our loop manually when the count is near maximum, we see that our condition could be:
    while counter <= maximum
  • Also, we consider the test update and decide that incrementing the counter does the job
  • Now we move to the last task and ask ourselves what value the counter variable must start with to print the first number correctly
  • We realize that we need to start the counter variable at 1 to get the first number correct:
    set count = 1
  • Putting the pieces together we have:
    set counter = 1
    while counter <= maximum
        print out the counter
        increment the counter
    
  • We test this algorithm manually and then translate it into C++ code

Example C++ Application That Counts to Five

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#include <iostream>
using namespace std;

int main() {
    int max = 0;
    cout << "This program writes lists of numbers.\n";
    cout << "Enter the maximum number: ";
    cin >> max;

    int counter = 1; // initialization code
    while (counter <= max) { //loop termination condition
        //loop body
        cout << counter << endl;
        counter = counter + 1; // adjust the counter
    }

    return 0;
}

Check Yourself

  1. Ask a person to clap 12 times.
    1. How does s/he know when to stop?
    2. What changes each time s/he claps?
  2. For the example loop shown below, the loop repeats ________ times.
    int counter = 1; // initialization code
    while (counter <= 5) { //loop termination condition
        //loop body
        cout << counter << endl;
        counter = counter + 1; // adjust the counter
    }
    
  3. True or false: the purpose of the variable counter is to keep track of the number of repetitions.
  4. True or false: if counter started at 100 (counter = 100), the loop would never repeat.
  5. True or false: if the statement updating the count was ommitted, like in the code shown below, the loop would never stop repeating until the program was terminated.
    int counter = 1; // initialization code
    while (counter <= 5) { //loop termination condition
        //loop body
        cout << counter << endl;
    }
    

5.1.2: for Statements

  • It turns out that counting is a very common way to use loops A series of steps
  • Loops that are controlled by a counter variable are called counter-controlled loops
  • We can visualize a counter-controlled loop as a series of steps to reach a goal
  • A counter-controlled loop has the form:
    i = start;
    while (i < end) {
        ...
        i++;
    }
    
  • Where:
    • i: the name of a counter variable
    • start: the initial starting value
    • end: the final ending value
  • Because counting loops are so common, there is a special statement:
    for (i = start; i < end; i++) {
        ...
    }
    
  • The following example shows the same loop as before but using a for loop instead of a while loop
  • Note how the repeated code is indented inside the loop
  • This lets us see easily which code is repeated and which is not

Counter-Controlled-Loop Example

counting loop

Understanding the for Loop

  • Notice the structure of the code for the looping application
  • First was the statement to correctly initialize the looping condition:
    int i = 1;
  • Then came the test condition
    i <= max
  • The loop executes the body of the loop if and only if the condition evaluates to true
  • The final statement inside the for loop is the update statement
    i = i + 1
  • Even though the statements are grouped inside the parenthesis of the for statement, they are not executed together
  • Following is a diagram of the for loop operation followed by a description of each step

Diagram of for Loop Operation

for loop flow chart

Execution Steps

  1. When for loop is reached, execute the INITIALIZATION statement
  2. Check if CONDITION is true
    1. if true then continue with Step 3
    2. Otherwise, continue with Step 6
  3. Execute the block containing the statements to repeat (LOOP_BODY)
  4. When end of loop body is reached, execute the UPDATE statement
  5. Return to Step 2
  6. Loop is finished: continue with statements after the loop

Check Yourself

counting loop

  1. For the loop above, enter the initialization statement.

    answer

  2. For the same loop, enter the test condition.

    answer

  3. For the same loop, enter the update statement.

    answer

Exercise 5.1

In this exercise we explore some uses of counter-controlled loops.

Background

Recall that a char data type is stored by the computer as a number using the ASCII code (ASCII Table). Since a char is stored as an int by the computer, C++ lets you cast an int to a char.

int count = 65;
cout << (char) count << endl;

Specifications

  1. Type the following program into a text editor and save it as counting.cpp:

    counting loop

  2. Compile and run the starter program to make sure you entered it correctly. When you run the program, the output should look like this:
    This program uses a loop to count.
    Enter the maximum number: 5
    1
    2
    3
    4
    5
    

    Note that we are using a for loop to count and that the variable i is the counter variable. For more information, see section: 5.1.2: for Statements.

  3. For our next counting application we will create a list of numbers and their square. Replace the cout statement inside the curly braces of the for loop with the following code:
    cout << i << '\t' << i * i << endl;
    

    Notice that the '\t' is the escape sequence for a tab character. We use the tab character to keep the columns aligned. For more information on escape sequences, see section: 3.2.6: Output of Hard-to-Print Characters.

  4. Compile and run your modified program and make sure your output looks like:
    This program uses a loop to count.
    Enter the maximum number: 5
    1       1
    2       4
    3       9
    4       16
    5       25
    
  5. For our next counting application we will display a list of numbers and their ASCII character equivalent. Replace the cout statement inside the curly braces of the for loop with the following code:
    cout << i << '\t' << (char) i << endl;
    

    Recall that a char data type is stored by the computer as a number using the ASCII code (ASCII Table). Since a char is stored as an int by the computer, C++ lets you cast an int to a char. For more information on casting, see section: 4.1.6: Type Casting.

  6. Compile and run your modified program and make sure your output looks like:
    This program uses a loop to count.
    Enter the maximum number: 128
    (output not shown)
    65      A
    66      B
    67      C
    (more output not shown)
    

    Use a large number like 128 to view the ASCII characters. You may want to use some of these special characters in your project.

  7. For our next counting application we will display a bar chart. Replace the current for loop with the following code:
    cout << "\n" << max << ": ";
    for (int i = 1; i <= max; i = i + 1) {
        cout << '*';
    }
    cout << endl;
    

    Notice that we show a horizontal bar chart by simply counting the number of characters to display. For more information, see section: 5.1.3: Making Bar Graphs.

  8. Compile and run your modified program and make sure your output looks like:
    This program uses a loop to count.
    Enter the maximum number: 5
    
    5: *****
    
  9. For our next counting application we will sum the numbers from 1 to the maximum value. Replace the code after the cin statement with the following:
    int sum = 0;
    for (int i = 1; i <= max; i = i + 1) {
        cout << i << endl;
        sum = sum + i;
    }
    cout << "The sum of these numbers is: "
         << sum << endl;
    

    For this application we needed to use another variable to hold the values as we gather them. This is known as accumulating values. For more information, see section: 5.1.4: Summing Numbers.

  10. Compile and run your modified program and make sure your output looks like:
    This program uses a loop to count.
    Enter the maximum number: 5
    1
    2
    3
    4
    5
    The sum of these numbers is: 15
    
  11. Submit your final program source code to Blackboard as part of assignment 5.

As time permits, read the following sections and be prepared to answer the Check Yourself questions in the section: 5.1.6: Summary.

5.1.3: Making Bar Graphs

  • Lets use a counting loop to make a horizontal bar graph
  • Our task is:

    Write a program that asks a user for a number and then displays a horizontal bar graph using '*' characters. Use one '*' for each number.

  • For example:
    Enter a number and I will display a bar graph.
    Enter your number: 5
    
    Your graph:
    *****
    
  • Since we understand our problem, our next step is to write our algorithm
  • We start with getting the user input
    Prompt the user
    Get the number to graph
    
  • Now we need an algorithm to display the bar graph
  • Since we need to repeat stars ('*'), we realize that we need to use a loop
  • Also, in a flash of inspiration, we realize that this problem is like our previous counting loop
  • We start our loop design by considering these things:
    1. Loop body -- which statements to repeat
    2. Loop test condition -- when to loop and when to stop
    3. Loop test update -- must change something to exit the loop
    4. Initialization code -- how to get started correctly
  • First we decide what needs to be repeated inside the loop
    print out a '*'
    
  • Then we realize we are going to output a specific number of stars
  • Thus we can use our standard counting loop:
    for (int i = 0; i < max number; i++)
    
  • We know that max number is the number entered by the user
  • Putting all the pieces together we have:
    Prompt the user
    Get the number of stars to graph
    set count = 0
    for (int i = 0; i < number of stars; i++)
        print out a '*'
    
  • We test this manually with a small number like 3 and then translate it into C++ code

Example C++ Application That Displays a Bar Chart

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#include <iostream>
using namespace std;

int main() {
    int number = 0;

    cout << "Enter a number and I will show its"
         << " bar graph.\nEnter your number: ";
    cin >> number;

    cout << "\nBar graph:\n";
    for (int i = 0; i < number; i++) {
        cout << '*';
    }
    cout << endl;

    return 0;
}

Check Yourself

Map the following terms to the example code:

for (int i = 0; i < number; i++) {
    cout << '*';
}
  1. Initialization
  2. Test condition
  3. Loop body
  4. Update

5.1.4: Summing Numbers

  • One common looping task is to input a list of numbers and calculate their sum
  • For example, given the task:

    Display the sum of the numbers from 1 through n, where n can be any positive number greater than 0.

  • We start analyzing the problem working out a problem manually:
    sum = 1 + 2 + 3 + 4 + 5 = 15
  • As we look at the problem, we notice that the difference from one number to the next is just 1
  • In a flash of inspiration, we realize that this problem is like our counting loop
  • We need to count the numbers from 1 to 5
  • However, instead of printing the numbers, we need to add them to some variable
  • Since we understand our problem, our next step is to write our algorithm
  • We start with getting the user input
    Prompt the user
    Get the number to sum to
    
  • We start our loop design by considering these things:
    1. Loop body -- which statements to repeat
    2. Loop test condition -- when to loop and when to stop
    3. Loop test update -- must change something to exit the loop
    4. Initialization code -- how to get started correctly
  • First we decide what needs to be repeated during the loop
    sum = sum + counter
    
  • We start with our standard counting loop:
    for (int i = 0; i < max number; i++)
    
  • We know that max number is the number entered by the user
  • However, we realize that adding 0 has no effect, thus we start at 1 instead
  • Also, we need to include our final number, so we change the test condition to <=
  • Putting all the pieces together we have:
    Prompt the user
    Get the max number
    set sum = 0
    for (int i = 1; i <= max number; i++)
        sum = sum + i
    
  • We test this manually and find we forgot to display the sum after the loop:
    Display the sum after the loop
  • We add the missing step and then translate the algorithm into C++ code

Example Application to Sum a Sequence of Numbers

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#include <iostream>
using namespace std;

int main() {
    cout << "Enter the number to sum to: ";
    int number = 0;
    cin >> number;
    int sum = 0;
    for (int i = 1; i <= number; i++) {
        sum = sum + i;
    }
    cout << "Total sum = " << sum << endl;

    return 0;
}

Check Yourself

  1. What would we change in the loop to sum even numbers only? odd numbers?
  2. What would we change in the code to compute the product of the numbers from 1 to 5?

5.1.5: More Loopy Errors

  • A common problem with counting loops is the off-by-one error
  • Finding the correct upper and lower bounds can be confusing
    • Should you start at 0 or 1?
    • Should you use < or <= as the test condition?
  • To understand the counting loop you need to count iterations
  • For instance, the following loop executes b - a times:
    for (int i = a; i < b; i++)
  • However, the following loop is executed b - a + 1 times:
    for (int i = a; i <= b; i++)
  • The "+1" is the source of many errors
  • For example, to sum the numbers from 1 to 5, what is wrong with:
    #include <iostream>
    using namespace std;
    
    int main() {
        int sum = 0;
        for (int count = 0; count < 5; count++) {
            sum += count;
        }
        cout << sum << endl;
    
        return 0;
    }
    
  • One way to visualize the "+1" error is by looking at a fence

    Fenceposts in a fence

  • How many posts do you need for a fence with three sections? (answer)
  • It is easy to be "off-by-one" with problems like this
  • Forgetting to count the last value is sometimes called a fence-post error

Debugging Technique: Tracing Variables

  • One good way to discover loopy errors is to display the variables that are part of the loop
  • Tracing variables means watching their values change as the program executes
  • You can insert temporary output statements in your program to watch the variables, like:
    cout << "count=" << count << ", sum=" << sum << endl;

5.1.6: Summary

  • One common use for loops is to count numbers
  • The for loop gives us a compact way to program counter-controlled loops
    for (i = start; i < end; i++) {
        ...
    }
    
  • Once you know that a program needs a loop, you need to consider these things:
    1. Loop body -- which statements to repeat
    2. Loop test condition -- when to loop and when to stop
    3. Loop test update -- must change something to exit the loop
    4. Initialization code -- how to get started correctly
  • The for loop lets you specify the last two items in the for statement
  • We saw several applications for loops that count in this section:
    • Counting loops
    • Making bar graphs
    • Summing numbers

Check Yourself

Answer these questions to check your understanding. You can find more information by following the links after the question.

  1. What must always consider when designing a looping algorithm? (5.1.1)
  2. What makes a loop a counting loop? (5.1.2)
  3. What does the following code display: (5.1.2)
    for (int counter = 0; counter < 0; counter++) {
        cout << counter << endl;
    }
    
  4. What does the following code display: (5.1.2)
    for (int counter = 5; counter > 0; counter--) {
        cout << counter << endl;
    }
    
  5. How do you code a loop to display horizontal bar graphs? (5.1.3)
  6. How do you code a loop to sum numbers? (5.1.4)
  7. What is a "fence-post error"? (5.1.5)

5.2: Nested Loops

Learner Outcomes

At the end of the lesson the student will be able to:

  • Write nested for loops
  • Hand trace the execution of for loops

5.2.1: About Nested Loops

  • Some looping applications have loops nested within other loops
  • For example, you may use a nested loop to print a table of values
  • The following example shows a simple table created with nested loops
  • Let's follow the execution sequence before checking the result

Example of Nested Loops

1
2
3
4
5
6
7
8
9
10
#include <iostream>
using namespace std;

int main() {
    for (int outer = 1; outer < 4; outer++) {
        for (int inner = 1; inner < 4; inner++) {
            cout << outer << " " << inner << endl;
        }
    }
}

Tracing the Variables

  • To understand a looping application, you need to trace the loop by hand
  • To trace the loop, write the variables used in the loop as headings across a page
  • On the first line under the headings, write the initial values
  • Execute the loop 3-5 times and record the values of the variables each time through the loop
  • Pay especial attention when entering the loop the first time and when ending the loop
  • You can slightly modify the computations if it helps to test the loop
  • Below is an annotated trace of the variables for the inner and outer loops
  • Note that the outer loop changes only after the inner loop is finished
Memory  Screen 
 outer   inner   
  1   1 1 1
    2 1 2
    3 1 3
    4 (end of loop)    
  2   1 2 1
    2 2 2
    3 2 3
    4 (end of loop)    
  3   1 3 1
    2 3 2
    3 3 3
    4 (end of loop)    
  4 (end of loop)       

5.2.2: Nested Loop Example: Drawing Squares

  • Another example of a nested loop is to draw a square using stars ("*")
  • The code for drawing a square consists of two loops, one nested inside the other:
    for (int row = 1; row <= size; row++) {
        for (int col = 1; col <= size; col++) {
            cout << "*";
        }
        cout << endl;
    }
    
  • The code is easier to read from the inside out
  • The inner loop draws a line of characters across the screen from left to right
  • At the end of the inner loop we print a newline to end the line of characters
  • The outer loop controls the number of lines to draw
  • Note how the inner loop is indented to make the structure clear
  • The inner loop is controlled by the outer loop, which is why it is indented
  • The inner loop in turn controls other statements, which ends up indenting yet again
  • Whenever you type an opening brace ({) you should indent the next character
  • Whenever you type a closing brace (}) you should remove the indentation (outdent)

Example Program to Draw Squares

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#include <iostream>
using namespace std;

int main() {
    cout << "I will print squares for you!\n\n";
    cout << "Enter the width of the square: ";
    int size;
    cin >> size;

    for (int row = 1; row <= size; row++) {
        for (int col = 1; col <= size; col++) {
            cout << "*";
        }
        cout << endl;
    }

    return 0;
}
  • You can make the square hollow by using an if statement inside the inner loop to decide when to print characters
  • Develop test conditions that allow the characters to print only at the start and end of the columns and rows
  • Use an else clause to print spaces when not printing characters
  • Another example of a nested loop is to draw a triangle, which we explore in the next exercise

Exercise 5.2

In this exercise we explore how nested loops work by tracing the execution of a loop in a program. Part of the trace will involve use of the Boolean "or" (||) operator we discussed in lesson 4.2.6.

Specifications

  1. Take out a piece of paper, put your name on it and draw a grid like this:

    row col # 1 2 3 4 5
    1 1 2 1 *        
    2 1 2 3 2 * *      
        3          
        4          
        5          

    Leave extra room for the col column as shown. The right hand area is for drawing the shape where the row and column headings match the row and col variables of the program.

  2. For the program listed below, trace the loop variables and write the values of the loop variables on the paper as your trace progresses for 5 rows. In addition, draw on your paper the shape printed by the nested loops in the program.

    The first few entries are shown in the table. As you trace the program, cross out the col entries as you update them, as shown. However, make each row change start on a new row so that the graph on the right lines up with the row entries.

  3. Review the hand trace with another student in the class.
  4. In a text file named drawing.txt, record your answers to the following questions:

    Q1: What was the name of the person with whom you reviewed your trace?

    Q2: What is the purpose of the if statement inside the inner loop?

    Q3: Which test condition of the if statement controls the printing of the hypotenuse (long side) of the triangle?

  5. Submit drawing.txt to Blackboard as part of assignment 5.
  6. Hand your paper with the trace information to the instructor before you leave.

File to Trace

#include <iostream>
using namespace std;

int main() {
    cout << "I will draw triangles for you!\n\n";
    cout << "Enter the width of the triangle: ";
    int size;
    cin >> size;

    for (int row = 1; row <= size; row++) {
        for (int col = 1; col <= row; col++) {
            if (col == 1 || row == col || row == size) {
                cout << "*";
            } else {
                cout << ".";
            }
        }
        cout << endl;
    }

    return 0;
}

As time permits, review the summary below and be prepared to answer the Check Yourself questions.

5.2.3: Summary

  • Some looping applications have loops nested within other loops
  • The structure of nest loops looks like:
    for (int outer = 1; outer < 4; outer++) {
        for (int inner = 1; inner < 4; inner++) {
            cout << outer << " " << inner << endl;
        }
    }
    
  • We looked at one application that printed a simple table
  • In addition, we looked at other applications that drew shapes, like squares and triangles, using stars ("*")

Check Yourself

Answer these questions to check your understanding. You can find more information by following the links after the question.

  1. True or false? You can nest if statements but not loop statements. (5.2.1)
  2. What is a nested loop? (5.2.1)
  3. True or false? Hand tracing a loop means to list the values of the loop variables during each iteration. (5.2.1)
  4. What do the following nested loops display? (5.2.1)
    for (int outer = 1; outer < 4; outer++) {
        for (int inner = 1; inner < 4; inner++) {
            cout << outer + inner << endl;
        }
        cout << endl;
    }
    
  5. True or false? The inner loop should be indented from the outer loop to make the structure clear. (5.2.2)

5.3: More About Loops

Learner Outcomes

At the end of the lesson the student will be able to:

  • Use sentinel values to terminate a loop
  • Describe the advantages of using a Boolean variable to control a loop
  • Use do-while statements to repeat sections of code
  • Develop strategies for processing input and handling errors

5.3.1: Indefinite Loops

  • Recall our looping application that simulated the play of an exciting game
1
2
3
4
5
6
7
8
9
10
11
12
13
14
#include <iostream>
using namespace std;

int main() {
    string repeat = "y";
    while ("y" == repeat) {
        cout << "\nPlaying an exciting game!\n";
        cout << "Do you want to play again? (y/n) ";
        cin >> repeat;
    }
    cout << "\nThanks for playing!\n";

    return 0;
}
  • Loops of this type are called indefinite loops because you do not know in advance how many time the loop will execute
  • This behavior is different from a counting loop where you know how many times the loop will execute before the loop starts
  • With an indefinite loop we can solve a new set of problems
  • Most problems solved with indefinite loops make use of while statements

While loop flow chart

Check Yourself

  1. True or false: with an indefinite loop, you know in advance how many times the loop will repeat.
  2. True or false: the best looping statement for an indefinite loop is a for statement.
  3. True or false: a counting loop is a good example of an indefinite loop.

5.3.2: Indefinite Loop Example

  • As an example of an indefinite loop, let us look at the problem of compounding interest
  • If we invest $10,000 at 5% interest, compounded annually, our savings grow like this:
    Year Balance
    0 $10,000
    1 $10,500
    2 $11,025
    3 $11,576.25
    4 $12,155.06
    5 $12,762.82
  • How many years does it take for the initial investment to double?
  • To solve this problem we can use a while loop:
    double balance = 10000;
    int year = 0;
    while (balance < 20000) {
        year++;
        double interest = balance * 0.05; // 5% interest
        balance = balance + interest;
    }
    
  • We can make the loop work for any interest rate, starting balance and target amount as shown below

Program with an Indefinite Loop

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
#include <iostream>
#include <iomanip>
using namespace std;

int main() {
    double balance = 0;
    double target = 0;
    double rate = 0;

    cout << "Enter the starting balance: ";
    cin >> balance;
    cout << "Enter the interest rate as a percent: ";
    cin >> rate;
    cout << "Enter the target amount: ";
    cin >> target;

    cout << fixed << setprecision(2);
    cout << "\nYear\tBalance\n";

    int year = 0;
    cout << year << '\t' << balance << endl;
    while (balance < target) {
        year++;
        double interest = balance * rate / 100;
        balance = balance + interest;
        cout << year << '\t' << balance << endl;
    }
    cout << "\nTarget amount of $" << target
         << " reached after " << year << " years.\n" ;

    return 0;
}

Check Yourself

  1. Why does the above program include the <iomanip> library?
  2. If the interest rate is 5%, how many years does it take for an investment to double?
  3. How many years does it take for an investment of $10,000 to triple at 5% interest?
  4. If the interest rate is 10%, how many years does it take for an investment of $10,000 to double?
  5. Can you easily predict how times the loop in the above program would repeat to double an investments at a certain interest rate? If so, how?

5.3.3: Processing a Sequence of Inputs

  • Another common use for indefinite loops is to process a sequence of inputs
  • As an example, let us add up (sum) a series of numbers
  • Every number is added to the sum
  • We use a loop to repeat the input until the user decides to stop
  • Since we do not know how many number the user will enter, we use an indefinite loop as shown below
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#include <iostream>
using namespace std;

int main() {
    double input = 1;
    double sum = 0;
    string repeat = "y";

    cout << "I will add up numbers for you\n\n";
    while ("y" == repeat) {
        cout << "So far, sum = " << sum << endl;
        cout << "Enter a number: ";
        cin >> input;
        sum = sum + input;

        cout << "Another number? (y/n) ";
        cin >> repeat;
    }
    cout << "Ending sum: " << sum << endl;

    return 0;
}

Terminating the Input with a Sentinel

A sentry

  • Whenever we read a sequence of input values, we need to have some way of terminating the input loop
  • We could use a separate variable and input statement as we have done before:
    string repeat = "y";
    while ("y" == repeat) {
        // ... statements to repeat
        cin >> repeat;
    }
    
  • However, when entering numbers (or other data) repeatedly, answering an extra question each time through the loop becomes annoying
  • One way to avoid asking an extra question is to use a sentinel value
  • A sentinel is guard who watches for something to happen
  • Similarly, a sentinel in a program watches for a specific sentinel value that signals termination of a loop
  • To use a sentinel value, we must have a special value in the input
  • Some commonly used sentinel values for numeric input are 0 or -1
  • However, if our application suggests another value, then we should use that value
  • The following program is an update of the previous program to use a sentinel value to end the loop

Example Application Using a Sentinel Value for the Loop Test

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#include <iostream>
using namespace std;

int main() {
    double input = 1;
    double sum = 0;

    cout << "I will add up numbers for you\n\n";
    while (input != 0) {
        cout << "So far, sum = " << sum << endl;
        cout << "Enter a number or 0 to exit: ";
        cin >> input;
        sum = sum + input;
    }
    cout << "Ending sum: " << sum << endl;

    return 0;
}

Check Yourself

  1. What is a sentinel value?
  2. What happens if the user enters a 0 as their first entry?
  3. When processing input from a user, is it always possible to have a sentinel value? If you think it is not possible, give an example.

5.3.4: Input Validation

  • Another common use for indefinite loops is input validation
  • Input validation combines a loop with one or more if statements
  • The loop repeats input until the user enters reasonable input
  • Since we do not know how many times the loop must execute ahead of time, the loop is indefinite
  • For example, the following program uses a loop to ensure a user enters a positive number
  • The if statement is used to decide when to output an error message

Example of Input Validation Using a Loop

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#include <iostream>
using namespace std;

int main() {
    double input = 0.0; // initialize value
    while (input <= 0) {
        cout << "Enter a positive number: ";
        cin >> input;
        if (input <= 0.0) {
            cout << "You must enter a positive number\n";
        }
    }
    cout << "You entered: " << input << endl;

    return 0;
}

Check Yourself

  1. True or false: the above is an example of an indefinite loop.
  2. Why are there two tests for (input <= 0.0)?

5.3.5: do-while Statements

  • Sometimes we want to execute the body of a loop at least once and perform the loop test after the body was executed
  • For this we can use the do-while (or just do) loop:
    do {
       statements
    } while (test); // loop test
    
  • Where:
    • statements: the statements to execute the first time and repeatedly while the test remains true
    • test: the test condition to evaluate
  • The loop test is placed after the body and executes at the end of the loop
  • The statements in the body of the loop always execute at least once
  • One common use of a do-while loop is to validate user input
  • The following code shows an example where we force the user to enter a positive value

Example do-while Loop Used to Validate Input

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#include <iostream>
using namespace std;

int main() {
    double input = 0.0; // initialize value
    do {
        cout << "Enter a positive number: ";
        cin >> input;
        if (input <= 0.0) {
            cout << "You must enter a positive number\n";
        }
    } while (input <= 0.0); // test condition at end
    cout << "You entered: " << input << endl;

    return 0;
}

When to Use do-while Statements

  • Use the do-while loop when you want to force a minimum of one iteration
  • Note that you can accomplish the same control flow with a while loop
  • However, in some cases we can save a statement by using a do-while loop

Check Yourself

  1. True or false: the test of a do-while loop occurs at the end of the loop.
  2. True or false: the body of a do-while loop always executes at least one time.

5.3.6: Checking for cin Failure

  • Another problem arises if the user enters a string when we expect a number
  • For instance, in the following, we get incorrect results if the user enters "seven"
    double input = 0.0;
    ...
    cin >> input;
    
  • The problem is that cin cannot convert the word "seven" into the number 7
  • When this happens cin fails, sets an error flag and skips the rest of the input operation
  • We can detect the failure condition using code like:
    if (cin.fail()) {
        // the stream failed
    }
    
  • The opposite of cin.fail() is cin.good()
  • Another way to test for cin failure is:
    cin >> input;
    if (cin) {
        // the stream did not fail
    } else {
        // the stream failed
    }
    
  • Using cin by itself is the same as using cin.good()
  • Yet another commonly used strategy is:
    if (cin >> input) {
        // the stream did not fail
    } else {
        // the stream failed
    }
    
  • If cin >> input fails to read a correct value then this expression returns the same thing as cin.good()
  • To clear the failed state you need to both clear the flags and the input stream, like:
    cin.clear();
    cin.ignore(INT_MAX, '\n');
    
  • Using cin.clear() will reset the error flag but leaves the bad input in the input stream
  • Adding cin.ignore(INT_MAX, '\n'); will clear all the input a user enters until the user presses an enter key

Example Program with Input Validation

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
#include <iostream>
using namespace std;

int main() {
    double input = 0.0;
    do {
        cout << "Enter a positive number: ";
        cin >> input;
        if (cin.fail()) {
            cout << "You must enter digits, not words\n";
            cin.clear();
            cin.ignore(INT_MAX, '\n');
            input = -1; // set loop test to fail
        } else if (input <= 0.0) {
            cout << "You must enter a positive number\n";
        }
    } while (input <= 0.0);
    cout << "You entered: " << input << endl;

    return 0;
}

Check Yourself

  1. True or false: when a user enters the wrong type of data, cin fails.
  2. To check cin for failure, call the cin function named ________.
  3. To clear a cin failure call the ________ function.

More Information on Some cin Functions

5.3.7: Using Boolean Variables

  • Another way to control loop termination is to use a Boolean variable
  • The advantage of using boolean variable is that we can check multiple conditions even without a sentinel value
  • The following is the same validation loop rewritten using a Boolean variable

Example Application Using a Boolean Variable for the Loop Test

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#include <iostream>
using namespace std;

int main() {
    double input = 0.0;
    bool more = true;
    do {
        cout << "Enter a positive number: ";
        cin >> input;
        if (cin.fail()) {
            cout << "You must enter digits, not words\n";
            cin.clear();
            cin.ignore(INT_MAX, '\n');
        } else if (input < 0.0) {
            cout << "You must enter a positive number\n";
        } else {
            more = false;
        }
    } while (more); // test condition
    cout << "You entered: " << input << endl;

    return 0;
}

Simplified Boolean Test Conditions

  • Recall that test conditions in loops and if statements evaluate to either true or false
  • For this reason, most professional programmers consider the following test conditions amateurish:
    while (more == true)  // avoid
    while (more != false) // avoid
    
  • The reason is that == true and != false are not needed for correct operation
  • Instead, we can simplify either test condition to:
    while (more)
    
  • However, if using a relational operator is clearer for you then do so

Check Yourself

  1. True or false: you can use a Boolean variable to control loop termination.
  2. True or false: the following two loop conditions are equivalent for the Boolean variable named more.
    while (more)
    while (more == true)
    

5.3.8: How to Write a Loop

  • When your program needs to do the same commands repeatedly, you should consider writing a loop
  • We have covered several common situations in which to use loops:
    • Repeating a program or part of a program
    • Counting a series of items
    • Displaying a series of numbers or items
    • Processing a series of items, such as the characters in a string
    • Repeating a series of calculations to arrive at a goal
    • Processing a sequence of inputs
    • Validating input
  • In this section we look at a step-by-step procedure for developing a loop like that shown in the textbook on pages 154-156
  • As an example, let us solve the problem:

    From a series of numbers entered by a user, such as for cash register receipts, find the total and highest number.

1. Decide what work must be done inside the loop

  • If the commands to repeat are not obvious, start by writing down the steps you would take to solve the problem by hand
  • For our example, the steps are something like:

    Read the first value
    Add the first value to the total
    Set the highest value as the first value
    Read the second value
    Add the second value to the total
    If the second value is higher than the highest, set the highest to the second value
    Read the next value
    Add this next value to the total
    If this next value is higher than the highest, set the highest to this next value
    ...

  • From these steps, look for the parts that are repeated and write them so they are uniform, like:

    Read the next value
    Add this next value to the total
    If this next value is higher than the highest, set the highest to this next value

  • These become the statements that go inside the loop
  • Thus you end up with psuedocode like:
    loop
        read the next value
        total = total + next value
        if next value > highest
            highest = next value
    

2. Write the loop condition

  • Decide what goal you want your loop to reach
  • For instance:
    • Has a counter reached the final value?
    • Has the user entered the last input value?
    • Has the loop reached a certain threshold?
  • For out example, we want to know if the user has entered the last value
  • Since we are totaling numbers, and we would not bother to enter the number zero, we can use zero as the sentinel value
  • Thus our test condition is something like:
    loop while the next value != 0
  • Remember that the test condition is about how to keep the loop going
  • When choosing a sentinel, we must make certain that the sentinel value is not used in the computation
  • For instance, entering a zero to exit the loop could end up being the highest value if all the numbers entered were negative
  • We correct this problem by adding an if statement that excludes the sentinel value from the computations
  • Thus our loop now looks like:
    loop while the next value != 0
        read the next value
        if next value != 0
            total = total + next value
            if next value > highest
                highest = next value
    

3. Choose the loop type

  • By this time you should have a good idea what your loop is doing
  • Decide on the loop statement as follows:
    1. If you know in advance of the loop how many times it repeats, use a for loop
    2. Otherwise, if the loop must be executed at least once, use a do-while loop
    3. Otherwise, use a while loop
  • For our example:
    1. The number of times the loop will execute is unknown before the loop starts
    2. There is no need to force the loop body to execute at least once
    3. Thus, we should use a while loop

4. Initialize the loop variables

  • For each of the variables used in the loop, determine what their first value must be
  • Usually, counter variables are set to 0 or 1 and totals to 0
  • In our example, the variables are:
    next value
    total
    highest
    
  • Both next value and total can be initialized to zero
  • However, we need to be careful about highest value
  • We cannot set it to zero because the user can enter negative numbers
  • For instance, if the user enters -1, -2 and then a 0 to exit, the highest value would compute as 0
  • A common strategy in this case is to set the highest value to the first value read
  • Thus our initialization looks like:
    read the first value
    total = first value
    highest = first value
    

5. Process the loop results

  • Sometimes this step is simply to use a variable computed in the loop
  • Other times you must do more computations with the variables from the loop
  • For our example, we only need to display the total and highest number
  • The psuedocode for our complete loop is:
    read the first value
    total = first value
    highest = first value
    loop while the next value != 0
        read the next value
        if next value != 0
            total = total + next value
            if next value > highest
                highest = next value
    Print total and highest
    

6. Trace the loop with example values

  • Before translating our algorithm to C++, we need to test it by hand with tracing
  • Write the variables used in the loop as headings across a page
  • On the first line under the headings, write the initial values
  • Execute the loop 3-5 times to check for errors
  • Pay especial attention when entering the loop the first time and when ending the loop
  • You can slightly modify the computations if it helps to test the loop
  • For our example, we can trace the execution as shown below

    value total highest
    10 10 10
    20 30 20
    30 60 30
    -10 50 30
    0 50 30

  • The trace shows that total and highest are properly set by the algorithm

7. Translate the algorithm to C++ and test the C++ code

  • When we are sure the algorithm works, we write the C++ code
  • Then we compile and test with some typical values
  • The complete program is shown below
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
#include <iostream>
using namespace std;

int main() {
    cout << "I will add up numbers for you\n\n";
    cout << "Enter the first value (0 to exit): ";
    double value;
    cin >> value;
    double total = value;
    double highest = value;
    while (value != 0) {
        cout << "Enter the next value (0 to exit): ";
        cin >> value;
        if (value != 0) {
            total = total + value;
            if (value > highest) highest = value;
        }
    }
    cout << "The total is " << total
         << " and the highest value value is "
         << highest << endl;

    return 0;
}

Exercise 5.3

In this exercise we use indefinite loops to process user input and to ensure correct user input.

Specifications

  1. Copy the following program into a text editor, save it as scores.cpp, and then compile and run the starter program to make sure you copied it correctly.
    #include <iostream>
    using namespace std;
    
    int main() {
        // Enter your code here
    
        return 0;
    }
    
  2. Declare two variables of type double named sumScores and nextScore and initialize the variables to 0. In addition, declare an integer variable named count and initialize it to 0. The following is the psuedocode for these steps:
    set sumScores to 0
    set nextScore to 0
    set count to 0
    

    Compile your code to make sure you declared the variables correctly.

  3. Now we want to use a loop to enter a series of scores. Since we do not know how many scores to enter, we use an indefinite loop like the following:

    Listing of while loop

    Compile your code to make sure you added the loop correctly. To exit the loop you will need to enter a negative number.

  4. The loop includes statements to collect the sum of the scores in the variable named sumScores. Add a statement after the loop to print sumScores to the console. When you run the program after adding this code, the output should look like:
    Score 1: 38
    Score 2: 39
    Score 3: -1
    
    Sum of scores: 77
    

    The loop uses the sumScores variable to accumulate scores during each repetition of the loop like that shown in lesson: 5.3.3: Processing a Sequence of Inputs.

  5. We could write our indefinite loop using a do-while loop instead. Replace your current loop with the following:

    Listing of do-while loop

    Note that the statements inside the loop did not change, only the loop statement itself. To make sure you made the changes correctly, compile and run your code and check to see if it works the same. The difference between a while and do-while loop is that a do-while ensures the body of the loop is executed at least once. For more information see lesson: 5.3.5: do-while Statements.

  6. One problem with our program is the user can still enter letters instead of digits. We can prevent this error by checking cin.fail() and looping until the user enters a correct value. Replace the current if statement with the following:

    Error checking if statement

    Note that the second if statement is the same as the current if statement. Compile and run your program to make sure you added the changes correctly. Try entering letters instead of digits and verify you see an error message. For more information see section: 5.3.6: Checking for cin Failure.

  7. Submit your final program source code to Blackboard as part of assignment 5.

As time permits, read the following sections and be prepared to answer the Check Yourself questions in the section: 5.3.8: Summary.

5.3.8: Summary

  • In this section we looked at using indefinite loops
  • With an indefinite loop, you do not know how many time the loop will execute ahead of time
  • One example was the main loop, where you let the user repeat your program
  • Since you do not know how many times the user will repeat ahead of time, the loop is indefinite
  • Another indefinite loop example was how long it took an investment to double
  • The amount of time depends on the investment and the interest rate
  • Another common use for indefinite loops is to process a sequence of inputs
  • Whenever we read a sequence of input values, we need to have some way of terminating the input loop
  • Since entering extra data each time through a loop is annoying, we discussed using a sentinel value to terminate the loop
  • A sentinel controlled loop looks for a sentinel value in the input data
  • A sentinel value is a special number (or other data) used to signal termination of a loop
  • We looked at how to sum numbers with a sentinel-controlled loop
  • Another common use for indefinite loops is input validation
  • Input validation combines a loop with one or more if statements
  • The loop repeats input until the user enters reasonable input
  • Since we do not know how many times the loop must execute ahead of time, the loop is indefinite
  • Another looping statement is the do-while loop, which tests the condition at the end of the loop body:
    do {
       statements
    } while (test); //loop condition
    
  • Testing at the end ensures a minimum of at least one iteration
  • We also looked at how to test cin for failure
  • The cin input stream fails if the user enters a string when we expect a number
  • We looked at how to add checks for cin failure to our input validation
  • Finally, we discussed a step-by-step procedure for developing loops

Check Yourself

Answer these questions to check your understanding. You can find more information by following the links after the question.

  1. What is an indefinite loop? (5.3.1)
  2. How many times does an indefinite loop execute? (5.3.1)
  3. For the program in section 5.3.2, how many years does it take to double $10,000 at 10% interest? (5.3.2)
  4. What is a sentinel value? (5.3.3)
  5. What is the advantage of using a sentinel value to terminate a loop? (5.3.3)
  6. What is input validation? (5.3.4)
  7. What is the difference between a while and a do-while loop? (5.3.5)
  8. What is a test condition you can use to see if cin has failed? (5.3.6)
  9. What is a good test to validate that the user did not enter a string after the following statements execute: (5.3.6)
    double x;
    cout << "Enter a number: ";
    cin >> x;
    
  10. What two statements can you use to fix cin if it has failed due to bad input? (5.3.6)
  11. When designing a loop, how do you decide what work is done inside the loop? (5.3.7)

Wrap Up

Due Next:
A4-Making Selections (3/8/12)
A5-Loopy Programs (3/15/12)
  • When class is over, please shut down your computer
  • You may complete unfinished exercises at the end of the class or at any time before the next class.
Home | Blackboard | Day Schedule | Eve Schedule
Syllabus | Help | FAQ's | HowTo's | Links
Last Updated: April 23 2012 @01:04:44