Computer Science - C++   Lesson 9:  while loops

Introduction:                
In many situations, the number of times a loop will occur is dependent on some changing condition within the loop itself.  The while control structure allows us to set up a conditional loop, one which occurs for an indefinite period of time until some condition becomes false.  In this lesson we will focus on while loops with some minor usage of nested if-else statements inside.  Later on in the course you will be asked to solve very complex nesting of selection, iterative, and sequential control structures.  The while loops are extremely useful but also very susceptible to errors.  This lesson will cover key methodology issues which assist in developing correct loops.  

Learning Objectives:

A.    The while Loop B.    Loop Boundaries
C.    The break Statement Variations D.   Conditional Loop Strategies

Vocabulary:                    

boundary The borders or limits of the conditional test.
break A command which forces an immediate end to a control structure.
sentinel A specific value is entered as input to use as the stopping value for the while loop.
state Condition
while control structure allowing us to set up a conditional loop

Discussion:                       

A.    The while Loop

1.    The general form of a while statement is:

while (expression) 
        statement;

a.     As in the if-else control structure, the Boolean expression must be enclosed in parentheses ( ).
b.    The statement executed by the while loop can be a simple statement, or a compound statement blocked with braces {}.

 2.    If the expression is true the statement is executed.  After execution of the statement, program control returns to the top of the while construct.  The statement will continue to be executed until the expression evaluates as false.

 3.    The following diagram illustrates the flow of control in a while loop:

            

4.    The following loop will print out the integers from 1-10. 

number = 1;                                                    // initialize

while (number <= 10)                                    // loop boundary condition
{
         cout << number << endl;
         number++;                                              //  increment
}

 5.    The above example has three key lines which need emphasis:

 a.     You must initialize the loop control variable (lcv).  If you do not initialize number to 1, the initial value of number is a garbage value and the results are unpredictable.

b.    The loop boundary conditional test (number <= 10) is often a source of error.  Make sure that you have the correct comparison (<, >, ==, <=, >=, !=) and that the boundary value is correct.

c.     There must be some type of increment or other statement which allows the loop boundary to eventually become false.  Otherwise the program will get stuck in an endless loop.

6.    It is possible for the while loop to occur zero times.  If the condition is false due to some initial value, the statement inside of the while loop will never happen.  This is appropriate in some cases.

 B.    Loop Boundaries

1.    The loop boundary is the Boolean expression which evaluates as true or false.  We must consider two aspects as we devise the loop boundary:

a.     It must eventually become false, which allows the loop to exit.

b.    It must be related to the task of the loop.  When the task is done, the loop boundary must become false.

 2.    There are a variety of loop boundaries of which two will be discussed in this section.

3.    The first is the idea of attaining a certain count or limit.  The code in section A.4 is an example of a count type of bounds.

Student Answer:

4.    Sample problem:  In the margin to the left, write a program fragment which prints the even numbers 2-20.  Use a while loop.

 5.    A second type of boundary construction involves the use of a sentinel value.  In this category, the while loop continues until a specific value is entered as input.  The loop watches out for this sentinel value, continuing to execute until this special value is input.  For example, here is a loop which keeps a running total of positive integers, terminated by a negative value.

total = 0;

number = 1;            // set to an arbitrary value to get inside the loop

while (number >= 0)

{

         cout << "Enter a number (-1 to quit) --> ";

         cin >> number;

         if (number >= 0)

                 total += number;

}

cout << "Total = " << total << endl;

 

a.     Initialize number to some positive value.  A random garbage value could be negative and the loop would never begin.

b.    The if (number >= 0) expression is used to avoid adding the sentinel value into the running total.

 C.    The break Statement Variations

1.    C++ provides a break command which forces an immediate end to a control structure (while, for, do, and switch).

 2.    The same problem of keeping a running total of integers provides an example of using the break statement:

 

total = 0;
number = 1;    /* set to an arbitrary value */

while (number >= 0)
{
         cout << "Enter a number (-1 to quit) --> ";
         cin >> number;
         if (number < 0)  break;
         total += number;   // this does not get executed if number < 0
}

a.     As long as (number >= 0), the break statement will not occur and number is added to total.

b.    When a negative number is typed in, the break statement will cause program control to immediately exit the while loop.

3.    The keyword break causes program control to exit out of a while loop.  This contradicts the rule of structured programming which states that a control structure should have only one entrance and one exit point.

 4.    The switch structure (to be covered in a later lesson) will require the use of the break statement.

D.    Conditional Loop Strategies

1.    This section will present a variety of strategies which assist the novice programmer in developing correct while loops.  The problem to be solved is described first.

Problem statement: A program will read integer test scores from the keyboard until a negative value is typed in.  The program will drop the lowest score from the total and print the average of the remaining scores.

2.    One strategy to utilize in the construction of a while loop is to think about the following four sections of the loop:  initialization, loop boundary, contents of loop, and the state of variables after the loop.

a.     Initialization - Variables will usually need to be initialized before you get into the loop.  This is especially true of while loops which have the boundary condition at the top of the control structure.

b.    Loop boundary - You must construct a Boolean expression which becomes false when the problem is done.  This is the most common source of error in coding a while loop.  Be careful of off-by-one errors which cause the loop to happen one too few or one too many times.

 c.     Contents of loop - This is where the problem is solved.  The statement of the loop must also provide the opportunity to reach the loop boundary.  If there is no movement toward the loop boundary you will get stuck in an endless loop.

 d.    State of variables after loop - To ensure the correctness of your loop you must determine on paper the status of key variables used in your loop.  This involves tracing of code which is demanding but necessary.

3.    We now solve the problem by first developing pseudocode.

Pseudocode:

initialize total and count to 0
initialize smallest to INT_MAX
get first score
while score is not a negative value
       increment total
       increment count
       change smallest if necessary
       get next score
subtract smallest from total
calculate average

4.    And now the code:

#include <iostream.h>
#include <limits.h>

main ()
{
         int  total=0;
         int  smallest = INT_MAX;
         int  score;
         double  avg;
         cout << "Enter a score (-1 to quit) ---> ";
         cin >> score;
         while (score >= 0)                           // loop boundary
         {
                total += score;
                count++;
                if (score < smallest)
                         smallest = score;              //  maintain state of smallest
                cout << "Enter a score (-1 to quit) ---> ";
                cin >> score;                  //  allows us to approach boundary
         }

         if (count > 1)
        {
             total -= smallest;
             avg = double (total)/(count-1);
             cout << "Average = " << avg << endl;
         }
         else
              cout << "Insufficient data to average" << endl;
}

5.    Tracing code is best done in a chart or table format.  It keeps your data organized instead of marking values all over the page.  We now trace the following sample data input:

       65   23   81   17   45   -1

score

score >= 0

total

count

smallest

 

undefined

undefined

0

0

INT_MAX

65

1 (true)

65

1

65

23

1 (true)

88

2

23

81

1 (true)

169

3

23

17

1 (true)

186

4

17

45

1 (true)

231

5

17

-1

0 (false)

 

 

 

       When the loop is terminated the three key variables (total, score, and smallest) contain the correct answers.

6.    Another development tool used by programmers is the concept of a state variable.  The term state refers to the condition or value of a variable.  The variable smallest maintains state information for us, that of the smallest value read so far.  There are three aspects to consider about state variables:

a.     A state variable must be initialized.

b.    The state will be changed as appropriate.

c.     The state must be maintained as appropriate.

       In the chart above, smallest was initialized to the highest possible integer.  As data was read, smallest was changed only if a newer smaller value was encountered.  If a larger value was read, the state variable did not change. 

7.    When analyzing the correctness of state variables you should consider three things.

  1. Is the state initialized?

  2. Will the state find the correct answer?

  3. Will the state maintain the correct answer?

  As first-time programmers, students will often initialize and find the state, but their code will lose the state information as the loop continues on.  Learn to recognize when you are using a state variable and focus on these three parts:  initialize, find, and maintain state.

8.    Later on in the year we will add the strategy of developing loop boundaries using DeMorgan's law from Boolean algebra.  This advanced topic will be covered in Lesson 17.

Lesson 9 Pointers

Summary/Review:          This lesson provides both syntax and strategies needed to build correct while loops.  The terminology of loop construction will give us tools to build and debug conditional loops.  We can use terms such as "off-by-one" errors or "failure to maintain state."  This is a critical topic, one which takes much time and practice to master. 

Assignment:                     Lab Exercise, L.A.9.1, Loan

                                                 Lab Exercise, L.A.9.2, FunLoops