Chapter 4 : Loops

Chapter 4 : Loops

In the programs we have written so far, the statements in the program have been executed in sequence, from the start of the program to the end, omitting sections of "if" and "switch" constructs which have not been selected. The real power of computers comes from their ability to execute given sets of statements many times.

The repetition may be required for several reasons.

To repeat sets of instructions there are three main loop constructs in C.

Contents

4.1. "while" loops

A "while" loop repeats a given set of instructions until a given condition holds. The notation is as follows.

The condition to be tested is contained in parentheses (round brackets) after the word "while", and the body of the loop is in curly braces after the condition. There is no semi-colon after the closing curly brace.

The sequence of operations in the loop (after the initialisation of the value of "number" to 10, for example) is

  • (i) Test whether "number >= 0".
  • (ii) If it is FALSE, abandon the loop, and continue with the statements after the closing curly brace. In this case, the next statement to be executed would print out the "Loop ended" message.
  • (iii) If the result of "number >= 0" is TRUE, execute the statements in the body of the loop (between the curly braces, in this case first print a message, and then decrement the value of "number" by 1), and then return to step (i) above.

    The test is TRUE to continue the loop, FALSE to leave it. The test occurs before the loop is executed; the loop may not be executed at all if the test result is FALSE the very first time that it is encountered. The pattern of execution is thus

    or

    or

    and so on. The last test on each line must have delivered the result FALSE; earlier tests must have delivered the result TRUE.

    When the loop finishes, control passes to the next instruction in the program, following the closing curly brace of the loop.

    Some simple examples of "while" loops

    To execute a loop for an integer variable "number" taking the values 1, 2, ..., 10 you may use any one of the following four possible "while" loop constructions.

    Version 1

    Version 2

    Version 3

    Version 4

    In the first two examples, it is immaterial whether you write "number++;" or "++number;"; to increment to value of "number" either of these will do. In the third and fourth examples, you must use "++" as shown.

    Some points to observe

  • 1 If what you really want is to execute the loop 10 times, write the condition (as above)

    and not as

    The numeric denotations (actual numeric values) appearing in your program should be exactly the numbers you would talk about in describing what the program is required to do. In this case, the value 9 should not appear. If you are converting seconds to minutes and hours, the value 59 should not appear, only the value 60. The Ceilidh automatic marking system checks program features such as this.

  • 2 In general, specific values such as "10" should not appear within the body of your program. They would probably be needed in more than one place, since you may have several loops processing the same number of data items. You should therefore declare them as "const"s at the top of the program as typified by the example

    The Ceilidh marking system checks that values other than, for example "0" and "1" do not appear in the body of the program, and appear exactly once in a "const" declaration. My examples in the notes may not follow this rule.

  • 3 In C generally you would more likely want to loop not from 1 to 10, but from 0 to 9. All counting in C tends to start at zero rather than one. This is a convention that most C programmers adopt.

    More examples of "while" loops

    To add together the sequence

    until the terms we are adding together are smaller than 0.00001 the program might be as follows.

    The value of "term" is halved each time round the loop; each of these values is added to the total.

    To read positive integer numbers in, terminated by a zero, and print the biggest one.

    Note that the terminating zero is still processed by the statements in the second part of the loop. In this example, it will have no effect on the final result. If we were counting how many positive numbers we had read, we would have to be careful not to include the terminating zero.

    If we were printing the square of each number read in, we would probably not want to print the square of the terminating zero. We would then need

    Note the following possible alternative coding, which has the drawback that the input instruction has to be repeated.

    Within the loop, we read the next number at the end of the loop. We must read the very first number before we enter the loop. We show a better solution to this problem later in this chapter.

    4.2. "do" loops

    The "while" loops above performed the test first, and then executed the loop. Sometimes you may wish to test at the end of the loop, after the execution of the statements in the body of the loop (and hence to execute the loop body always at least once). In C we use what is referred to as a "do" loop, written as follows.

    In this case the value of "number" would be 1 the first time round the loop, and 10 the last time.

    The condition (exactly as in a "while" loop) is still contained in round brackets, and is still TRUE to continue with another execution of the loop body, and FALSE to leave the loop. Remember that there is a semi-colon after the condition, terminating the whole statement. We have one more semi-colon overall than the equivalent "while" loop.

    The pattern of execution in this case can be summarised as follows.

    The code in the above programming example could also be written

    This is the form of combined "increment and test" that most C programmers would use. The "++" must, of course, be in front of the "number" in this case.

    It is generally safer to test at the start of a loop; "while" loops are generally safer and more common than "do" loops.

    More examples of "do" loops

    To read in positive numbers until a zero is encountered, and print the biggest one.

    The use of exit

    We may wish to abandon the program from within the body of the loop if some error condition occurs.

    Use of the comma operator

    You can use the comma operator in the condition and write statements such as

    At the start of the loop we decrement "this_one", then increment "that_one", and then test whether "this_one > that_one" before proceeding with the body of the loop.

    It would perhaps be clearer to lay this out as

    This shows each of the statements and tests on separate lines for clarity.

    This type of construction in which the "while" condition involves several statements, effectively gives us a loop which exits in the middle. A simple "while" loop tests and exits at the top, a simple "do ... while" loop tests and exits at the bottom, and a "while" loop with commas tests and exits in the middle of the loop.

    Examples of the comma operator

    The cleanest way to, for example, read integer values until a zero is encountered, is to use the comma operator in the following construct.

    With this program structure, the terminating zero is not processed; this is generally what we require.

    Note the layout of the program; we treat parentheses rather like curly braces. If a matching opening and closing parentheses fit onto one line, that is fine. If they do not, then they should line up with each other and be indented in the same way as curly braces. The Ceilidh automatic marking system checks that program layout conforms to this pattern.

    4.3. "for" loops

    There is a third type of loop in C, called a "for" loop. It is written as follows.

    The general form of a "for" loop is

    The initialise statement is carried out once only, at the start of the very first time that the loop is entered. The test is executed before each execution of the body of the loop. The first time will be immediately after the initialisation, and hence there will be perhaps no executions of the loop body if the test fails at this stage. The third expression is a statement executed after every execution of the loop body, before the next test.

    The sequence is now

    Again note that the increments in the examples above could be written with the "++" before or after the variable identifier; in this case it does not matter.

    Readability

    One of the important advantages of a "for" loop is its readability. All of the essential loop control is grouped together at the top of the loop. We can see at a glance the initial values which are set up, the test to be satisfied for loop exit, and the main variable increments. You should make maximum use of this readability.

    The "for" loop could be written as a "while" loop in the form

    In this layout, the loop control is not so clearly seen.

    Defaults

    Defaults are obvious; any or all of the three control statements can be omitted. The construct

    gives no initialisation, assumes a TRUE test result, and performs no incrementing.

    The dreaded comma again

    You may find the comma operator useful again, particularly in the initialisation and increment parts of the loop control.

    4.4. General points on loops

    4.4.1. Nesting of loops

    Loops may, of course, be nested to any depth in any combination as required.

    The loop executes with "month" and "year" taking the pairs of values [1900,0], [1900,1], [1900,2], ..., [1900,11], [1901,0], [1901,1], ..., [1901,11], ..., [1999,11] in turn in that order.

    4.4.2. The "break" statement

    In any of the above loops, the special statement "break" causes the loop to be abandoned, and execution continues following the closing curly brace.

    The program continues after the end of the loop.

    Within a nested loop, "break" causes the innermost loop to be abandoned.

    4.4.3. The "continue" statement

    In any of the above loops, the statement "continue" causes the rest of the current round of the loop to be skipped, and

  • a "while" or "do" loop moves directly to the next test at the head or foot of the loop, respectively; and
  • a "for" loop moves to the increment expression, and then to the test.

    4.4.4. Example of "break" and "continue"

    We wish to write a loop processing integer values which we have read in. If the value we have read is negative, we wish to print an error message and abandon the loop. If the value read is great than 100, we wish to ignore it and continue to the next value in the data. If the value is zero, we wish to terminate the loop.

    4.4.5. Comments

    It is good practice to comment the end closing curly brace of any loop which extends over more than a few lines. The Ceilidh system expects a comment after every closing brace which appears more than 10 lines from its opening curly brace.

    4.4.6. Curly braces

    If there is only a single statement in the loop body, the curly braces are not obligatory in C. It is however recommended that you always use them.

    4.4.7. Empty loop bodies

    You may find examples of programs in which the complete work of a loop is performed within the parentheses of the test; such a loop may have an empty body.

    This is quite legal; it may not be clear to a reader at first glance exactly what is happening.

    4.5. Other general loop examples

    4.5.1. Sum, minimum, and maximum of data

    Read positive "float" values from the input, and print their sum, how many numbers were read, the largest value and the smallest value.

    Be careful if you wish to print the average of the numbers, and use

    You must ensure that you can never attempt a division by zero. Wherever there is a division sign in a program you must be able to prove that the denominator cannot be zero.

    4.5.2. Sum of squares

    To sum the square of all the integer values from 1 squared up to 99 squared.

    4.5.3. Decreasing powers of 2

    To print (in decimal) the decreasing powers of 2 (1, 1/2, 1/4, 1/8, ...) you would write:

    It may be clearer to write

    4.5.4. Read a sentence of text

    To read text until a full stop (period) is encountered, and to count the number of occurrences of the letter "e", you could write:

    4.5.5. Increasing and decreasing integers

    To read a series of integers, terminated by a zero, and print how many times an integer was larger than its predecessor, and how many times it was smaller. Ignore the terminating zero.

    Coursework exercise marking

    The exercises in this unit are marked partly on dynamic correctness, partly on typographic layout, partly on features (see earlier units for details of all of these), and may now have two new sub-headings, Complexity and Structure.

    The complexity marker compares the complexity of the structure of your solution (the number of conditional, the number of loop,s, the depth of the loops, etc) with the teacher's model solution. Your program should not differ too far from the teacher's.

    The structure marker looks for program weaknesses such as variables declared and not used, variables with values assigned but not used, and other points such as those revealed by using the verbose compilation option.

    Copyright Eric Foxley 1996


    Notes converted from troff to HTML by an Eric Foxley shell script, email errors to me!