LOOPS (Repetitive Structures) Pascal supports three different loop structures based on the reserved words WHILE DO, REPEAT UNTIL and FOR DO. Without question, mastery of loop structures is a key requirement of any programming environment. "With practice of key concepts comes mastery thereof!" WHILE DO: WhileDo Statements in loop body 1. Before the loop is executed, the Boolean expression must be properly initialized; otherwise the loop may be out of control and the statements in the loop body never executed. Example: Sum := 0; While Sum > 0 Do etc. 2. If the loop body consists of two or more statements, the loop body must be enclosed in a BEGIN .. END pair. Otherwise, only the first statement will be considered part of the loop body. Example: Sum := 0; Count := 1; While Count <= 10 Do Sum := Sum + Count; Count := Count + 1; Writeln(Sum); This is an example of a loop which is out of control. The ONLY statement the compiler considers is in the loop body is the first statement "Sum := Sum + Count". Since the value of Count is never altered while the loop executes, the computer is now in an infinite loop condition. What was likely intended by the programmer was: Sum := 0; Count := 1; While Count <= 10 Do Begin Sum := Sum + Count; Count := Count + 1; End; Writeln(Sum); 3. The programmer is required to ensure that the Boolean Expression controlling the WHILE DO loop is properly initialized before the loop begins and that the Boolean Expression is updated (or altered) sometime during loop execution. Even so, it is a logical possibility that a WHILE DO loop will never execute. EXAMPLE OF WHILE DO LOOP The following problem is an example of a SENTINEL CONTROLLED PROCESS: Read in integers until a -1 is encountered. The output is to consist of (1) the number of integers entered; (2) their real average; (3) the largest integer entered. All variables are declared integer, except Average is declared real. Sentinel := -1; { declare value of sentinel "flag" } Sum := 0; { initialize accumulator and counter } Count := 0; Read(Number); { perform a so-called "priming read" } Largest := Number; { initialize what will become largest value read } While (Number <> Sentinel) Do Begin Sum := Sum + Number; Count := Count + 1; If Number > Largest Then Largest := Number; { read next number only after previous number has been completely processed } Read(Number) End; If Count > 0 Then Begin Average := Sum / Count; Writeln('There were ', Count, 'numbers entered.'); Writeln('Their average is: ', Average :0:2); Writeln('The largest number entered was: ', Largest) End Else Writeln('There was no data processed.'); The following example shows a COUNT CONTROLLED PROCESS: Read in 50 numbers. Print out the numbers, 5 to a line, and then their average. Number_to_read := 50; Count := 0; Sum := 0; While (Count < Number_to_read) Do Begin Read(Number); { input a number } Sum := Sum + Number;{ update the accumulator } Count := Count + 1;{ update the counter } Write(Number :8) { print the number } If Count Mod 5 = 0 { perform a line feed if needed } Then Writeln; End; If Count > 0 Then Begin Average := Sum / Count; Writeln('Their average is: ', Average :0:2) End Else Writeln('There was no data processed.'); Nested WHILE loops are certainly allowed. For example, a well-known example problem involves printing out a simple multiplication table for the integers from 1 - 9: Program Mult_table; Uses Crt; Const Max_row = 9; Max_col = 9; Var Row, Column, Product: Integer; Begin Clrscr; Row := 1; Writeln(' x | 1 2 3 4 5 6 7 8 9'); Writeln('---|---------------------------------------------'); While (Row <= Max_row) Do Begin Column := 1; Write(Row :2, ' |'); While (Column <= Max_col) Do Begin Product := Row * Column; Write(Product :5); Column := Column + 1 End; Writeln; Row := Row + 1 End; Readln End. PROGRAM OUTPUT: x | 1 2 3 4 5 6 7 8 9 ---|--------------------------------------------- 1 | 1 2 3 4 5 6 7 8 9 2 | 2 4 6 8 10 12 14 16 18 3 | 3 6 9 12 15 18 21 24 27 4 | 4 8 12 16 20 24 28 32 36 5 | 5 10 15 20 25 30 35 40 45 6 | 6 12 18 24 30 36 42 48 54 7 | 7 14 21 28 35 42 49 56 63 8 | 8 16 24 32 40 48 56 64 72 9 | 9 18 27 36 45 54 63 72 81 REPEAT UNTIL Repeat Until Boolean The Repeat loop is a bottom driven loop (i.e., the Boolean test follows the execution of the loop body). Notice that: (1) The loop body will ALWAYS be executed at least once, since the Boolean test comes after carrying out the instructions in the loop. Thus a REPEAT UNTIL loop should NEVER be used when it is a logical possibility that the loop should never execute. REPEAT LOOPS ALWAYS EXECUTE AT LEAST ONCE! (2) A BEGIN-END pair is not necessary around the loop body in a REPEAT UNTIL loop, since the key words REPEAT and UNTIL encapsulate the instructions in the loop body. (3) Notice the primary distinction between WHILE and REPEAT loops: a WHILE loop executes while (as long as) the Boolean test is TRUE. A REPEAT loop executes until the Boolean becomes true (i.e., while the Boolean is FALSE). A typical example of a REPEAT loop is synthesizing exponents in Pascal: Count := 1; Base := 4; Power := 1; REPEAT Power := Power * Base; Count := Count + 1; UNTIL (Count = 5); Writeln('Four to the fifth power is ', Power); Another popular use of REPEAT loops in to control a menu of choices. Refer to problem #12, page 152. Program Menu; Uses Crt; Var Count, Sum, Value, Largest: Integer; Average: Real; Choice: Char; Begin Largest := 0; Count := 0; Sum := 0; Randomize; REPEAT Clrscr; Writeln('A. Generate a new value.'); Writeln('B. Report average to this point.'); Writeln('C. Report highest value to this point.'); Writeln('Q. QUIT'); Writeln; Write('Enter your selection ==> '); Readln(Choice); If NOT((Choice = 'Q') or (Choice = 'q')) Then Begin Case CHOICE of 'A', 'a': Begin Value := Random(99); Writeln('Value generated = ', Value); If Value > Largest Then Largest := Value; Sum := Sum + Value; Count := Count + 1; End; 'B', 'b': If Count > 0 Then Begin Average := Sum / Count; Writeln('Average so far is ', Average :0:2) End Else Writeln('No average possible to this point.'); 'C', 'c': If Count > 0 Then Writeln('Largest value so far is ', Largest) Else Writeln('No largest value to this point.'); Else Writeln('Illegal value entered.') End; { CASE } Writeln; Write('Press enter key to continue...'); Readln End; Until (Choice = 'Q') or (Choice = 'q') End.