# Lab 7: More Control Structures

In Lab 4, we considered one of C++'s selection structures — the `if` statement — and two of its repetition structures the `for` and the `while` statements. This lab exercise introduces two more control structures:

• Part 1 describes C++'s `switch` selection statement
• Part 2 describes C++'s `do-while` repetition statement and the "forever loop" — a special type of `for` loop.

## Part 1: Selection Structures

Up to now, the only selection structure we have been using is the `if` statement. It is one of C++'s most versatile statements in that it can be used to implement both two-alternative and multialternative selections. In the first part of this lab exercise we look at another selection structure — the `switch` statement — that is more efficient in some cases, but is limited in its applicability.

### Getting Started

In Lab 4, we developed a simple 5-function calculator program that allowed the user to select from a menu of operations:

• subtract two numbers
• multiply two numbers
• divide two numbers
• raise a number to a power
In this lab we will start with a file `calculate.cpp` that differs from that in Lab 4 in that the menu options are labeled `a`, `b`, `c`, `d`, `e` instead of `+`, `-`, `*`, `/`, `^` and two functions are used:
`getMenuChoice()`: to get the operation selected by the user
`apply()`: to apply the operation to the operands

These may seem like rather minor changes and the menu relabeling even an undesirable one because it is much easier to remember to enter
`+` for addition instead of `a`,
`-` for subtraction instead of `b`,
`*` for multiplication instead of `c`, and so on.
But we will see the reason making this change in the second part of this lab exercise.

Here is a listing of `main()` in `calculate.cpp`:

```int main()
{
//*** ENTER YOUR OPENING OUTPUT STATEMENT(S) HERE

"\tb - to perform subtraction;\n"
"\tc - to perform multiplication;\n"
"\td - to perform division;\n"
"\te - to perform exponentiation;\n"
"--> ";

double op1, op2, result;
cout << "Now enter your operands: ";
cin >> op1 >> op2;
assert( cin.good() );

result = apply(operation, op1, op2);

cout << "The result is " << result << endl;
}
```
You should download/copy `calculate.cpp` into whatever directory/folder/project you are using for this lab exercise.
• Exer. 7.1. Personalize the opening document as specified by your instructor.

• Exer. 7.2. Add an opening output statement in `main()` that outputs information required by your instructor — e.g., your name, course, assignment #.
In the program in Lab #4 we used an `if ... else if ... else` statement to process the user's menu selection. We now look an alternative way to implement this multialternative selection structure.

## The `switch` Statement

The multi-branch `if` suffers from one drawback:

• To perform the addition operation, one condition is evaluated: `(operation == '+')`.
• To perform subtraction, two conditions are evaluated: `(operation == '+')` and `(operation == '-')`.
• To perform multiplication, three conditions must be evaluated: `(operation == '+')`, `(operation == '-')`, and `(operation == '*')`.
• And so on...

Now consider the following general multi-branch `if` statement:

```if (`Condition``1`)
`Statement``1`
else if (`Condition``2`)
`Statement``2`
...
else if (`Conditionn`)
`Statementn`
else
`Statement``n+1````

For `Statementi` to be selected, the `i` conditions `Condition``1`, `Condition``2`, ..., `Condition``i-1`, `Conditioni` must be evaluated. This can be just what is needed when, for example, it is necessary to know that all of the tests preceding the `i`th one did, in fact, fail.

On the other hand, the evaluation of each condition takes time; statements that occur later in the multi-branch `if` statement take longer to execute than statements that occur earlier. In some situations, synchronization is required; the time required to reach any of the `Statementi` must be the same for all `i`.

We look now at one way this can be avoided — by using a `switch` statement, which has the form

```switch ( `SelectorExpression` )
{
`  CaseList``1`
`  StatementList``1`
`  CaseList``2`
`  StatementList``2`
...
`  CaseListn`
`  StatementListn`
default:
`  StatementListn``+1`
}```

where

• `SelectorExpression` is any C++ expression whose value is an integer or is integer-compatible (e.g., `char`);
• each `StatementListi` is a sequence of valid C++ statements;
• and each `CaseListi` is one or more cases of the form
`case `Constant` :`
where `Constant` is an integer-compatible constant.

Pay careful attention to the terminology here.

A `switch` statement is executed as follows:

1. The `SelectorExpression` is evaluated.
2. If the value of the expression is present in `CaseListi`, then execution begins in `StatementListi` and continues until
• a `break` statement,
• a `return` statement,
• or the end of the `switch` statement
is encountered.
3. If the value of `SelectorExpression` is not present in any `CaseListi`, then the (optional) default `StatementListn``+1` is executed.
4. No `Constant` may appear in more than one `CaseListi`.

 Helpful hint: Just as a multi-branch `if` should always have a fail-safe `else` clause, you should always have a `default` case in a `switch` statement, even if it simply prints an error message.

Perhaps the trickiest thing about a `switch` statement is the purpose of the cases. They are merely labels for the compiler to tell it where to start executing code. Consider this code, where `i` is an integer:

```switch (i)
{
case 0:
cout << "Zero ";
case 1:
case 2:
cout << "One Two ";
default:
cout << "Other";
}```

Then, if `i` is 0, this outputs

`Zero One Two Other`
If `i` is 1 or 2, it outputs
`One Two Other`

If `i` is any other value, it outputs

`Other`

As this example illustrates, the various cases specify to the compiler where execution of the code is to begin, but not when to stop — rather, execution "falls through" to the end of the `switch`. This is useful in a few situations, but it isn't what we want here. When we use our 5-function calculator and select option `a` to add two numbers, we don't want to also subtract them, multiply them, divide them, and raise one to the other power.

To stop executing the code at the end of a statement list in one of the cases, we can put a `break` statement, a `return` statement, or a call to `exit()` at the end of the list; for example,

```switch (i)
{
case 0:
cout << "Zero ";
break;
case 1:
case 2:
cout << "One Two ";
break;
default:
cout << "Other";
}```

Now, if `i` is 0, this outputs

`Zero `
and if `i` is 1 or 2, it outputs
`One Two `
and if `i` has any other value, the output will be
`Other`

We have used the `return` statement to return a value from a function; and we have used the `exit()` function to stop a program in case of an error. The `break` statement in the preceding example is even simpler:

`break;`
The following are the key things to remember about using the `switch` statement:

Things to Remember:
 The statement list of every case list in a `switch` statement should end with a `break`, a `return`, or an `exit()`. Each `case` must be a constant. The `SelectorExpression` and the case values must all be integer-compatible. Finding a matching `case` is done only through equality tests.

The integer-compatible data types in C++ include `int`, (of course), `short`, `long`, `unsigned`, `char`, and `bool`.
It does not include
`double` or `string`.

As a guide: If you find yourself using an algorithm of the form on the left of chart below where `Expression` is integer-compatible, you can use the `switch` in the middle, which is equivalent to the multi-branch `if` on the right:

 ``` Set `Variable` to `Expression`. If (`Variable` is equal to `Value1`) `StatementList1` Else if (`Variable` is equal to `Value2`) `StatementList2` ... Else if (`Variable` is equal to `Valuen`) `StatementListn` Else `StatementListn+1` End if``` ``` switch (`Expression`) { case `Value1`: `StatementList1` break; case `Value2`: `StatementList2` break; ... case `Valuen`: `StatementListn` break; default: `StatementListn+1` }``` ```` Variable` = `Expression`; if (`Variable` == `Value1`) { `StatementList1` } else if (`Variable` == `Value2`) { `StatementList2` } ... else if (`Variable` == `Valuen`) { `StatementListn` } else { `StatementListn+1` }```

A `switch` statement is more efficient than the multi-branch `if` statement because a `switch` statement can select any `StatementListi` in the time it takes to evaluate one condition. The `switch` statement thus eliminates the non-uniform execution time of statements controlled by a multi-branch `if` statement. But the restrictions on the `switch` statement do limit its use.

• Exer. 7.3. In the definition of the `apply()` function in `calculate.cpp`, a `switch` has been partially written — it implements the addition operation. Complete this `switch` statement as directed in the comments. Use the default case to handle illegal operations by having it output an error message and return 0. Test your program to ensure that it works; be sure to test each operator, including illegal ones.

## Part 2: Repetition Structures — `do` and forever Loops

The two repetition structures that we used in Lab #4 were a `for` loop and a `while` loop. A ``` for``` loop is designed to count through a range of values and we used it to implement the exponentiation operation. We used a `while` loop to allow the user to repeatedly select a menu option, stopping when a "special" operation was selected. In this lab exercise, we will look at two other kinds of loops: a `do` loop and a forever loop.

### Characterizing Loops

A loop is categorized by when it evaluates its condition:

1. A pretest loop evaluates its condition before its statements.
2. A posttest loop evaluates its condition after its statements.
3. An unrestricted loop evaluates its condition wherever we specify.

The `for` loop is a pretest loop, because it evaluates its condition before the loop's statement is executed. It is designed primarily for problems that involve counting through ranges of numbers or problems in which the number of repetitions can be determined in advance. For many problems, however, we don't know how many repetitions will be needed.

The other three C++ loops differ from the `for` loop in that they are general-purpose loops, designed for problems where the number of repetitions is not known in advance.

1. The C++ `while` loop provides a general pretest loop.
2. The C++ `do` loop provides a general posttest loop.
3. The C++ forever loop provides a general unrestricted loop.

Let's see which of these loops to use to handle menu input.

### Getting a Valid Menu Choice

`getMenuChoice()` is defined in `calculate.cpp` as follows:

```char getMenuChoice(const string MENU)
{
char choice;
cin >> choice;
return choice;
}```
• Exer. 7.4. What happens if the user enters a bad value — one that isn't in the menu? Execute the current version of `calculate.cpp` to find out and describe what happens.

We can make our program more user-friendly by handling input errors in this function. One way is to reject bad values entered by the user and to keep on displaying the menu until the user enters a valid menu item. How many repetitions will be needed before this happens isn't something we can predict because we have no idea how many times the user will input bad data.

The general-purpose loops give us a way to handle such user errors, but we must decide which one to use. We can begin by using a generic loop in which we don't worry (for now) how control will leave the loop:

1. Loop:
1. Display `MENU`.
2. Read `choice`.
End loop.
2. Return `choice`.

We have seen how conditions are used in `if` and `for` statements to alter the default sequential flow of execution. Similarly, for general purpose loops, there are two types of conditions we can use:

• A continuation condition that specifies when repetition should continue: "When do I keep on going?"
• A termination condition that specifies when repetition should terminate: "When do I stop?"
The kind of loop we use will determine what type of condition we need. When we change from one loop to another, we may have to change the type of condition.

For our problem, we want the repetition to

• continue as long as the user's `choice` is an invalid selection from the menu, and
• terminate when `choice` is a valid selection.

Since `choice` is not known until after the user enters it, we can't check its validity until after Step (b) of the preceding generic loop

1. Loop:
1. Display `MENU`.
2. Read `choice`.
3. If `choice` is a valid menu choice, exit the loop.
End loop.
2. Return `choice`.
In this algorithm, because the controlling condition is evaluated at the bottom of the loop, a post-test loop is the appropriate loop to choose. And in C++, a `do` loop is such a post-test loop; its pattern is as follows:
```do
{
`Statements`
}
while ( `Condition` );```
When execution reaches such a loop, the following actions occur:
1. `Statements` are executed.
2. `Condition` is evaluated.
3. If `Condition` is true, control returns to step 1; otherwise, control proceeds to the next statement after the loop.
Because repetition continues as long as the condition is true, a `do` loop uses a continuation condition.

Also, note that its `Condition` is not evaluated until after the first execution of `Statements`. This means that a `do` loop guarantees that `Statements` will be executed one or more times. For this reason, the `do` loop is said to exhibit one-trip behavior — we must make at least one trip through `Statements`.

The notion of a "valid" menu choice can be a bit tricky. One way to make this straightforward is to use consecutive numbers or letters of the alphabet for our menu selections; — e.g., `'a'` through `'e'` as in the menu of operations in this lab.

How does this help? We can pass the first and last valid choices to `getMenuChoice()` as arguments,

`char operation = getMenuChoice(MENU, 'a', 'e');`
and add parameters to the `getMenuChoice()`'s prototype and definition to store these arguments:
`char getMenuChoice(const string MENU, char firstChoice, char lastChoice);`
Exer. 7.5. Add the new arguments to the function call in the driver program. Add the new parameters to the prototype and the definition of `getMenuChoice()`. Recompile the program to check for errors. However, the program won't run any differently yet.

Because `firstChoice` and `lastChoice` will define the range of valid choices, we can express our loop's continuation condition in terms of those values: `choice` is invalid if and only if

`choice < firstChoice || choice > lastChoice`
We are now ready to add a `do` loop to the `getMenuChoice()` function to implement our algorithm.
Exer. 7.6. Add a `do` loop to the definition of the `getMenuChoice()` function.
• The body of the loop consists of the statements to output `MENU` and input `choice`.
• The declaration of `choice` must be before the loop so that it can be returned after the end of the loop.

### Getting Valid Numeric Input

Another potential source of error occurs when our program reads values for the operands `op1` and `op2` from the keyboard — the user might enter some non-numeric value. Our current version checks for this using the `assert()` mechanism and `cin`'s built-in member function `good()`.

But suppose we wish to give the user another chance to enter valid values instead of terminating execution? At first glance, it looks as though we could use the same approach as before, by replacing the `assert()` with a posttest loop that repeats the steps so long as `good()` returns false:

```do
{
// prompt for op1 and op2
// input op1 and op2
}
while ( !cin.good() );```
However, this approach doesn't work well because of two subtleties about `cin` input (actually, `istream` input in general). When the `>>` operator is expecting a value of a certain type but gets a non-compatible value, two things happen, each of which causes a difficulty:

1. When input via `cin` fails, its internal status is set so that its built-in function member `good()` will return false. No input operations can be performed with `cin` so long as `cin.good()` returns false.
2. After failed input, the bad input value stays (unread) in the input stream.

The first problem can be fixed with `cin.clear()`, which resets the status of `cin` so that `cin.good()` returns true again.

But the second problem is more difficult to fix. We don't want the loop to continue reading the same bad value over and over and over again, so we need some way to skip over the bad input. To accomplish this, we can use `cin`'s `ignore()` member function:

`cin.ignore( `NumChars`, `UntilChar` );`
Characters in `cin` will be skipped until `NumChars` have been skipped or until the character `UntilChar` is encountered, whichever comes first. Since lines are usually not more than 120 characters in length, and the end of a line of input is marked by the newline character (`'\n'`), we can use the following to solve this difficulty:
`cin.ignore(120, '\n');`

All of this, however, complicates our choice of which loop to use, because we now have four steps to perform:

1. Display a prompt for two real values. [One or more times.]
2. Input `op1` and `op2`. [One or more times.]
3. `cin.clear();` [Only if necessary — zero or more times.]
4. `cin.ignore(120, '\n');` [Only if necessary — zero or more times.]
It looks like our loop-exit test should be placed in the middle — between steps (b) and (c). A `do` loop isn't going to work.

One traditional solution is modify our algorithm to use a pre-test loop in the following way:

1. Display a prompt for the two operands.
2. Input `op1` and `op2`.
3. Loop while `cin.good()` is false:
1. `cin.clear();`
2. `cin.ignore(120, '\n');`
3. Display a prompt for two real values.
4. Input `op1` and `op2`.
End loop.

The C++ pretest loop is the `while` loop,

```while ( `Condition` )
`Statement````
a pretest loop that we have used before in Lab #4. It works like a `do` loop except that `Condition` is evaluated before the `Statement` is evaluated. If `Condition` is false right away, `Statement` is never executed. For this reason, a `while` loop is said to exhibit zero-trip behavior — we might make zero trips through `Statement`.
Exer. 7.3. Replace the `assert(cin.good());` statement in `main()` with a `while` loop to to implement the while loop in the preceding algorithm. The body of the loop consists of four statements to implement the four statements in the loop of the algorithm — the first two to fix up `cin` and the last two to output a prompt for the real operands and then read them.

### One Execution, Multiple Calculations

The algorithm that our program is using is basically as follows:

1. Display opening output.
2. Define the menu of operations.
3. Call `getMenuChoice()` to get a value for `operation`, guaranteed to be a valid menu operation.
4. Display a prompt for two operands.
5. Input `op1` and `op2`.
6. Loop while a bad operand (not a real value) was entered:
1. Clear the status of `cin`.
2. Skip the invalid input.
3. Display a prompt for two operands.
4. Input `op1` and `op2`.
End loop.
7. Compute `result` by calling `apply()` to apply `operation` to `op1` and`op2`.
8. Display `result`.
Using this algorithm, we have to re-run our program for each calculation, which is inconvenient for the user. A more convenient calculator would wrap some of the statements in a loop, so that the user could perform multiple calculations without having to re-run the program.

To accomplish this, we enclose everything after steps 1 and 2 within a loop as follows:

1. Display opening output.
2. Define the menu of operations.
3. Loop:
1. Call `getMenuChoice()` to get a value for `operation`, guaranteed to be a valid menu operation.
2. Display a prompt for two operands.
3. Input `op1` and `op2`.
4. Loop while a bad operand (not a real value) was entered:
1. Clear the status of `cin`.
2. Skip the invalid input.
3. Display a prompt for two operands.
4. Input `op1` and `op2`.
End loop.
5. Compute `result` by calling `apply()` to apply `operation` to `op1` and`op2`.
6. Display `result`.
End loop.
But, what kind of loop should we use? To answer this, we have to determine where to check the loop's termination condition, which we might express as "the user wants to quit."

In a menu-driven program such as this, a common approach is to add an option to the menu that the user can select to quit — typically, the last item on the menu. So we will provide an additional menu choice `'f'` for quitting. The condition `(operation == 'f')` will be true if the user wishes to quit.

So when do we check this condition? The ideal place is to evaluate it as soon as it can be checked; in this case this would be immediately following the input of `operation`. We thus have a situation where the loop's condition should not be evaluated at the loop's beginning nor at its end but rather, somewhere "in the middle" of the loop.

1. Display opening output.
2. Define the menu of operations.
3. Loop:
1. Call `getMenuChoice()` to get a value for `operation`, guaranteed to be a valid menu operation.
2. If the "quit" operation has been selected, use `break` to exit from the loop.
3. Display a prompt for two operands.
4. Input `op1` and `op2`.
5. Loop while a bad operand (not a real value) was entered:
1. Clear the status of `cin`.
2. Skip the invalid input.
3. Display a prompt for two operands.
4. Input `op1` and `op2`.
End loop.
6. Compute `result` by calling `apply()` to apply `operation` to `op1` and`op2`.
7. Display `result`.
End loop.

In C++, one way to implement an unrestricted loop is with a special form of the `for` loop that we call a forever loop and that has the following pattern:

```for (;;)           // or as some prefer:  while(true)
{
`StatementList1`
if ( `Condition` ) break;
`StatementList2`
}```
By leaving out the three expressions that normally control a `for` loop, it becomes an infinite loop. Of course, we do not want an infinite number of repetitions; rather, we want execution to leave the loop when a termination condition becomes true. As shown in the pattern above, this can be accomplished by placing an `if` statement that uses a termination condition to control a `break` statement within the body of the loop.

When a `break` statement is executed, execution is immediately transferred out of the forever loop to the first statement following the loop. By only selecting the `break` statement when `Condition` is true, a forever loop's repetition can be controlled in a manner similar to the other general-purpose loops.

Exer. 7.8. In `main()`: (i) first add another item to the menu of operations:
``       f - to quit``
and modify the call to `getMenuChoice()` appropriately.

(ii) then add a forever loop to implement the forever loop in the preceding algorithm.

Note: A forever loop can also be used for the "valid numeric input" loop that we wrote before. Make that change in the program, if you like.

Hand In:

Your code and a sample run of your program to demonstrate that everything works — that is, an execution:

• with each possible operator and valid operands
• with an invalid operator
• with at least two operations but with invalid operands
• with the "quit" operation