Welcome to Lesson 13!


Learning Objectives
By the end of today's lesson, you should be able to answer the following questions...

  • What is a nested loop?
  • What is an application of a nested loop?
  • What is a do-while loop?
  • How does the syntax of a do-while loop compare to that of a while loop?
  • When do you use a do-while loop instead of a while loop?
  • When a user enters a string rather than a number, how do you handle the user error?
  • What is the difference between cin.good() and cin.fail()?
  • What are cin.clear() and cin.ignore(1000,'\n');?

Announcements

  • Quiz 5 on Thursday
    • Return Quiz 4 during an activity
  • Friday is a holiday - No lab!
  • Google Career Panel Extra Credit
    • Attend Google panel 12:30-2:00pm this Thursday, November 9 in the VPAC theater
    • Sign in with me during the event to receive 20pts E.C. on assignments.


Review Questions

Find a partner and answer the following questions:
  • Change the following for loop into the equivalent while loop:

for (int i = 10; i < 20; i++)
{
    cout << "*";
}
  • What will the following for loop print to the console window?

for (int i = 5; i < 10; i++)
{

    if (i % 3 == 0)

        cout << "*";

    else

        cout << "!";

}


Nested Loops

About Nested Loops
  • Some applications require loops within loops, called "nested" 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
11
12
13
#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 any 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 special 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 variable outer changes only after the inner loop is finished
Memory Screen 
 outer  inner  
  1  11 1
   21 2
   31 3
   4 (end of loop)   
  2  12 1
   22 2
   32 3
   4 (end of loop)   
  3  13 1
   23 2
   33 3
   4 (end of loop)   
  4 (end of loop)     
  • By analogy, nested loops are like an odometer on a car
  • The inner loop is like the digit to the right on an odometer
  • The numbers to the right loop completely before the number to the left increments by one


Nested Loop Example: Drawing Squares
  • Another example of a nested loop is to draw a square using stars ("*")
  • Remember our bar graph example with the for loop?

#include <iostream>
using namespace std;

int main() {
int size = 0;
cout << "Enter a number and I will show its"
<< " bar graph.\nEnter your number: ";

cin >> size;

cout << "\nBar graph:\n";

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

return 0;
}
  • Now, let's alter the program to contain a nested for loop.
  • We will place another for loop inside the first one.
  • The nested loop makes the bar graph print in 2D.
  • 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 are indented yet again
  • Formatting note:
    • 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
19
20
#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;
}
  • We 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

Activity 13.1: Tracing a Nested Loop!

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 last class.

Specifications

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

rowcol#12345
11 21*    
21 2 32**   
  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.
  • For the code snippet 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. Do NOT run the program.
  • You can see the trace for the first few entries in the grid above. 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.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
for (int row = 1; row <= 5; row++)
{
    for (int col = 1; col <= row; col++)
    {
        if (col == 1 || row == col || row == 5)
        {
            cout << "*";
        }
        else
        {
            cout << ".";
        }
    }
    cout << endl;
}
  • When you are finished tracing it on paper, draw your trace into the box provided on Canvas.
  • Do not show your paper to any other students and do not run the code until all students have completed the hand tracing.
  • The instructor will trace it on the board when everyone is finished.



Do-While Loops

  • In some cases, it would be preferable to execute the body of a loop at least once before performing the loop test.
  • In these cases, we can use a do-while loop.
  • The structure of a do-while loop looks like this
    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

Flowchart of do-while loop:

Flowchart of working of do...while loop in C programming.

Image source.

  • One common use of a do-while loop is to validate user input (i.e. check for errors in the 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

#include <iostream>
using namespace std;

int main() {
    double input;
    do {
        cout << "Enter a positive number: ";
        cin >> input;
    } 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

Group Activity
With a partner, answer the following questions:
  • How is the syntax of a do-while loop different from a while loop?
  • When would you use choose a do-while loop over a while loop?
  • Change the following while loop into a do-while loop:

int sum = 0;
int score = 0;

cout << "Enter a score or 0 to quit: ";

cin >> score;

while (score != 0)
{
    sum += score;
    cout << "Enter a score or 0 to quit: ";
    cin >> score;
}
cout << "The sum is: " << sum << endl;

Using Loops for Error Checking

Using Loops to Check for cin Failure

  • A problem arises if the user of a our programs 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.
  • You have probably seen this when you have mistakenly entered the wrong content in your program.
  • We can detect the failure condition using code like:
    while (cin.fail()) { 
        // the stream failed... code to handle failure here
       
       
//Keep prompting the user to enter valid input
        cout << "Please enter a number not a string: ";
       
        cin >> input;
    }
  • As we saw when discussing uses of loops, It is good practice to use a loop in cases like these as the user might enter invalid input more than once.
  • To clear the failed state you need to both clear the flags and the input stream, like:
    cin.clear();
    cin.ignore(1000, '\n');
    
  • Using cin.clear() will reset the error flag but leaves the bad input in the input stream
  • Adding cin.ignore(1000, '\n'); will clear all the input a user enters until the user presses an enter key
  • For example:
while (cin.fail()) { 
        //clear the invalid input
        cin.clear(); //clear the error flag
        cin.ignore(1000, '\n'); //ignore the last 1000 characters or until \n

        // keep prompting user to enter a valid input until they get it right
        cout << "Please enter a number not a string: ";
        cin >> input;
    }
  • Note that we could also use a do-while loop as in the next example.
  • Why would a do-while loop be useful here?
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(1000, '\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;
}
More information on cin functions


Activity 13.2: Scores (10 pts)

  • In this exercise we use indefinite loops to process user input and to ensure correct user input.
  • Find a partner for pair programming.
  • Copy the following program into CodeBlocks, save it as scores.cpp, and then compile and run the starter program to make sure you copied it correctly.
    #include <iostream>
    #include <climits>
    using namespace std;
    
    int main() {
        int sumScores = 0, nextScore = 0, count = 1;
    
        cout << "Enter a series of scores or -1 to quit\n\n";
    }
    
  • Make sure the code compiles and runs.
  • 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:
while loop code

  • In addition, add a statement to display sumScores after the loop.

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

  • 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:
    Enter Score#1: 38
    Enter Score#2: 39
    Enter Score#3: -1
    
    Sum of scores: 77
    

    The loop uses the sumScores variable to accumulate scores during each repetition of the loop. 

  • We could write our indefinite loop using a do-while loop instead. Replace your current loop with the following:
while loop now replaced with 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. 

  • 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:

  • When finished, upload your scores.cpp file to Canvas.


Wrap Up

  • With your partner, answer the questions from today's learning objectives. Additionally:
    • How many times will the following loop execute?
                for (int i = 1; i < 5; i++){
            cout << i << endl;
         }
  • And this one?
         for (int i = 1; i <= 5; i++){
            cout << i << endl;
         }
  • Alter the nested loop below so that it will print rectangles instead of squares:
#include <iostream>
using namespace std;

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

    cout << "Enter the length of the triangle: ";
    int length;
    cin >> length;

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


Upcoming Assignments
  • Assignment 13 due Thursday at 3:20pm on Canvas
  • Quiz 5 on Thursday.
  • No Lab Friday