Control Structures ------------------ Up to now, all of the programs we have seen were examples of what is known as STRAIGHTLINE programming. Program execution commenced with the first statement and proceeded statement by statement until the end of the program was reached. Most non-trivial programs require some sort of mechanism to alter the sequence of statement execution. C++ has two conditional constructs and three looping constructs. The conditional constructs determine which statements are to be executed depending upon a certain condition, the looping contructs determine the number of times a block of statements is to be executed. The Boolean type --------------- In the original version of the C programming language a LOGICAL FALSE was represented by the integer value 0, a LOGICAL TRUE was represented by any NON-ZERO integer. Thus in C (and early versions of C++) the following were all legal ways of representing a logical true: 1 5 678*3 Similarly, the following are legal ways of expressing a logical FALSE 0 16 % 16 C++ now has the built-in BOOLEAN logical data type which is named bool. The bool data type can take on one of two possible symbolic constants: true, false. Relational Operators -------------------- C++ has two type of relational operators: equality and ordering. The equality operators are: == returns true if both of the operands are equal to each other != returns true if the two operands are not equal to each other Some examples of the use of the equality operators are: int i = 1; int j = 1; int k = 2; (i==j) ; // this will return true (i==k) ; // this will return false (i!=k) ; // this will return true We are not limited to comparing only integers for equality or inequality. Any built-in C++ data type can be used (when working with floating point values we should be a bit more careful... more on this later). char letter1, letter2, letter3; letter1 = 'a'; letter2 = 'b'; letter3 = 'c'; letter1 == letter2 ; // this will return false; letter2 != letter3 ; // this will return true; What do you think the output of the following program which tests two structs for equality will be ? // Author: Ted Obuchowicz // Jan. 16, 2002 // example program illustrating use of // equality operators on struct data type #include #include using namespace std; int main() { struct a_simple_struct { int a_number; char a_letter; bool a_boolean; }; a_simple_struct first_struct, second_struct, third_struct; first_struct.a_number = 1; first_struct.a_letter = 'a'; first_struct.a_boolean = true; second_struct.a_number = 1; second_struct.a_letter = 'a'; second_struct.a_boolean = true; third_struct.a_number = 5; third_struct.a_letter = 'a'; third_struct.a_boolean = true; if (first_struct == second_struct) cout << "first and second structs are equal" << endl; else cout << "first and second structs are not equal" << endl; return 0; } The answer is nothing! The program DOES NOT EVEN COMPILE : ted@flash Programs 8:25pm >g++ -o struct_equality struct_equality.C struct_equality.C: In function `int main()': struct_equality.C:40: no match for `main()::a_simple_struct & == main()::a_simple_struct &' The compiler is complaining about line 40 in the source code which is the if statement: if (first_struct == second_struct) If you want to compare structs, then the comparison must be done on a field-by field basis. For example, the above program can be fixed by simply replacing the if statement with something along the lines of: if ((first_struct.a_number == second_struct.a_number) && (first_struct.a_letter == second_struct.a_letter) && (first_struct.a_boolean == second_struct.a_boolean) ) cout << "first and second structs are equal" << endl; else cout << "first and second structs are not equal" << endl; Ordering Operators ------------------ C++ uses the following 4 ordering operators to determine the relative size of two operands: < less than > greater than <= less than or equal >= greater than or equal Examples: ( 1 < 2 ) will return true ( 1 > 2) will return false Boolean Operators ----------------- C++ has three Boolean operators: &&, ||, and !. Their meaning is as follows: && : used to perform a logical AND of two boolean expressions: ex. (i < 3 ) && (k < 56 ) || : used to perform a logical OR of two expressions: ex. (i < 2 ) || ( k > 45) ! : used to perform a logical NEGATION ex. ! (i < 2) SHORT-CIRCUIT EVALUATION ------------------------ When evaluation the value of a logical expression, C++ requires that first the left operand be evaluated to yield a boolean value, then the right operand be evaluated. Furthermore, if the value of the entire logical expression may be determined from the left operand, then the right hand operand should not be evaluated. This is known as short-circuit evaluation. For example: ( i != 0) && ( (k/i) < 2 ) the ( i != 0) will be equal to false only in the case of i being equal to 0, since the boolean && operator requires both its operands to be true in order for the entire to be expression to be true, it is not even necessary to evaluate the right-hand side ( (k/i) < 2 ) in the case of i being equal to 0. By virtue of short-circuit evaluation, we can guarantee that division by zero will NEVER occur. If C++ did not provide short-circuit evaluation, then there would be a possibility that a division by zero would be attempted while evaluation the right hand side operand. Comparing floating point numbers ------------------------------- Round-off errors due to inherent limitiations of how real numbers are internally stored in a computer's memory can cause some problems when comparing floating point numbers for equality. For example, consider the following program which adds 0.0000001 ten times to theoretically give the value 0.000001: // Author: Ted Obuchowicz // Jan. 16, 2002 // example program illustrating use of // testing real numbers for equality #include #include #include using namespace std; int main() { float number; number = 0.0000001 + 0.0000001 + 0.0000001 + 0.0000001 + 0.0000001 + 0.0000001 + 0.0000001 + 0.0000001 + 0.0000001 + 0.0000001; if (number == 0.000001 ) cout << " number is equal to 0.000001" << endl; else cout << " number is not equal to 0.000001" << endl; cout << setprecision(15) << "number is equal to " << number << endl; return 0; } The output may surprise you: number is not equal to 0.000001 number is equal to 9.99999997475243e-07 When testing real number for equality, it is a better practice to check that the two numbers are close enough to one another. The following program makes use of the fabs() function found in the library to check that the absolute value of number - 0.000001 is less than some prespecified value called epsilon: // Author: Ted Obuchowicz // Jan. 16, 2002 // example program illustrating use of // testing real numbers for equality #include #include #include #include using namespace std; int main() { float number; const float epsilon = 0.001; number = 0.0000001 + 0.0000001 + 0.0000001 + 0.0000001 + 0.0000001 + 0.0000001 + 0.0000001 + 0.0000001 + 0.0000001 + 0.0000001; if ( fabs( (number - 0.000001) <= epsilon ) ) cout << " number is equal to 0.000001" << endl; else cout << " number is not equal to 0.000001" << endl; cout << setprecision(15) << "number is equal to " << number << endl; return 0; } We use the #include statment to tell the compiler where to look for the definition of the fabs function. We would compile this program on the ECE UNIX g++ compiler with the following command line: g++ -o floating_point_equality2 floating_point_equality2.C -lm The -lm option must appear at the end of the command line. It tells the linker to link the math library with your object code. This time the program output is what we expect: number is equal to 0.000001 number is equal to 9.99999997475243e-07 The IF STATEMENT --------------- The previous programs have already examined the use of the IF statement. The if statement comes in two forms: Form 1: if (expression) statement; Form 2: if (expression) statement; else another statement; NOTE: If it is required to perform more than one statement in a branch of the if statement, then the entire block of statements must be enclosed in { } such as: if (expression) { statement1; statement2; ... statementn; }; or using Form 2: if (expression) { statement1; statement2; ... statementn; }; else { statementx; statementy; ... statementz; }; Be careful to use the delimiting { } properly. Failure to do so may cause strange program behaviour as is the following program: // Author: Ted Obuchowicz // Jan. 16, 2002 // example program illustrating INCORRECT use of // if statement #include #include using namespace std; int main() { int i ; cin >> i; if (i != 1) cout << " i is not equal to 1" << endl; cout << " end of program goodbye" << endl; return 0; } When we run this program and enter 1 for the value of 1, the output is: end of program goodbye What went wrong? The expression ( i != 1) is false for i equal to 1 (since 1 is equal to 1). So why was the "end of program goodbye" produced as output? . What the program actually did was: if (i != 1) cout << " i is not equal to 1" << endl; cout << " end of program goodbye" << endl; The second cout is actually independent of the first if since we did not delimit the two statements within { }. If we change the program to: // Author: Ted Obuchowicz // Jan. 16, 2002 // example program illustrating INCORRECT use of // if statement #include #include using namespace std; int main() { int i ; cin >> i; if (i != 1) { cout << " i is not equal to 1" << endl; cout << " end of program goodbye" << endl; }; // the above messages will be printed ONLY FOR values of i not equal to 1 // when i is equal to 1, no output will be produced return 0; } A sample session with the running program is: ted@flash Programs 10:08pm >if_statement2 1 ted@flash Programs 10:09pm > ted@flash Programs 10:09pm >if_statement2 3456 i is not equal to 1 end of program goodbye ted@flash Programs 10:09pm > CAVEAT ------- The following is a VERY COMMON MISTAKE THAT BEGINNER C and C++ programmers make: // Author: Ted Obuchowicz // Jan. 16, 2002 // example program illustrating use of // common programming error with an if #include #include using namespace std; int main() { int balance_owed; cin >> balance_owed; if (balance_owed = 0) cout << "You owe me nothing" << endl; else cout << "You owe me " << balance_owed << " dollars" << endl; return 0; } This program when run will ALWAYS print out: You owe me 0 dollars irrespective of the value the user inputs for the integer variable balance_owed! WHY???? look very carefully at the if statement: if (balance_owed = 0) ^^^^^^^^^^^^^^^^^ cout << "You owe me nothing" << endl; else cout << "You owe me " << balance_owed << " dollars" << endl; the (balance_owed = 0) is an ASSIGNMENT of 0 to the variable balance_owed. The result of the assignment is that variable balance_owed take son the value 0. The condition then reduces to: if(0) cout << "You owe me nothing" << endl; else cout << "You owe me " << balance_owed << " dollars" << endl; since a 0 is false in C++, the condition is always false so the else part is always executed with a value of 0 for the amount owed!!! /********************************************************************/ /* */ /* ALWAYS USE == FOR COMPARISON IN IF STATEMENTS!!!!! */ /* */ /* */ /********************************************************************/ The proper version of the program is: // Author: Ted Obuchowicz // Jan. 16, 2002 // example program illustrating use of // correct use of if statement #include #include using namespace std; int main() { int balance_owed; cin >> balance_owed; if (balance_owed == 0) cout << "You owe me nothing" << endl; else cout << "You owe me " << balance_owed << " dollars" << endl; return 0; } Note that the only difference between the good and the bad versions is the difference between = and == . Amazing what a single missing = will do in a program! PAY YOUR ATTENTION INSIDE OF IF STATEMENTS AND ALWAYS CHECK FOR EQUALITY WITH THE == !!!!!!! The proper output is: ted@flash Programs 10:47pm >good_if 0 You owe me nothing ted@flash Programs 10:47pm >good_if 456 You owe me 456 dollars Nested if-else-if statements: ---------------------------- Consider the following if construct: char command; cin >> command; if (command == 'u') cout << "Move up command was received" << endl; else if (command == 'd') cout << "Move down command was received" << endl; else if (command == 'l') cout << "Move left command was received" << endl; else if (command == 'r') cout << "Move right command was received" << endl; else cout << "Invalid command" << endl; The indentation of the if statements is purely cosmetic. The compiler does not care about nesting. We can rewrite the above if statement as: if (command == 'u') cout << "Move up command was received" << endl; else if (command == 'd') cout << "Move down command was received" << endl; else if (command == 'l') cout << "Move left command was received" << endl; else if (command == 'r') cout << "Move right command was received" << endl; else cout << "Invalid command" << endl; Using this style improves program readability and avoids the problem of running out of space on the right hand side as the nesting level of the if statements increases. The switch statement ------------------- C++ has a very convenient statement for multi-branch conditional testing as in the above statement. It is called the switch statement. The above if can be rewritten as a switch statement. // Author: Ted Obuchowicz // Jan. 17, 2002 // example program illustrating use of // switch statement #include #include using namespace std; int main() { char command; cin >> command; switch (command) { case 'u': cout << "Move up command was received" << endl; break; case 'd': cout << "Move down command was received" << endl; break; case 'l': cout << "Move left command was received" << endl; break; case 'r': cout << "Move right command was received" << endl; break; default : cout << "Invalid command" << endl; } return 0; } When the switch statment is executed, the value of command is compared with the specified cases. If a match is found, the statements corresponding to the matching case are executed. If the value of command does not match any of the specified cases, then the sequience of statements for the specified default case is executed (if there is no default case specified, flow of control resumes with the statement immediately following the switch). The break statement ------------------ Note that in the above switch, there is a break statement associated with every specified case. The break statement causes a change of flow of control to the statement following the switch. The break can be interpreted as "the switch statement has completed its task and program execution should resume with the statement immediately following the switch statement". If a switch statement does not contain breaks for the specified cases, then the action for the FIRST matching value is executed, FOLLOWED BY ANY REMAINING groups of action statements (for the remaining values even though they do not match). For example, // Author: Ted Obuchowicz // Jan. 17, 2002 // example program illustrating use of // switch statement #include #include using namespace std; int main() { char command; cin >> command; switch (command) { case 'u': cout << "Move up command was received" << endl; case 'd': cout << "Move down command was received" << endl; case 'l': cout << "Move left command was received" << endl; case 'r': cout << "Move right command was received" << endl; default : cout << "Invalid command" << endl; } return 0; return 0; } If the user supplies u for the value of the command, the program produces the following output: ted@flash Programs 12:55pm >switch_no_break u Move up command was received Move down command was received Move left command was received Move right command was received Invalid command If we supply d for the value of the input variable command, the following output is produced: ted@brownsugar Programs 7:21pm >switch_no_break d Move down command was received Move left command was received Move right command was received Invalid command giving l as an input value results in: ted@brownsugar Programs 7:21pm >switch_no_break l Move left command was received Move right command was received Invalid command if we give r as the value : ted@brownsugar Programs 7:25pm >switch_no_break r Move right command was received Invalid command Cases in a switch with no break ------------------------------ In most programming problems, every 'action' statement should have an associated break statement as in switch (condition) { case value1 : action1; break; case value2 : action2; break; ... case valuen : actionn; break; default : default_action; } In some programming situations, using the so-called "fall through" behaviour (some actions without an associated break) makes sense. Consider once again the menu switch where we now consider the upper and lower case letters as being valid input characters (i.e. both 'u' and 'U' should be recognized as a legal move up command, 'd' and 'D' as legal move down commands etc). We can rewrite our previous program as: #include #include using namespace std; int main() { char command; cin >> command; switch (command) { case 'u': // fall through to the 'U' case case 'U': cout << "Move up command was received" << endl; break; case 'd': // fall through to the 'D' case case 'D': cout << "Move down command was received" << endl; break; case 'l': // fall through to the 'L' case case 'L': cout << "Move left command was received" << endl; break; case 'r': // fall through to the 'R' case case 'R': cout << "Move right command was received" << endl; break; default : cout << "Invalid command" << endl; } return 0; } It should be noted that the switch statement in the above example can be rewritten more clearly as: case 'u' : case 'U' : cout << "Move up command was received" << endl; break; case 'd' : case 'D': cout << "Move down command was received" << endl; break; case 'l': case 'L': cout << "Move left command was received" << endl; break; case 'r': case 'R': cout << "Move right command was received" << endl; break; default : cout << "Invalid command" << endl; } Using this style clearly indicates the code which is to be executed for common cases. To reiterate, the switch statement is different from similar statements in languages such as Pascal in a very important way. In C and C++, when a program jumps to a certain line in a switch statement (when it finds the first matching value of the listed cases) , the program THEN SEQUENTIALLY EXECUTES all the statements following that line unless you EXPLICITLY TELL OTHERWISE (with the break) . Program execution DOES NOT AUTOMATICALLY stop at the next case. To make execution stop at a particular line, you must use the break statement. The break causes the program to continue exection from the next statement following the switch. One final note regarding the switch statement. Both the expression which is being tested and the values of the cases should be of an INTEGRAL type. This limitation means that a switch statement cannot be used to determine the flow of program control based on the value of a floating-point variable. LOOPING CONSTRUCTS ----------------- Suppose we wish to find the sum , and average value of a list of 4 numbers. Our first (brute-force) program might look like: // Author: Ted Obuchowicz // Jan. 21, 2002 // example program illustrating use of // brute force approach to finding the sum and average of 5 floating // point values #include #include using namespace std; int main() { float sum; float average; float number_1; float number_2; float number_3; float number_4; float number_5; cout << "Please enter first number "; cin >> number_1; cout << "Please enter second number "; cin >> number_2; cout << "Please enter third number "; cin >> number_3; cout << "Please enter fourth number "; cin >> number_4; cout << "Please enter fifth number "; cin >> number_5; sum = number_1 + number_2 + number_3 + number_4 + number_5; average = sum / 5.0; cout << "The sum of the 5 numbers is : " << sum << endl; cout << "The average value is : " << average << endl; return 0; } Suppose we had to find the sum and average of a list of 10 000 values? Clearly, the above brute force approach is not very convenient to use. We can use a while loop to control the number of times a portion of program code is to be executed. The following is an ALGORITHM which repeatedly gets the next input value and adds it to the sum of the previous input values and then calculates the average: Step 1: Set the value of the running sum to 0.0 Step 2: Set the value of the number of processed values to 0. Step 3: while (number of processed items < sixe of the list ) Step 3a: read in a value; Step 3b: sum = sum + value; Step 3c; add 1 to the number of items processed so far Step 4: calculate the average as sum / list size Step 5: display the values of the sum and the average A complete C++ program which corresponds to the above pseudocode is: // Author: Ted Obuchowicz // Jan. 21, 2002 // example program illustrating use of // while loop to find sum and average of 5 floating point values read in // from keyboard #include #include using namespace std; int main() { float sum; float average; const int size_of_list= 5; float number; int number_of_items_processed; // perform some initialization sum = 0.0; number_of_items_processed = 0; while (number_of_items_processed < size_of_list) { cout << "Please enter a number " << endl; cin >> number; sum = sum + number; // update running sum number_of_items_processed++; // increment number of items processed so far } average = sum / size_of_list; cout << "The sum is " << sum << endl; cout << "The average is " << average << endl; return 0; } Improving the above program: The above program is fine for lists whose sizes is known ahead of time. What if we wanted to find the sum and average of an unknown number of values???? We can modify the above program to test the number which is input to see if it is a special "flag" ( in computer programming a flag variable is one which the programmer places "special meaning" to). For example, we can reserve the number -9999 to indicate that the list has no more values. The modified program is : // Author: Ted Obuchowicz // Jan. 21, 2002 // example program illustrating use of // while loop to find sum and average of 5 floating point values read in // from keyboard #include #include using namespace std; int main() { float sum; float average; const float flag = -9999.0; float number; int number_of_items_processed; // perform some initialization sum = 0.0; number_of_items_processed = 0; cout << "Please enter a number " << endl; cin >> number; while ( ! ( (number - flag) < 0.00001 ) ) { sum = sum + number; // update running sum number_of_items_processed++; // increment number of items processed so far cout << "Please enter a number " << endl; cin >> number; } if (number_of_items_processed != 0) { average = sum / number_of_items_processed; cout << "The sum is " << sum << endl; cout << "The average is " << average << endl; } else { cout << " No numbers were entered " << endl; cout << " Sum is " << sum << endl; cout << " Impossible to compute average... sorry " << endl; } return 0; } Some comments on the above program: ---------------------------------- 1) Note that before we enter the while loop, we first read in a number... this is necessary so that the variable called number has an intial value when it is being tested inside the conditional expression of the while loop: cout << "Please enter a number " << endl; cin >> number; while ( ! ( (number - flag) < 0.00001 ) ) ----- | -----> this must have some value before it can be tested 2) the test in the while loop does not test for equality with -9999.0, rather it tests that the difference between the number read in and the constant flag of -9999 is less than some small number ( actually we should really test for the absolute value of the difference between number and flag being less than some value...) 3) in the while loop , we read in a new value for number: cin >> number; this is necessary , since we eventually want the while loop to terminate. 4) we test that some numbers have been actually entered to avoid a potential division by zero in our source code: if (number_of_items_processed != 0) { average = sum / number_of_items_processed; cout << "The sum is " << sum << endl; cout << "The average is " << average << endl; } else { cout << " No numbers were entered " << endl; cout << " Sum is " << sum << endl; cout << " Impossible to compute average... sorry " << endl; } Alternative solution ------------------- While flags are useful programming tricks, they are not totally without problems of their own. What if the flag represents a valid possible number to be entered? Fortunately, C++ has a mechanism which overcomes the problems associated with flags. We can test for the end of input in the following manner: while ( cin >> number ) { do some more processing; } The value of an extraction operator is true provided the extraction is successfull (i.e. a number is typed in ). When the input stream has been exhausted (tha tis there are no more values to read in) the value of the extraction operation is false and the while loop will terminate. The expression cin >> number is true if and only if a number has been read in. To indicate that there are no more values to be entered, the user types in an escape sequence which is specific to the operating system. In UNIX, the end-of-file escape sequence is the Control-D sequence (press the Control kety then the D key). The program is as follows: // Author: Ted Obuchowicz // Jan. 21, 2002 // example program illustrating use of // while loop to find sum and average of // from keyboard using control-d to indicate end of file #include #include using namespace std; int main() { float sum; float average; float number; int number_of_items_processed; // perform some initialization sum = 0.0; number_of_items_processed = 0; cout << "Please enter a number " << endl; while ( cin >> number ) { sum = sum + number; // update running sum number_of_items_processed++; // increment number of items processed so far cout << "Please enter a number " << endl; } if (number_of_items_processed != 0) { average = sum / number_of_items_processed; cout << "The sum is " << sum << endl; cout << "The average is " << average << endl; } else { cout << " No numbers were entered " << endl; cout << " Sum is " << sum << endl; cout << " Impossible to compute average... sorry " << endl; } return 0; } Here is another example of a while loop. The program uses the simple "keep subracting one number from another until you can't subtract anymore " algorithm to perform simple integer division which yields an integer quotient and remainder: // Author: Ted Obuchowicz // Jan. 16, 2002 // example program illustrating use of // while loop to perform simple integer division which // yields an integer quotient and an integer remainder // using the grade school division algorithm #include #include using namespace std; int main() { int dividend; int divisor; int quotient = 0; int remainder; // read in the two values cin >> dividend >> divisor; cout << "Dividend = " << dividend << " Divisor = " << divisor << endl; // check for a zero divisor if ( divisor == 0 ) cout << "Cannot divide by zero you bonehead!!!!" << endl; else { while (dividend >= divisor) { quotient++; dividend = dividend - divisor; }; remainder = dividend; cout << "Quotient = " << quotient << " Remainder = " << remainder << endl; } return 0; } The for loop ----------- C++ has another looping construct which is frequently used. We will illustrate its use with a simple program which performs integer multiplication by repeated addition. The program is based on the fact that a multiplication of the form: product = a * b is equivalent to adding a to itself a total of b times (or adding b to itself a total of a times). In the early times of computing (when there were no built-in multiply instructions, multiplication was actually carried out in such a manner). // Author: Ted Obuchowicz // Jan. 21, 2002 // example program illustrating use of // for loop in a multiplication by repeated addition program // we will keep it simple and assume only positive operands #include #include using namespace std; int main() { int product = 0; // initialize to 0 int multiplicand; int multiplier; cout << "Enter the multiplicand " << endl; cin >> multiplicand ; cout << "Enter the multiplier " << endl; cin >> multiplier; for (int i = 0 ; i < multiplier ; i++ ) { product = product + multiplicand; } cout << multiplicand << " * " << multiplier << " = " << product << endl; return 0; } The general form of a for loop is the following: for ( initialization ; test_expression ; postexpression ) action; (again as in the case of an if, if more than one statement constitutes the action portion, then they must be enclosed in the { } ) : for ( initialization ; test_expression ; postexpression ) { action1; action2; ... actionn; } When a for loop is encountered in a program the following steps are performed: 1) the initialization is performed first 2) next, the test_expression is evaluated, if the expression is true then the step(s) in the Action portion are executed and then postexpression is executed 3) the test_expression is reevaluated, if true, the action statements are again executed, if false the for loop TERMINATES and control continues with the next statement in the program. Another example: --------------- We can re-write our while loop program to use a for loop: // Author: Ted Obuchowicz // Jan. 21, 2002 // example program illustrating use of // for loop to find sum and average of 5 floating point values read in // from keyboard #include #include using namespace std; int main() { float sum; float average; const int size_of_list= 5; float number; int number_of_items_processed; // perform some initialization sum = 0.0; number_of_items_processed = 0; for (int i = 0; i < size_of_list ; i++) { cout << "Please enter a number " << endl; cin >> number; sum = sum + number; // update running sum } average = sum / size_of_list; cout << "The sum is " << sum << endl; cout << "The average is " << average << endl; return 0; } In a for loop , any of the initialization test_expression postexpression may be omitted. This may appear strange , but consider the following program // Author: Ted Obuchowicz // Jan. 21, 2002 // example program illustrating use of // an INFINITE for loop #include #include using namespace std; int main() { for( ; ; ) { cout << "This is an infinite for loop " << endl; } return 0; // actually the program will never return untill you kill it with // control-c } The following is also another variation of the above theme: for( ; true ; ) { cout << "This is an infinite for loop " << endl; } As another example of the versatility of the for loop let us first rewrite our general purpose sum and average program: // Author: Ted Obuchowicz // Jan. 21, 2002 // example program illustrating use of // for loop to find sum and average of // from keyboard using control-d to indicate end of file #include #include using namespace std; int main() { float sum; float average; float number; // perform some initialization sum = 0.0; cout << "Please enter a number " << endl; for ( int number_of_items_processed = 0; cin >> number; number_of_items_processed++ ) { sum = sum + number; // update running sum cout << "Please enter a number " << endl; } if (number_of_items_processed != 0) { average = sum / number_of_items_processed; cout << "The sum is " << sum << endl; cout << "The average is " << average << endl; } else { cout << " No numbers were entered " << endl; cout << " Sum is " << sum << endl; cout << " Impossible to compute average... sorry " << endl; } return 0; } While at firsrt glance, this program appears both syntactically and semantically correct, it DOES NOT EVEN COMPILE!!!! : Here are the compilation error messages as reported by the g++ compiler: ted@brownsugar Programs 8:47pm >g++ -o for_loop_gen_purpose_sum for_loop_gen_purpose_sum.C for_loop_gen_purpose_sum.C: In function `int main()': for_loop_gen_purpose_sum.C:40: name lookup of `number_of_items_processed' changed for new ANSI `for' scoping for_loop_gen_purpose_sum.C:30: using obsolete binding at `number_of_items_processed' The problem is related to RULES OF SCOPE. Basically, the problem is that the loop index variable number_of_items_processed is known only within the body of the for loop. Outside the for loop, this index variable cannot be accessed. The solution is to remove this variable declaration from the for loop initialization statement and put it as part of the main program: // Author: Ted Obuchowicz // Jan. 21, 2002 // example program illustrating use of // for loop to find sum and average of // from keyboard using control-d to indicate end of file #include #include using namespace std; int main() { float sum; float average; float number; // perform some initialization sum = 0.0; cout << "Please enter a number " << endl; int number_of_items_processed = 0; for ( ; cin >> number; number_of_items_processed++ ) { sum = sum + number; // update running sum cout << "Please enter a number " << endl; } if (number_of_items_processed != 0) // this will not compile since scope rules // limit visibility of number_of_items_processed // to body of for loop { average = sum / number_of_items_processed; cout << "The sum is " << sum << endl; cout << "The average is " << average << endl; } else { cout << " No numbers were entered " << endl; cout << " Sum is " << sum << endl; cout << " Impossible to compute average... sorry " << endl; } return 0; } Note that in the case that the test_expression evaluates to false right away, the body of the for loop is never executed: // Author: Ted Obuchowicz // Jan. 21, 2002 // example program illustrating use of // of a for loop whose action stateements are never executed #include #include using namespace std; int main() { for(int index = 0 ; ( 1 > 1024); index++ ) { cout << "This will not be printed" << endl; cout << "Keith is better than Madonna " << endl; } return 0; } In the above program, the initialization of the loop index is performed and the expression ( 1 > 1024) is evaluated, since it evaluates to false, the body of the loop is never entered and control continues with the next statement (which is the end of the program....) Nested loops: ------------ Loops may be nested. For example; // Author: Ted Obuchowicz // Jan. 7, 2002 // example program illustrating use of // nested for loops #include #include using namespace std; int main() { for(int out = 1 ; out <= 5; out++) for (int in = 1 ; in <= 5 ; in++) { cout << "out = " << out << " in = " << in << " " ; if (in % 5 == 0 ) cout << endl; } return 0; } The program output is: out = 1 in = 1 out = 1 in = 2 out = 1 in = 3 out = 1 in = 4 out = 1 in = 5 out = 2 in = 1 out = 2 in = 2 out = 2 in = 3 out = 2 in = 4 out = 2 in = 5 out = 3 in = 1 out = 3 in = 2 out = 3 in = 3 out = 3 in = 4 out = 3 in = 5 out = 4 in = 1 out = 4 in = 2 out = 4 in = 3 out = 4 in = 4 out = 4 in = 5 out = 5 in = 1 out = 5 in = 2 out = 5 in = 3 out = 5 in = 4 out = 5 in = 5 In the above example, the statements in the body of the innermost for loop are repeated for every value of out in the outer for loop: First the value of out is set to 1 and then the inner loop is executed with values of in ranging from 1 to 5, then the outer loop index out is incremented to 2 and again the inner loop repeats with values of in ranging from 1 to 5. The process repeats until the outer loop terminated when out becomes equal to 6. The break statement: ------------------- A break statement can be used inside a loop construct to prematurely terminate the loop. Program execution then resumes with the statement which follows the looping statement. The break can be used in any of the C++ looping constructs. Here is an example of a for loop with a break statement which forces an exit from the loop when the user enters the value -999: // Author: Ted Obuchowicz // Jan. 7, 2002 // example program illustrating use of // break statement inside a for loop to cause premature exit // from the loop #include #include using namespace std; int main() { int exit_value = -999; // suppose we wish to stop processing the loop if user // inputs this value int input_value; for ( ; cin >> input_value ; ) if ( input_value != exit_value) cout << "You entered " << input_value << endl; else { cout << "exit_value encountered in input stream... breaking from loop!" << endl; break; // exit from the loop } return 0; } The use of break statements inside of loops is somewhat recommended against as it makes program behaviour difficult to understand. Sometimes it is possible to rewrite the loop without using a break as in the following possible to rewrite the loop without using a break as in the following alternate version of the above program: // Author: Ted Obuchowicz // Jan. 23, 2002 // example program illustrating use of // loop rewritten without a break #include #include using namespace std; int main() { int exit_value = -999; // suppose we wish to stop processing the loop if user // inputs this value int input_value; for ( ; ( (cin >> input_value) && (input_value != exit_value) ) ; ) cout << "You entered " << input_value << endl; return 0; } A BREAK STATEMENT MAY ONLY APPEAR IN A SWITCH STATEMENT OR IN ANY OF THE LOOP STATEMENTS. IT MAY NOT APPEAR ANYWHERE ELSE! The following program does not compile (since it contains a break in an if statement which is not allowed in C++): ted@brownsugar Programs 8:01pm >g++ -o illegal_break illegal_break.C illegal_break.C: In function `int main()': illegal_break.C:30: break statement not within loop or switch // Author: Ted Obuchowicz // Jan. 23, 2002 // example program illustrating // an illegal use of a break statement #include #include using namespace std; int main() { int i, j; cin >> i >> j; if ( i < 5 ) { cout << "i less than 5" << endl; cout << "Have a nice day" << endl; if ( j < 10 ) { cout << " j less than 10 " << endl; cout << " have a good evening " << endl; break; // this break is illegal } cout << " j is not less than 10 " << endl; } return 0; } The continue statement: ----------------------- The continue statement is used ONLY IN LOOPS. When a continue statement is encountered in the body of a loop, the REMAINING statements in the body of the loop are SKIPPED OVER, and a new LOOP ITERATION commences. Note that that while a continue statement causes the program to skip any remaining body statements , it does not skip the loop test_expression. In a for loop, the continue makes the program skip to the postexpression part and then it tests the condition. In a while loop, the continue causes the program to go directly to the test expression part of the while (condition) . Here is a program which uses a continue statement within a for loop which reads 5 characters and counts the number of 't' characters which have been entered: // Author: Ted Obuchowicz // Jan. 23, 2002 // example program illustrating use of // a continue statement within a for loop #include #include using namespace std; int main() { char a_letter; int how_many_ts = 0; for(int i = 0; i < 5; i++) { cout << "Please enter a letter " ; cin >> a_letter; if ( a_letter != 't' ) continue; cout << "Ahhhh... the t was entered!" << endl; how_many_ts++; } cout << "The total number of t's entered was " << how_many_ts << endl; return 0; } If the letter entered is not equal to 't', then the program goes to the i++ part of the for (int i = 0; i < 5; i++) part and evaluates if the condition i < 5 is true or not. Based on this evaluation either the loop continues or terminates. If the letter entered is equal to 't', then the two statements following the continue are executed and loop execution carries on in the normal manner (when it gets to the } the i++ is executed and the condition is evaluated). More examples of programs with loops ------------------------------------ Example 1: Computing the factorial of a postive integer using a for loop. The factorial of an integer n (designated as n!) is defined as the product of the integers 1 through n: n! = 1 if n = 0 = n x (n-1) x ... x 1 if n >=1 We can use a for loop to compute the product of the numbers 1 through n as in the following program: // Author: Ted Obuchowicz // Jan. 23, 2002 // example program illustrating use of // a for loop to compute the factorial // of a number n #include #include using namespace std; int main() { unsigned long int n; unsigned long int n_factorial = 1; cout << "Please enter a positive integer " << endl; cin >> n; for (unsigned long int i = 1 ; i <= n ; ++i) n_factorial = n_factorial * i; cout << n << "! is " << n_factorial << endl; return 0; } This program exhibits interesting behaviour: it reports the following answers: 10! is 3628800 11! is 39916800 12! is 479001600 13! is 1932053504 the last value is incorrect as the true value of 13! = 6 227 020 000. This value exceeds the maximum value of an unsigned long int (which on our UNIX workstations is 4 294 967 295) so an integer OVERFLOW arises during the calculation of 13! and an incorrect answer is given. How do we fix the problem??? Simple.... change the type of the variable n_factorial from unsigned long int to a double: // Author: Ted Obuchowicz // Jan. 23, 2002 // example program illustrating use of // a for loop to compute the factorial // of a number n #include #include #include // needed for the setprecision() using namespace std; int main() { unsigned long int n; double n_factorial = 1.0; cout << "Please enter a positive integer " << endl; cin >> n; for (unsigned long int i = 1 ; i <= n ; ++i) n_factorial = n_factorial * i; cout << setprecision(15) << n << "! is " << n_factorial << endl; return 0; } Now, it gives correct results (to a certain point): 10! is 3628800 11! is 39916800 12! is 479001600 13! is 6227020800 14! is 87178291200 69! is 1.71122452428141e+98 (on most pocket calculators this is nearing the limit) 70! is 1.19785716699699e+100 100! is 9.33262154439441e+157 170! is 7.25741561530799e+306 171! is Infinity Interestingly enough, it reports 171! as Infinity... recall the range of the double data type... it was someting like 1.75 e +308. When we tried to calculate 171! a floating point overflow occured... most computers use a standard called the IEEE 754 floating point standard to represent real numbers... the standard has a method of representing Infinity (when the number exceeds the representable range of values)... similary the IEEE 754 standard has something called NaN (Not a Number),,, you will see this displayed when you try to do something stupid like taking the square root of a negative number . What do you think the output of the following program will be? / Author: Ted Obuchowicz // Jan. 23, 2002 // example program illustrating // an attempt to divide by zero #include #include using namespace std; int main() { cout << " 1 divided by 0 is " << 1 / 0 << endl; return 0; } These are the compile time messages: infinity.C: In function `int main()': infinity.C:18: warning: division by zero in `1 / 0' Let's run the program: ted@flash Programs 9:57pm >infinity Floating exception ted@flash Programs 9:57pm > Example 2: A program to compute the first 15 Fibonacci Numbers: The sequence of numbers: 1 1 2 3 5 8 13 21 , .... where the first two numbers in the sequence are equal to 1, and every successive term is the sum of the previous two terms is known as the Fibonacci sequence. It was developed by an Italian mathematician by the name of Leonardo Pisano in 1202. He stumbled upon his famous sequence while pondering the problem of determining the number of rabbits which a pair of fertile rabbits may produce in one year... Here is a program which uses a for loop to display the first 15 Fibonacci numbers: // Author: Ted Obuchowicz // Jan. 23, 2002 // example program illustrating use of // for loop to display the first 15 Fibonacci numbers #include #include using namespace std; int main() { int previous = 1; int current = 1; int sum; cout << 1 << endl; cout << 1 << endl; for(int i = 3; i <= 15; i++) { sum = previous + current; cout << sum << endl; previous = current; current = sum; } return 0; } The program output is: 1 1 2 3 5 8 13 21 34 55 89 144 233 377 610 The do-while loop ----------------- C++ has another loop constuct called the do-while loop which is used in situations where a certain action is to be performed AT LEAST ONCE. The general form is: do { statement 1; statement 2; ... last_statement_to_do; } while (some_condition); Here is a simple program which uses the do while statement: // Author: Ted Obuchowicz // Jan. 28, 2002 // example program illustrating use of // do while construct with a guessing game which continues // prompting the user for a number between 1 and 100 until // the user guess the "right answer" (which is set at 58, // Keith Richards' current age. The program also keeps track // of the number of guesses until a corrdsct guess is entered #include #include using namespace std; int main() { const int Keiths_age = 58; int num_of_guesses = 0; int user_guess; do { cout << "Please enter a guess between 1 and 100" << endl; cin >> user_guess; num_of_guesses++; } while (user_guess != 58); cout << "Congratulations. It took you " << num_of_guesses << " to guess Keith's age." << endl; return 0; } Some more examples of loops: ---------------------------- Here is a program which uses while loops to "decompose" an integer value (which is less than 1 000 000) into its components consisting of the number of hundreds of thousands, number of tens of thousands, number of thousands, etc. A typical interaction withe the program is: Please enter a number less than a million 567890 hundreds of thousands = 5 tens of thousands = 6 thousands = 7 hundreds = 8 tens = 9 ones = 0 Here is the program which uses a sequence of while loops: // Author: Ted Obuchowicz // Jan. 29, 2002 // example program illustrating use of #include #include using namespace std; int main() { int hundred_thousands_counter = 0; int ten_thousands_counter = 0; int thousands_counter = 0; int hundreds_counter = 0; int tens_counter = 0; int ones = 0; int number; cout << "Please enter a number less than a million" << endl; cin >> number; while (number >= 100000) { hundred_thousands_counter++; number = number - 100000; } while (number >= 10000) { ten_thousands_counter++; number = number - 10000; } while (number >= 1000) { thousands_counter++; number = number - 1000; } while (number >= 100) { hundreds_counter++; number = number - 100; } while (number >= 10) { tens_counter++; number = number - 10; } ones = number; cout << "hundreds of thousands = " << hundred_thousands_counter << endl; cout << "tens of thousands = " << ten_thousands_counter << endl; cout << "thousands = " << thousands_counter << endl; cout << "hundreds = " << hundreds_counter << endl; cout << "tens = " << tens_counter << endl; cout << "ones = " << ones << endl; return 0; } We start off with the first while loop which will be entered if the number >= 100000, the loop is entered and we keep on subtracting 100000 from the number and increment a counter. Eventually, the number becomes less than 100000 and we continue with the next loop. This loop is responsible for subtracting 10000 from the resulting number and incrementing a certain other counter. We do this for 1000, 100, 10 ... whatever is left over is the number of 'ones' in the number. Here is a more cryptic version of a similar program. It simply displays line by line the number of hundreds of thousands, number of thousands, etc that make up a certain number: The output is: Please enter a number less than a million 345678 3 4 5 6 7 8 The actual program is: // Author: Ted Obuchowicz // Jan. 29, 2002 // example program illustrating use of #include #include #include using namespace std; int main() { int number; cout << "Please enter a number less than a million" ; cin >> number; for(int i = 6 ; i >= 1 ; i--) { cout << (number % (int)( pow(10, i) )) / ( (int) pow(10, i-1)) << endl ; } return 0; } Which version is easier to understand??? The pow(x,n) function returns the value of n x by the way. It is found in the library It makes use of the following facts about the mod operator: i = 1 ones = 345 % 10 = 5 1 i = 2 tens = 345 % 100 = 45 , then do 45/ 10 , where the division is performed as INTEGER DIVISION (4.5, we truncate the 0.5 to obtain 4) 2 i = 3 hundreds = 345 % 1000 = 345, then do 345 / 10 to obtain 3 (again as interger division) in each loop interation we are doing i number % 10 , then take this result and do i-1 result % 10 Difficult to understand from the code, but it was possible to code the program using a single clever for loop.