More Control Structures if and switch (Chap. 8) do-while and forever loops (Chap. 9) 1 Are there any Weaknesses in the if Statement? For some problems, the "waterfall" execution of the multi-branch if leads to poor (or perhaps unacceptable) performance of a program. Example: Suppose we need a function that, given the number of a day of the week (1-7), computes its corresponding name (SundaySaturday)? 2 Algorithm: 0. Receive dayNumber. 1. If dayNumber == 1: Return "Sunday". Else if dayNumber == 2: Return "Monday". Else if dayNumber == 3: Return "Tuesday". Else if dayNumber == 4: Return "Wednesday". Else if dayNumber == 5: Return "Thursday". Else if dayNumber == 6: Return "Friday". Else if dayNumber == 7: Return "Saturday". Else Display an error message, and return "". 3 // Receive a day number, return its name string dayName(int dayNumber) { if (dayNumber == 1) return "Sunday"; else if (dayNumber == 2) return "Monday"; else if (dayNumber == 3) return "Tuesday"; else if (dayNumber == 4) return "Wednesday"; else if (dayNumber == 5) return "Thursday"; else if (dayNumber == 6) return "Friday"; else if (dayNumber == 7) return "Saturday"; else { cerr << "\n** DayName: invalid day number\n"; return ""; } } 4 The multi-branch if has non-uniform execution time: 1 comparison • Computing "Sunday" requires __ 2 comparisons • Computing "Monday" requires __ • ... 7 comparisons • Computing "Saturday" requires __ Computations that are "later" in the if take longer. There are situations where the time to select one of many statements must be uniform. 5 A Solution The C++ switch statement provides an alternative: string dayName(int dayNumber) { switch (dayNumber) { case 1: return "Sunday"; case 2: return "Monday"; case 3: Cases need not return "Tuesday"; be in order nor case 4: consecutive, and return "Wednesday"; there can be case 5: multiple labels. return "Thursday"; case 6: return "Friday"; case 7: return "Saturday"; default: cerr << "\n* dayName: invalid day number\n"; return ""; } 10 } The switch Statement The switch statement provides multi-branch selection, but guarantees uniform execution time, regardless of which branch is selected. Thus, the time to select return "Saturday"; is identical to the time to select return "Sunday"; if a switch statement is used to select them. 7 Pattern: switch (expression) { caseList1 StatementList1 caseList2 StatementList2 ... caseListN StatementListN default: StatementListN+1 } Enclose in { } if it contains any declarations where expression is an integer-compatible expression, each caseList is one or more cases of this form: case ConstantValue : and each StatementList usually ends with a break or return statement. 8 Warning C++ switch statements exhibit drop-through behavior. 1. expression is evaluated. 2. If expression == constanti , control jumps to the statement associated with constanti . 3. Control continues within the switch statement until: a. The end of the switch is reached; b. A break is executed, terminating the switch; c. A return is executed, terminating the function; or d. An exit() is executed, terminating the program. 9 Example What will the following statement display, if the value of dayNumber is 6? switch(dayNumber) { case 1: cout << "Sunday"; case 2: cout << "Monday"; case 3: cout << "Tuesday"; case 4: cout << "Wednesday"; case 5: cout << "Thursday"; case 6: cout << "Friday"; case 7: cout << "Saturday"; default: cout << "Error!" << endl; } Friday SaturdayError! Output: __________________ 10 Solution To avoid the "dropthrough" behavior, we need to add a break or return statement at the end of each case: switch(dayNumber) { case 1: cout << "Sunday"; break; case 2: cout << "Monday"; break; case 3: cout << "Tuesday"; break; case 4: cout << "Wednesday"; break; case 5: cout << "Thursday"; break; case 6: cout << "Friday"; break; case 7: cout << "Saturday"; break; default: cout << "Error!" << endl; } Friday Output when dayNumber is 6? _______________ 11 Other Repetition Structures The most common use of for loops is to count from one value first to another value last: for (int count = first; count <= last; count++) Statement count = first F count <= last T Statement Or to count down from a larger value to a smaller one: for (int count = first; count >= last; count--) Statement count++ 12 More General Loops But sometimes — e.g., when reading data — we need a more general repetition structure one in which we don't know in advance how many iterations will be needed. For example, in the structure pictured at the right, repetition continues so long as some Condition is true. StatementList1 F Condition T StatementList2 13 The while Loop For such situations, C++ provides the while loop: while (Condition) Statement Statement is almost F Condition T Statement always a compound C++ statement. Repetition continues while the Condition is true. 14 Post-test Loops If StatementList2 is omitted in our general repetition structure, we get a test-at-the-bottom or post-test loop: StatementList1 F Condition T 15 The do Loop For such situations, C++ provides the do loop: NOTE! do Statement while (Condition); Statement is almost always a compound C++ statement. Statement F T Condition Repetition "does" Statement while Condition is true. 16 The do-loop is good for query-controlled input loops: do { cout << "\nEnter a failure time: "; cin >> failureTime; failureTimeSum += failureTime; numComponents++; cout << "Do you have more data to enter (y or n)? "; cin >> response; } while (response == 'y' || response == 'Y'); The do-loop is good for fool-proofing input loops: do { Prompt for a menu selection and have the user enter it } while ( not a valid menu selection ); 17 Test-in-the-Middle Loops More general loops like that pictured earlier in which the termination test is made neither at the top nor the bottom of the loop are sometimes called test-in-the-middle loops. Note: The"T" and "F" labels on Condition have been switched here so that repetition terminates when Condition becomes true. StatementList1 T Condition F StatementList2 This makes it easier to implement this structure. 18 Forever Loops Such test-in-the-middle loops can be implemented in C++ with a for-loop of the form: for (;;) // or while (true) { StatementList1 if (Condition) break; StatementList2 } StatementList1 T Condition F StatementList2 Because the for clause contains no expressions to control repetition (thus allowing an infinite loop), this is sometimes called a forever loop. 19 Test-in-the-Middle Input Loops The forever loop is very useful for constructing sentinel-controlled input loops: Good to set off termination test with blank line before and after it. for (;;) // or { Input dataValue while (true) if (dataValue == sentinel) break; } Process dataValue Note that when the sentinel value is input, it does not get processed as a "regular" data value. Also note that if the sentinel value is the first value entered, repetition terminates immediately. 20 An Example // Read, count, find mean of a list of numbers int count = 0; double value, sum = 0, mean; for (;;) { cout << "Enter next value (-999 to stop): "; cin >> value; if (value == -999) break; } count++; sum += value; if (count == 0) cerr << "No values entered\n"; else mean = sum / count; 21 Summary C++ provides four repetition statements: • The for loop, for counting. • The while loop, a general-purpose pretest loop. • The do loop, a general-purpose post-test loop. • The forever loop, a general-purpose test-inthe-middle loop. 22 The four C++ loops provide very different behaviors: • The for loop is a loop designed for counting that provides pretest behavior. • The while loop is a general-purpose loop that provides test-at-the-top (pretest) behavior. • The do loop is a general-purpose loop that provides test-at-the-bottom (post-test) behavior. • The forever loop is a general-purpose loop that provides test-in-the-middle behavior. 23 Choosing a Loop: • Use the for loop for problems that require counting over some range of values. • For other problems, identify the condition needed to terminate repetition and then determine whether execution needs to: use a: skip the loop body if termination condition doesn't hold while loop go through the body at least once before checking termination condition do loop go through the first part of loop body before checking termination condition and skip second part if it holds forever loop 24