Chapter 5 Making Decisions and Looping ====================================== Choosing between different courses of action makes a program much more useful and flexible. Decision making constructs allow for many different logical branches of code to be incorporated into a single program. One of the fundamental properties of a programming language is the ability to repetitively execute a sequence of statements. These looping capabilities enable programmers to develop concise programs containing repetitive processes that could otherwise require an excessive number of statements. 5.1 Program Control ~~~~~~~~~~~~~~~~~~~ The **if-else** statement allows conditional execution of a group of statements. The general form of an **if-else** statement is Fig 5-1 ``````` :: if(expression) { statement-block-1; } else { statement-block-2; } where **expression** can be a combination of logical and relational operators and their operands, a function call, or a mathematical expression. If the **expression** is true, then statement-block-1 is executed otherwise statement-block-2 is executed. Only **expressions** evaluating to zero(0) are considered to be false in C and C++. Statements subordinate to **if** and **else** clauses can be compound statements; meaning several statements grouped together and bounded by opening and closing curly braces. It is recommended that subordinate statements be indented to indicate the subordination. Most programmers indent from three to five spaces, some use as many as eight spaces. It is also recommended that code not be placed after column seventy-two (72), this makes all the code on a line visible on the display and usually makes for a readable printout. Fig 5-2 ``````` :: A: if(x == y) a = b + c; B: if(c >= 10) { cout << "\nC is over 10"; ++a; } else { cout << "\nNot yet!"; c++; } Notice that the first example, A, does not use an **else** clause. The **else** clause is optional and is only used if needed. Also, note that curly braces are not used on example A because there is only a single statement subordinate to the **if**. **if-else** statements can be nested. There is no reasonable limit imposed by the compiler to the number of nested **if-else** statements, although there should be a practical limit. It is recommended that if nested **if-else** statements are used, that the nest not go over four deep. This limit is more a matter of readability and not anything imposed by the compiler. For example, the following shows nested **if-else** statements. Notice how quickly the code progresses toward the right edge of the display, even with short variable names. Also, this example has a major error in logic. See if you can find it. Fig 5-3 ``````` :: if( a > 10 ) if( b < 5 ) b = a * 10; else if( a < 5 ) if ( b > 10 ) b = a * b; else if( c > 5 && b == 10 ) if( c < 10 ) c = b * a; else c = a * c; In nested **if-else** statements, the **else** is associated with the nearest **if**, unless bracketed within curly braces which form a compound statement. The error in the above sample is at the very beginning where Fig 5-4 ``````` :: if( a > 10 ) if( b < 5 ) b = a * 10; else The **else** is associated by the compiler with the **if( b < 5 )** statement not with **if( a > 10 )**. The intention of the programmer was to associate the **else** with **if( a > 10 )**. In order to accomplish the correct association, the code block should appear as Fig 5-5 ``````` :: if( a > 10 ) { if( b < 5 ) b = a * 10; } else Notice the use of the curly braces to limit the scope of the **if( b < 5 )** statement. Many errors in logic occur because of incorrect **else** statement association. Use the curly braces if there is any doubt about how the compiler will associate **if** with **else** statements. 5.2 Switch Statement ~~~~~~~~~~~~~~~~~~~~ The **switch** allows the conditional execution of one of a number of groups of statements based on the value of an expression. The general form of a **switch** statement is: Fig 5-6 ``````` :: switch( expression ) { case constant-value-1: statement-block-1; break; case constant-value-2: statement-block-2; break; . . . default: statement-block-n; break; } Where **expression** must produce an integer or character result and each of the constant values must be an integer or character value that could be a possible value of the **expression**. The **expression** in the switch statement is evaluated and compared to each of the case constant values in order. If a match is found, execution is started at that **case** statement. If no match is found, control is transferred to the **default** statement, if one has been coded. Listing 5-1 ``````````` :: #include ing main() { int day; cout << "\nEnter a number for" << "the day of the week:"; cin >> day; switch( day ) { case 0: cout << "Sunday"; break; case 1: cout << "Monday"); break; case 2: cout << "Tuesday"; break; case 3: cout << "Wednesday"; break; case 4: cout << "Thursday"; break; case 5: cout << "Friday"; break; case 6: cout << "Saturday"; break; default: cout << "No Such Day"; break; } return 0; } The **break** statement causes an immediate exit from the switch. Without the **break**, the execution will fall thru to the next **case** and will continue to fall thru until a **break** statement is reached. Sometimes the desired logic is to have multiple **case** statements cause one code block to be executed. For example, assume that the keyboard is being read and that when a newline character or a carriage return character is read a null byte is to placed at the end of an array of characters. Listing 5-2 ``````````` :: #include int main() { char buffer[80]; int ch, idx = 0, lgth = sizeof( buffer) -1; cout << "\nEnter a string of characters: "; while ( idx < lgth && ch != '\n' && ch != '\r' ) { cin >> ch; switch( ch ) { case '\n': case '\r': buffer[idx] = '\0'; break; case '\b': --idx; if( idx < 0 ) idx = 0; putchar( '\b' ); putchar( ' ' ); putchar( '\b' ); break; default: buffer[idx] = ch; ++idx; break; } } return 0; } 5.3 while Loops ~~~~~~~~~~~~~~~ The **while** loop allows for the repeated execution of a group of statements as long as a condition is true. The condition is checked each time before the code is executed. The general form of the loop construct is: Fig 5-7 ``````` :: while (expression) { statement-block; } If **statement-block** comprises a group of statements, then the group must be bracketed by opening and closing curly braces. The statement or group of statements inside the while loop will be executed until the expression is false Listing 5-3 ``````````` :: #include int main() { int ch = 0; cout << "\nCharacter Set"; while ( ch < 256 ) { cout << "\nChar: " << char(ch) << " Hex: " << hex << ch << " Oct: " << oct << ch << " ASCII: " << ch ; ++ch; } return 0; } 5.4 for Loops ~~~~~~~~~~~~~ The **for** loop is a specialized form of the **while** loop, which includes an initialization statement, a conditional expression and a third expression, referred to as the increment expression, which is executed at the end of the loop before control is transferred back to the conditional expression test at the loop beginning. The general form of the for loop is: Fig 5-8 ``````` :: for(init-expression; conditional-expression; increment-expression) { statement-block; } All three expressions composing the **for** loop are optional. The expressions can be any legal expression, function call, or mathematical statement. The statements are executed as follows: Fig 5-9 ``````` :: init-expression; loop: if conditional-expression is true begin statement-block; increment-expression end else exit the loop; end of loop: The following example prints the character set being used on the current machine. The program prints character, the ASCII value, the hexadecimal value and the octal value of the character. Listing 5-4 ``````````` :: #include #define MAX_LINES 23 int main() { char ans; int ch, lines, stop = 0, maxchars; // // how many characters in current character set // cout << "\nHow many characters in the character set: "; cin >> maxchars; // // print the ASCII and extended ASCII characters // for(ch = 0, lines = 0; ch < maxchars && !stop; ++ch) { cout << "\nCHAR: " << char( ch ) << " ASCII: " << ch << " HEX : " << hex << ch << " OCT : " << oct << ch ; if( ++lines > MAX_LINES ) { cout << "\nContinue(Y/N)?"; cin >> ans; if(ans == 'N' || ans == 'n') { stop = 1; break; } lines = 0; } } return 0; } 5.5 do-while Loops ~~~~~~~~~~~~~~~~~~ This loop is like the while loop, except that the condition is checked after the loop is executed. The general form is as follows: Fig 5-10 ```````` :: do { statement-block; } while(expression); The statement or statement-block are executed at least once, even if the expression is false on the first test. Listing 5-5 ``````````` :: #include #define ESC 27 int main() { int ch; do { cout << "\nPress any key:"; cin >> ch; cout << "\nCHAR: " << ch << HEX: " << ch; } while(ch != ESC); return 0; } 5.6 break Statement ~~~~~~~~~~~~~~~~~~~ The **break** terminates execution of a loop or switch-case and transfers execution to the first statement following the loop or the switch-case. If the **break** statement is within a loop that is nested within another loop, the **break** statement only exits the loop the holds the **break** statement, not the outer loop. 5.7 continue Statement ~~~~~~~~~~~~~~~~~~~~~~ The **continue** causes execution to pass to the end of the current loop. For example: Fig 5-11 ```````` :: for(i=1; i < 100; i++) { if( i == 10 ) continue; . . . } when **i** is equal to **10** execution will go to the increment- expression, **i++** and bypass any code between the **if** and the increment-expression. 5.8 Declarations within Blocks ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++ allows declarations within blocks after code statements. This allows a programmer to declare an entity closer to its first point of application. For example, an index can be declared within a loop, as follows: :: for( int i = 0; i < 12; i++ ) 5.9 Scope Qualifier Operator ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ The new operator **::** is used to resolve name conflicts. For example, if the automatic variable **vector_sum** is declared within a function and there exists a global variable **vector_sum**, the specifier **::vector_sum** allows the global variable to be accessed within the scope of the automatic variable **vector_sum**. The reverse is not true. It is not possible for the automatic variable **vector_sum** to be accessed from outside its scope. The scope qualifier **::** is also used in connection with classes. Listing 5-6 ``````````` :: // **::** scope resolution operator example int i = 1; // external or global i #include int main() { int i = 2; // redeclares i locally to main { // an inner block within a function cout << "Enter inner block" << endl; int n = i; // the global i is still visible int i = 3; // hides the global i which can only be // referenced by using the :: operator // print the local i and the global i cout << i << " i << ::i " << ::i << endl; cout << "n = " << n << endl; } // end of inner block cout << "Enter outer block" << endl; // print the current local i and the global i cout << i << " i ** ::i " << ::i << endl; return 0; } ** The output of this code is: Fig 5-12 ```````` :: Enter inner block 3 i :: ::i 1 n = 2 Enter outer block 2 i :: ::i 1 5.10 Scope of Identifiers ~~~~~~~~~~~~~~~~~~~~~~~~~ Each identifier or name has a scope that indicates the region of the program where that identifier can be used. C++ supports the notion of the following types of scope: #. **Local:** Names appearing inside a block statement (enclosed in a pair of curly braces **{...}**) have local scope. You can use these only within that block and only after the actual declaration. Note that you cannot define a function in a local scope. (This means you cannot define one function inside the body of another.) #. **File:** Names appearing outside all blocks and class declarations have file scope. These can be used within that file anywhere after the point where they are declared. #. **Class:** Names of data and function members of a **class** (or **struct**) have class scope.