C for Yourself - part 10

Steve Mumford takes a look at how C handles the processes of decision and interation.

Up to this point, the flow of the programs in this series has been somewhat linear and the computer has not had to make many decisions on the route it takes through the code - executions starts with the first line in main() and continues until the program terminates. However, this rigidity is unacceptable on all but the most basic of programs, and techniques are needed which allow the flow of the program to be altered. In this article, I will be describing the ways in which you can interrupt the stream of the program to allow conditional execution of program segments to take place. After that, I'll move on to mention the forms of loop available in C.

Decisions, decisions

The simplest form of decision is the if statement and it takes the form shown below:

if (condition)
{
  /* some statements */
}

The statements contained within the braces are only executed if the condition evaluates as being true - otherwise, the computer simply skips over them and continues executions wherever the id construction finishes. Greater flexibility is provided by the else keyword, allowing you to chain several if statements together, providing a method of making multi-choice decisions.

if (guess == number)
{
  printf("You are correct!\n");
} else
if ((guess > number-5) && (guess < number+5))
{
  printf("Well, you were close.\n");
} else
{
  printf("Sorry, that's not right.\n");
}

The switch statement

Although you can use these chained ifs to make a choice from a long list of possibilities, C has a different construction to make your life that bit easier:

switch (x)
{
  case 1:
    printf("x = 1\n");
    break;
    
  case 2:
    printf("x = 2\n");
    break;
    
  default:
    printf("x does not equal 1 or 2\n");
    break;
}

This code fragment examines the value of the integer x and then makes the comparisons give in the block - if x is equal to a constant included after a case statement, the program begins execution at that point and continues until it reaches a break statement or the end of the switch block.

The statements after the default keyword are executed if none of the case statements match the value given after the switch command. This feature makes the switch construction particularly useful for creating menu systems - after the user has picked an option from the menu, it can be checked against a list of possibilities and the appropriate action take. If the user happens to enter an option that is not supported by the menu, the default action is taken, and this might be to inform the user to make another choice.

The break statement is particularly important here, as once a case has been found that matches the switch expression, the program begin execution at that point and will ignore any following case comparisons, continuing execution until the next break. Although this can be useful in a few cases, after you've spent a good while implementing your menu structure, it's somewhat demoralising to find that the computer is executing most of the options regardless of your choice.

There are a couple of restrictions on the switch construction - firstly, it can only test for integers (and characters, since these are actually stored as an integer). Secondly, you must not include two case constants with the same value in the same switch.

The 'for' loop

There are several forms of loop available in C, and we'll start by examining the for loop. It's somewhat different to the one implemented in BASIC in that instead of stepping between two constants, it keeps iterating while a suitable condition is met:

for (initialisation; loop condition; increment)
{
  /* statements to be repeated */
}

The initialisation is usually something simple like x=0 which prepares the variable to be used as the looping flag. However, you must still remember to declare the variable earlier in the program. The loop will continue repeating while the condition given in the middle of the statement is true - this might be x<=5. Finally, the increment statement is applied to the flag on each successive loop, and in this case it could be x++. Putting this together would give a loop similar to the following:

for (x=0; x<=5; x++)
{
  printf("The value of x is %d\n", x);
}

This fragment would loop six times, printing out the numbers 0 to 5 on the screen. This is a somewhat contrived example, and the for loop can be used for more creative tasks - for instance, an infinite loop can be constructed by leaving all three fields blank, and the only way to escape from such a loop is by using the break command.

The 'while' loop

The for loop is generally used when the programmer knows what the start and end conditions are in advance - however, this is not always possible so another, more general form is needed, and this is known as the while loop. There are two closely-related forms which test for the end condition at different times in the cycle, and we'll start with the simpler version:

while(condition)
{
  /* statements to be repeated */
}

The statements are repeated while the condition given at the top of the loop is true, but it's important to see that since the comparison is made at the head of the structure, the statements in the loop will never get executed if the condition is false to begin with.

The second form is known as the do-while loop, and it looks rather similar in its construction - however, you must remember to include the semi-colon at the end of the block!

do
{
  /* statements to be repeated */
} while (condition);

The major difference is that the statements in the loop are always executed at least once, because the comparison is only made at the end of the block. If the construction feels a little familiar, that because it's similar to REPEAT-UNTIL in BASIC, with the difference being in the way it tests for the end condition. REPEAT-UNTIL loops until a condition is met, and do-while iterates while a condition is met - they're said to be logically opposite.

Break and continue

We've already used the break command while we were discussing switch statements, but its main use is to terminate execution of a loop immediately. This might be included in a data-loading function to allow it to be stopped if the end of a file was reached unexpectedly. When the program comes across a break, it will exit from the loop it was executing at the time. If you have several nested loops, the break will only exit from the innermost one, and program execution will continue with the loop surrounding it.

C has a related command named continue - this is less severe when compared to break, and instead of exiting the loop completely, it just forces an early iteration:

for (x=0; x < 15; x++)
{
  if (x==13) continue;
  printf(x = %d\n", x);
}

For the supersitious among you, this program fragment will print out the integers from 0 to 14, missing out the number 13. When the continue command is issued, it immediately skips pas the rest of the statements in the loop, and returns control to the head of the block. The loop flag is incremented and the end condition tested, and if the loop is still valid it continues as normal.

The dreaded goto

I've only included this command for the sake of completeness - I learnt the error of my ways a long time ago. The goto command leads to code that's notoriously difficult to follow, and due to the way C has been written, it's actually obsolete. With that in mind, here's how you write one:

x = 0;
loop:
x++;
if (x < 50) goto loop;
printf("x = 50!\n");

To perform a goto you must have defined a label elsewhere in the program by including a valid identifier followed by a colon. In this case, the label is loop:. The fragment keeps incrementing x and returning to loop until x is equal to 50. So now you know, but for the benefit of programmers everywhere, please try to avoid using it.


Source: Acorn User - 154 - April 1995
Publication: Acorn User
Contributor: Steve Mumford