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:
1. SEQUENCES
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.
1.2. GOTO STATEMENT CONSIDERED
HARMFUL (Dijkstra 1968)
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.
We can also identify a number of variations of the above which are
particular to individual programming languages. For example the Ada:
There is also nothing that prevents us from nesting "if-else" statements
(Figure 2). A C
example is given below.
Figure 2: Nested if-else control flow diagram
include < stdio.h>
void main(void)
{
int number;
char type[8];
scanf("%d",&number);
if (number < 100) {
if (number < 10) strcpy(type,"small");
else strcpy(type,"medium");
}
else strcpy(type,"large");
printf("%d is %s\n",number,type);
}
|
2.3. CASE STATEMENTS
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:
- A distinct value of a given selector.
- An expression involving the selector.
- A default value.
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:
- A number of Alternatives (each separated by a bar |).
- Ranges expressed using the .. operator.
- Selection by condition *e.g. <, =, >).
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).
Ada Example:
Format:
`case' SELECTOR `is'
`when' < ALTERNATIVES> `=>' < STATEMENTS>
...
`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);
|
C Example:
Format:
`switch' SELECTOR `{'
`case' VALUE `:' < STATEMENTS>
`break;'
...
`}'
Usage:
#include < stdio.h>
void 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.
3. REPETITION AND FIXED COUNT LOOPS
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:
- Fixed count loops - repeat a predefine number of times.
- Variable count loops - repeat an unspecified number of times.
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.
3.1. PRE-TEST AND POST-TEST 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.
4. FIXED COUNT LOOPS
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:
- Type of the control value.
- Nature of start and end conditions.
- Updating the control variable.
- Reverse processing.
- Nesting.
4.1. TYPE OF THE CONTROL VARIABLE
- In some imperative languages (C, Pascal) the control variable is considered to be simply
another data item which is
declared in the normal manner. Thus the control variable can usually be of any discrete type (integer or
char in Pascal).
- In other languages (Ada) the nature of the control variable is predefined - usually as an integer type.
4.2. NATURE OF START AND END CONDITIONS.
- The control variable, in a fixed count loop, must always have some start value, we refer to this value as the start condition for the
loop.
- In some imperative languages the start value is fixed.
- In most other imperative languages (Ada, Pascal, C) the programmer is free to specify a start value, this
is usually some discrete value which is assigned to the control variable. Alternatively in languages such as C and Pascal the
start value may be defined by some assignment expression.
- Fixed count loops must also
always have an end condition
(if they are to terminate). This is usually a Boolean expression, or a sequence of such expressions, involving the control,
variable.
4.5. UPDATING THE CONTROL VARIABLE
- To avoid infinite repetition the control variable must be updated on each repetition.
- The most straight forward approach to updating is to simply increment the control variable by 1 on each repetition.
- In some imperative languages (Ada and Pascal) such incrementation is carried out automatically,
in others (C) it must be specified by the programmer.
- Updating is much more flexible if it can be defined by the programmer.
4.6. REVERSE PROCESSING
- In languages where the control value is automatically incremented, to process a series of
statements in reverse, an
adjective such as reverse (Ada) or downto (Pascal) must be included in the definition
of the loop.
- In languages where the programmer controls incrementation, decrementation can be defined explicitly in
the same manner that incrementation is defined.
4.7. C AND ADA FOR LOOP EXAMPLES
The following example programs initialise a 10 element array and then processes (outputs) that array using a
fixed count (for) loop construct.
Ada Example:
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.
C Example:
Format:
`for (' <CONTROL_VALUE> `;' <START_CONDITION> `;' <END_CONDITION> `) {'
<STATEMENTS>
`}'
Usage (processing an array):
#include < stdio.h>
void 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.
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.
4.8. NESTING
- All common imperative languages support nesting of for loops (Figure 3).
#include < stdio.h>
void main(void)
{
int num1, nmu2;
for (num1=4; num1!=1; num1--) {
for (num2=2; nmu2 < =6; num2=num2+2) {
printf(" %d",num1+num2);
}
printf("\n");
}
}
|
4.9. EXAMPLE WITH MORE THAN ONE CONTROL VARIABLE
|
Figure 3: Nested loop control flow diagram
|
#include < stdio.h>
void main(void)
{
char letter;
int number;
for (letter = 'A', number = 2;
letter < 'J'; letter++,
number = number+5) {
printf("%c(%d), %c(%d)\n",letter,
letter,letter+number,
letter+number);
}
}
|
5.1. REPETITION AND VARIABLE COUNT LOOPS
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).
Ada While Loop Example (Variable Count):
with CS_IO ; use CS_IO ;
procedure EXAMPLE is
X: integer range 0..10;
begin
put_line("Input integer 0..10")
get(X);
while X < = 10 loop
put(X);
put(X*X);
put(X*X*X);
new_line;
X := X + 1;
end loop;
end EXAMPLE;
|
C While Loop Example (Variable Count):
#include < stdio.h >
void main(void)
{
int x = 1;
printf("Input integer 0..10\n");
scanf("%d",&x);
while (x <= 10) {
printf("%d %d %d\(bs",
x,x*x,x*x*x);
x++;
}
}
|
5.1 FOR LOOP OR WHILE LOOP?
Both for and while loops are "pretest" loops. In languages where "for" loops
can only be used to describe fixed count loops (e.g. Ada, Pascal,
BASIC) the answer is straight forward:
- For statements for fixed count loops
- While statement for variable count loops
In C where for and while statements can be used to describe both fixed and variable count loops, it simply
a matter of style. The following two examples show how Ada and C while loops can
be used to repeat for a "fixed" number of itterations.
Ada While Loop Example (Fixed Count):
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;
|
C While Loop Example (Fixed Count):
#include < stdio.h >
void main(void)
{
void main(void)
{
int counter = 1;
while (counter < = 10) {
printf("%d %d %d\n",counter,counter*counter,counter*counter*counter);
counter++;
}
}
|
Similarly, the following C example shows how the same variable count program
can be implemented using botha for and a while construct.
void main(void) {
int x;
scanf("%d",x);
while (x < = 10) {
printf("%d ",x);
printf("%d ",x*x);
printf("%d\n",x*x*x);
x++;
}
}
|
|
void main(void) {
int x;
scanf("%d",x);
for(; x < = 10; x++) {
printf("%d ",x);
printf("%d ",x*x);
printf("%d\n",x*x*x);
}
}
|
|
6. POST-TEST LOOPS (DO-WHILE)
Whereas for pretest loops the control variable is tested prior to, the start of each iteration in postest
loops
the control variable is tested at the end of each iteration.
#include < stdio.h>
void main(void)
{
int numTerms=0, frstTerm, scndTerm, tempNum;
do {
if (numTerms == 0) {
frstTerm = 0; printf("%d ",numTerms);
}
else if (n == 1) {
scndTerm = 1; printf("%d ",numTerms);
}
else {
tempNum = frstTerm+scndTerm;
frstTerm = scndTerm;
scndTerm = tempNum;
printf("%d ",tempNum);
}
numTerms++;
} while (numTerms < 11);
printf("\n");
}
|
C post-test do-while loop example (Fibonacci)
void main(void)
{
int number;
printf("Input an integer between 1 and 50
(inclusive)\n");
do {
scanf("%d",&number);
} while (number < 1 || number > 50);
printf("%d\n",number);
}
|
|
void main(void)
{
int number = 0;
printf("Input an integer between 1 and 50
(inclusive)\n");
while (number < 1 || number > 50) {
scanf("%d",&number);
}
printf("%d\n",number);
}
|
|
Comparison of C pretest (while) loops and post-test
(do-while) loops)
6. TERMINATING A 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 (Figures 4 and 5 give control flow diagrams of pre-test and
post-test loops with exit statements).
Ada actually supplies two types of exit statement, exit and
exit when.
Figure 4: Pre-test loop with exit statement control flow diagram
|
Figure 5: Pre-test loop with exit statement control flow diagram
|
Ada While Loop Example (With exit
Statement):
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;
|
C Do-While Loop Example (With exit
Statement) 1:
#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);
}
|
C Do-While Loop Example (With exit
Statement) 2:
#include < stdio.h>
void main(void)
{
int seed;
printf("Enter seed (odd number within the
range 1 to 8191)\n");
do {
scanf("%d",&seed);
if (seed < 1 || seed > 8191) {
printf("Invalid seed: %d, ",seed);
printf("seed must be within the range ");
printf("1 to 8191, try again!\n");
}
else {
if (seed % 2 == 1) break;
else {
printf("Invalid seed: %d, ",seed);
printf("seed must be an odd number, ");
printf("try again!\n");
}
} while(1) ;
printf("Seed = %d\n",seed);
}
|
6.1 USING AN ADA EXIT STATEMENT TO
ACHIEVE THE EFFECT OF A
POST_TEST LOOP
procedure LOOP_EXAMPLE is
NUMBER : INTEGER ;
begin
PUT("Input an integer between ");
PUT_LINE("0 and 50 (inclusive)");
loop
GET(NUMBER);
exit when (NUMBER < 50 and NUMBER > 0);
end loop;
PUT(NUMBER);
NEW_LINE;
end LOOP_EXAMPLE;
|
Exit statements are best avoided because they cause the flow of control to be
"irregular" and thus break way from the concept of structured
programming. For example we can avoid the use of the exit when
statement as used in the above example by rewriting the code as follows:
procedure LOOP_EXAMPLE is
NUMBER : INTEGER := 10;
begin
PUT("Input an integer between ");
PUT_LINE("0 and 50 (inclusive)");
while (NUMBER < 50 and NUMBER > 0) loop
GET(NUMBER);
end loop;
PUT(NUMBER);
NEW_LINE;
end LOOP_EXAMPLE;
|
7. ROUTINE INVOCATION
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).
Ada Routine Inocation Example (with "while"
Loop):
with CS_IO ; use CS_IO ;
procedure EXAMPLE is
NUMBER : integer:= 1;
COUNTER : integer:= 0;
--------------------------------
function SQUARE (VALUE: integer)
return integer is
begin
return(VALUE*VALUE);
end SQUARE;
--------------------------------
begin
while (COUNTER < = 49) loop
COUNTER:= SQUARE(NUMBER);
put(COUNTER);
NUMBER:=NUMBER+1;
end loop;
new_line;
end EXAMPLE ;
|
C Routine Inocation Example (with "do while"
Loop):
void main(void)
{
int number = 1, counter;
do {
counter = square(number);
printf("%d ",counter);
number++;
} while (counter < = 49);
printf("\n");
}
int square(int value)
{
value = value*value;
return(value);
}
|
Return to imperative home page or
continue.
Created and maintained by
Frans Coenen.
Last updated 03 July 2001">