All programming language utilise program constructs. In imperative languages they are used to control the order (flow) in which statements are executed (or not executed). There are a number of recognised basic programming constructs that can be classified as follows:
A sequence construct tells the processor which statement is to be executed next. By default, in imperative languages, this is the statement following the current statement (or the first statement in the program). If we wish to "jump" to some other statement we can use a goto statement. This was popular in the early days of computer programming (1950's to early 1960's). Example BASIC goto statement:
GOTO 400
This tells the processor to "jump" to line 400 and to then continue processing from this point in the program. The use of goto statements was also encouraged by languages such as Fortran and Cobol.
Goto statements make it difficult to "trace" a program's execution and to determine the state of variables at a given point during processing. As a result errors are often obscure and difficult to locate. For this reason some more modern (post mid 1960's) imperative languages, for example Modula-2 and Pascal, have abandoned the goto statement all together. However, there are some legitimate reasons why a goto may be desirable, for example to facilitate error handling or to terminate a deeply nested sequence of loops. Both Ada and C support a goto statement but it is best avoided.
A selection statement provides for selection between alternatives. We can identify three types of selection construct:
However, imperative languages do not generally make much use of pattern matching
(logic and some modern functional languages do), thus we will limit the following discussion to the "if" and "case"
forms of selection.
An if statement, sometimes referred to as a conditional, can be used in two forms:
Where X is a Boolean expression (or a sequence of Boolean expression), and Y and Z are program statements of some description. We can also identify a number of variations of the above which are particular to individual programming languages. For example the Ada:
if X1 then Y1 elsif X2 then Y2 ... elsif Xn then Yn else Yn+1 end if
with CS_IO ; use CS_IO ; procedure IF_ELSE_EXAMPLE is NUM_X, NUM_Y, NUM_Z: integer; begin get(NUM_X); if NUM_X < 0 then NUM_Y := -NUM_X; NUM_Z := 10+NUM_X; else NUM_Y := NUM_X; NUM_Z := 10-NUM_X; end if; put("NUM_X = ");put(NUM_X);new_line; put("NUM_Y = ");put(NUM_Y);new_line; put("NUM_Z = ");put(NUM_Z);new_line; end IF_ELSE_EXAMPLE;
#includevoid main(void) { int num_x, num_y, num_z; scanf("%d",&num_x); if (num_x < 0) { num_y = num_x*num_x; num_z = 10+num_x; } else { num_y = num_x*num_x*num_x; num_z = 10-num_x; } printf("num_x = %d, num_y = %d, num_z = %d\n",num_x,num_y,num_z); }
Generally speaking an "if ... then ... else ..." statement supports selection from only two alternatives; we can of course nest such statements, but it is usually more succinct to use a case statement. Case statements allow selection from many alternatives where each alternative is linked to a predicate, referred to as a selector, which when evaluated to true causes an associated program statement (or statements) to be executed. Selections may be made according to:
Selectors must be of a discrete type (typically an integer, a character or an enumerated type). C only supports selection by distinct value or default (default). Ada also supports selection by distinct value and default (others), as well as selection according to:
Also note that where selection is by distinct value, in some cases, these must be presented in the correct numeric order (this is the case in C).
Format:
`case' SELECTOR `is' `when'`=>' ... `end case;'
Usage:
with CS_IO ; use CS_IO ; procedure IF_ELSE_EXAMPLE is SELECTOR : integer; begin case SELECTOR is when 0 => put("SELECTOR equals 0"); when 1 | 5 => put("SELECTOR equals 1 or 5"); when 2..4 => put("SELECTOR equals 2, 3 or 4"); when others => put("SELECTOR less than 0 or greater than 5"); end case; new_line; end (CASE_EXAMPLE);
Format:
`switch' SELECTOR `{' `case' VALUE `:'`break;' ... `}'
Usage:
#includevoid main(void) { int selector; scanf("%d",&selector); switch (selector) { case 0: printf("selector equals 0\n"); break; case 1: case 2: case 3: printf("selector equals 1, 2 or 3\n"); break; default: printf("selector less than 0 or greater than 3\n"); } }
Note that C requires that selectors are presented according to their numeric order. Note also that neither Ada nor C support selection using expressions involving selectors, e.g. a conditional expression or an arithmetic expression. This is supported by languages such as Pascal.
A repetition construct causes a group of one or more program statements to be invoked repeatedly until some end condition is met. Typically such constructs are used to step through arrays or linked lists. We can identify two main forms of repetition:
To which we could add recursion (routine calls itself). Recursion is not used so much in imperative languages, although it is the principal program construct used to achieve repetition in logic and functional languages, thus we will confine ourselves in the following discussion to fixed and variable count loops.
Both fixed and variable count loops can be further classified according to whether they are pretest or posttest loops. In the case of a pretest loop (also referred to as an entrance-controlled loop) the end condition is tested for prior to each repetition, while in the case of a posttest loop (also referred to as an exit-controlled loop) the end condition is tested for after each repetition.
Fixed count loops (sometimes referred to as for loops) allow a statement to be repeated a "fixed" number of times as specified on entry into the loop. Fixed count loops tend to be pretest loops, i.e. the end condition is tested prior to each repetition. Issues:
The following example programs initialise a 10 element array and then processes (outputs) that array using a fixed count (for) loop construct.
Format:
`for' <CONTROL_VALUE> `in' <START_CONDITION> `..' <END_CONDITION> `loop' <STATEMENTS> `end loop;'
Usage (processing an array):
with CS_IO ; use CS_IO ; procedure FOR_LOOP_EXAMPLE is DIGIT: array (integer range 0..9) of integer; begin for INDEX in 0..9 loop DIGIT(INDEX) := INDEX; end loop; for INDEX in reverse 0..9 loop put(DIGIT(INDEX)); new_line; end loop; new_line; end FOR_LOOP_EXAMPLE;
Note that: (1) the control variable INDEX is not declared or initialised by the program and (2) that the second loop processes the array in reverse.
Format:
`for (' <CONTROL_VALUE> `;' <START_CONDITION> `;' <END_CONDITION> `) {' <STATEMENTS> `}'
Usage (processing an array):
#includevoid main(void) { int index=0, digits[10]; for (index;index<10;index++) { digits[index] = index; } for (index=9;index>=0;index--) { printf("%d ",digits[index]); } printf("\n"); }
Note that the way the C for loop construct is used here is fixed count, the construct could equally well be used to implement a variable count loop.
Sometimes there is a need to terminate a loop somewhere in the middle. Many languages therefore support a break (C) or exit (Ada) statement. Ada actually supplies two types of exit statement, exit and exit when.
Variable count loops allow statements to be repeated an indeterminate number of times.
The repetition continues until a control condition (usually a boolean expression) is no longer fulfilled. As such,
variable count loops do
not feature a control variable which is incremented and tested against some end condition on each loop.
Variable count loops may be pretest or posttest loops. Pretest variable count loop are sometimes referred to as
a while loops (Ada, C, Pascal), and posttest variable count loops as a do-while (C) or
repeat (Pascal) loops (Ada does not feature a posttest variable count loop construct).
with CS_IO ; use CS_IO ; procedure WHILE_LOOP_EXAMPLE is COUNTER: integer:= 1; begin while COUNTER <= 10 loop put(COUNTER); put(COUNTER*COUNTER); put(COUNTER*COUNTER*COUNTER); new_line; COUNTER := COUNTER + 1; end loop; end WHILE_LOOP_EXAMPLE;
#includevoid main(void) { void main(void) { int counter = 1; while (counter <= 10) { printf("%d %d %d\n",counter,counter*counter,counter*counter*counter); counter++; } }
with CS_IO ; use CS_IO ; procedure GUESSING_GAME is NUMBER: integer; GUESS, OFFSET: integer:= 64; COUNTER: integer:= 1; begin put_line("Enter a number between"); put_line("1 and 127 inclusive"); get(NUMBER); while COUNTER < 7 loop put(COUNTER); put("Guess ");put(GUESS);new_line; exit when GUESS=NUMBER; OFFSET:= OFFSET/2; if NUMBER < GUESS then GUESS:= GUESS-OFFSET; else GUESS:=GUESS+OFFSET; end if; COUNTER:= COUNTER+1; end loop; if (COUNTER = 7) then put_line("You win!"); else put("Number is ");put(GUESS); new_line; put_line("I win!"); end if; end GUESSING_GAME;
#include <stdio.h> void main(void) { int number, guess = 64, offset = 64, counter = 1; printf("Enter a number between "); printf("1 and 127 inclusive "); scanf("%d",&number); printf("\n"); do { printf("%d) Guess %d\n",counter,guess); if (guess == number) break; offset = offset/2; if (number < guess) guess=guess-offset; else guess=guess+offset; counter++; } while (counter < 7); if (counter == 7) printf("You win!\n"); else printf("Number is %d\nI win!\n",guess); }
Routine (or procedure) invocation is particular to imperative languages. When a sequence of statements forms a conceptual unit about which it is possible and useful to think and reason in isolation it is convenient to encapsulate the sequence in a named routine (procedure) and to replace it with a procedure call in the original code. Unlike a goto statement, routine invocation guarantees that the flow of control will eventually return to the point from which the routine was called (the procedure call).
LIFT CALL: UP - return to imperative home page, DOWN - continue.
Created and maintained by Frans Coenen. Last updated 03 July 2001