Notes on Imperative programming languages, selection, and iteration

advertisement
Imperative Programming Languages
(your book performs examples in Pascal, I’ll show examples in Ada, and C,
An excellent site for learning Ada is: http://www.scism.sbu.ac.uk/law/lawhp.html)
Imperative programming languages are a family of languages where computations are
performed through a sequence of actions which manipulate the contents of variables
which represent values stored in memory. Imperative programming languages are also
frequently referred to as procedural programming languages.
Variables: Variables are “named” storage locations, which have a program defined
identifier associated with a “block” of storage somewhere in memory. Variables are
created via the process of “declaration” where an identifier (legal name in some
programming language) is associated with storage, the size of which is determined by the
variables “type”. As variables are used it may take on many different values throughout
the life of the program. Each time an assignment is performed, the pervious value of the
variable is lost.
int x;
Actions: are language statements that in some way use or manipulate the contents of a
variable. Expressions, Assignment, I/O, Function Calls
x = 10;
printf(“%d”, x);
The collection of identifiers and their associated values and the location of control in the
program constitute the “state” of the program. The state is a logical model of storage
which is an association between memory locations and values. A program in execution
generates a sequence of states. The transition from one state to the next is determined by
assignment operations and sequencing commands (alter the flow of control).
Programs are a sequence of individual actions which together perform some
computation. Unless carefully written an imperative program can only be understood in
terms of its execution behavior. IE: for the most part there are no restrictions on how a
programmer can write a program. The reason is that during the execution of the code,
any variable may be referenced, control may be transferred to any arbitrary point and any
variable binding may be changed (variables and a value is bound by an assignment).
Thus the whole program may need to be examined in order to understand even a small
portion of code.
When imperative programming is combined with subprograms it is called
procedural/structured programming. Structured programming is a style of programming
that emphasizes hierarchical program structures in which each command has one entry
point and one exit point. The goal of structured programming is to provide control
structures that make it easier to reason about imperative programs (subprograms,
conditional statements, and constructs for iteration.)
An program written in an imperative programming language is structured as a set of one
or more “subprograms”: Procedures or Functions:
Function is a type of subprogram which generates and returns a value to the calling
program.
A procedure only communicates with the calling program by the parameters passed to it.
The general format of a C program is:
<compiler directives>
<function prototypes>
int main ()
{
declarations
executable statements
>
<function implementations>
A C program consists of one or more functions one of which MUST be named main. C
only supports one type of subprogram and that is the function.
Execution of a C program is initiated with the function main.
There are many types of compiler directives, but to begin with we will just consider 2.
1) #include <.ksfk> refers to s system library header file,
2) #include “ “ refers to a user defined header file.
Header files give our programs access to pre-built resources such as the definitions of
constants, data types, and function prototypes. These resources are typically grouped by
type, based on similar purpose. Ie: stdio.h - io functions
The implementation of functions declared in the system header files are contained in the
C run-time library. The header file provides information about the resources to the
compiler and the linker causes the function bodies to be included in the program .
The C compiler pre-processor replaces the #include statement with the contents of the
appropriate header file
#include <stdio.h>
provides our program with access to the standard i/o functions
#include <math.h>
provides our program with access to the mathematical functions that constitute the
math library.
A second useful compiler directive is #define
#define name value
is a way to define constants in our program….. These are not variable constants….
#define MAXIMUM 100
---tradition is to use uppercase letters..
The preprocessor replaces the string “name” everywhere it appears in our program except
within comments with the literal string “value”. The compiler makes NO attempt at
verification, and the replacement could cause a compiler error.
In C all statements end with a semicolon ----------- ;
Comments begin with /* and end with */ and can continue across several lines…
Look at example 1
Variables & bindings:
Imperative programs are characterized by a sequence of “bindings” in which a name is
bound to a value at one point in the program and later bound to a different value. Most
descriptions of IPL’s are tied to hardware and implementation considerations where a
name is bound to an address, a variable to a storage cell and a value to a bit pattern. An
identifier is tied to three bindings, a binding to a location, a binding to a data type, and to
a value. The location is called the lvalue, and the value is called the rvalue.
X = X +1;
The x on the Left of the assignment denotes a location while the X on the right hand side
denotes a value. Assignment change the value at a location.
When a binding occurs varies: A programming language may have static or dynamic
bindings. A binding is static is it occurs before runtime, or dynamic if it occurs at run
time. Languages such as C and Ada, statically bind a data type to a variable at compile
type. An “lvalue” may be bound at compile time (rare), or a load time (for languages
with static allocation: C, Ada, Pascal) or at run time (for languages with dynamic
allocation. The “rvalue” associated with a variable may change many times during the
execution of a program, so the “rvalue” binding is dynamic.
Variable declarations are used to determine the amount of storage required by a program.
Forms:
C:
Ada:
Type name;
name: Type;
Every programming language has it’s own set of “data types” which define both the types
of values that can be stored in a variable, and the amount of storage that will be allocated
to the variable.
C:
Short, long, & int: integer types in the range 2-4 bytes
Int x = 10;
Float & Double: Floating point numbers, 4 & 8 bytes respectively
Float y = 4.5;
Char: Character variables, 1 byte
Char z = ‘a’;
Identifiers: a-z, A-Z, 0-9 and “_”. First character can not be a digit. Identifier length
can vary between operating systems and C compilers. Ansi C considers the first 31 only,
and disregards the remainder.
Ada:
Integer: Whole numbers
X : integer := 10;
Float: Real Numbers, and integer part , a decimal portion with a decimal point
in between.
Y: float := 10.50;
Boolean: True & False
flag: boolean := true;
String: Data consisting of one or more characters. letters, digits or special
symbols. It must have a defined length.
name: string (1..25) := “Camille Hayhurst”;
Character: single character.
C: char := ‘c’;
identifiers (names): (A-Z & a-z, 0-9), and underline, must begin with a letter. Not case
sensitive.
NOTE: integer, char, enumeration and Boolean data types are often referred to as
discrete types, because they have a predefined, limited set of values.
Note: Variables are different than named constants.. the value associated with a variable
can change throughout the program execution, while the value associated with a constant
can not:
In ada we define constants like variables, but use the KEYWORD “constant”. Constants
must be assigned an initial value when they are declared!!!.
Ada
PI: constant float := 3.1415;
C basically offers two types of constants:
C:
Const type identifier=initial value;
const int X = 12;
Defines a named constant, which is a variable whose value can not be changed. These
are treated as variables by the compiler, and allows the compiler to perform consistency
checking when a program is compiled.
#define identifier value
#define MAX 100
defines a “symbolic” constant, which is simply a literal string, that can be included in
header file. The preprocessor simply does a “blind” substitution of the value anywhere
that the “identifier” is encountered in the program text. This can cause compilation
errors.
Binding of values
The variable and a value is Bound by an assignment statement:
C:
Ada:
V = E;
V := E;
Where V is a variable name, and E is some expression. Either a constant or an
expression which yields some value. Assignment is what distinguishes imperative
programming languages from other programming languages, it is read “assign the name
V to the value of the expression E until the name V is reassigned to another value.
X := 3
X := X +1
There are many kinds of assignments:
X := X op E --- calculation
X=X+1
X := V
-- V is a literal value X = 3
“C”
X op= E
multiple assignment
X0:= X1:=X2:= E;
C is NOT a strongly typed language, which means we can have variables of different
types in the same expression. Ada IS a strongly typed language. We may not have
variables of differing types in the same expression, unless we explicitly perform a type
conversion.
In Ada:
X: integer =0;
Y: float := 3.4;
X := integer(Y) +1;
A type conversion is C is called “casting”. Where we basically coerce a value of one
type into another. X = (int) Y +1;
Flow of Control:
The order in which statements are executed is the “flow of Control” within a program.
The default “flow” of control is sequential, statements are executed one after the other in
the order in which they occur in the file.
Control Structures: Are syntactic structures that define the order in which executable
statements are performed. These are sequence control mechanisms and fall into 4
categories :sequential composition, alternation and iteration.
Sequential Composition: Sequential composition specifies a linear ordering for the
execution of commands. It is the default flow of control, where statements are executedc
one after the other in the order in which they occur in the file. It is usually indicated by
placing commands in textual sequence and a special symbol (ie: ;) is used as either a line
separator or line terminator the termination.
C & Ada: ; is a line terminator
Sequential composition is a sequence of two or more commands, it is the simplest form
of composition, and available in every imperative language:
s0;s1;s2
C: Hello World
#include "stdio.h"
int main (void)
{
printf ("HELLO WORLD\n");
return;
}
Ada: Hello World
with Text_Io;
procedure Hello is
begin
Text_Io.Put(“Hello World!!”);
Text_Io.New_line;
Text_io.Put(“I am Camille”);
end Hello;
Selection: (alternation): Selection permits the specification of alternate sequences of
actions (commands), where the selection of a particular sequence to execute is based on
the value of a logical expression. Examples of these statements are the if & case
(switch) constructs.
Alternation: may contain a number of alternative sequences of command from which
EXACTLY ONE is chose to be executed: if, nested if, and case.
Classic forms: of selection statements are: E represents a logical expression which
can be evaluated to true or false, and S, S1 & S2 represent sets of one or more
executable statements.
If E Then S1; If the logical expression E is true, then execute step S1,
other wise continue with the next executable statement
Decision Tree
for simple
If construct
true
E
S1
In C the basic if statement has the following format:
if (logical expression) statement;
A logical expression in C consists of a series of one or more conditional expression. A
conditional expression has the form:
Value1 relational-operator value2
Where value1 & value2 can be a variable name, a literal value, or the value returned from
a function call. In C, the execution of a conditional statement has a numeric value. A
value of 0 (zero) is defined as “false” and every thing else is considered as true!!!!
Relational operators: <, >, <=, >=, = = , != (left to right associatively)
Compound logical expressions contain a series of 2 or more conditional expressions,
joined with the logical and (&&), or the logical or (||) operators. The logical not (!)
negates (reverses) the initial value of an expression.
Truth table:
P
True
True
False
False
Q
True
False
True
False
P && Q
True
False
False
False
P || Q
True
True
True
False
!P
False
False
True
True
Sample expressions:
1<9
X==y
X > 0 && X < 10
Peculiarities:
int a = 5;
if ( a == 10) is false
if ( a = 10) is TRUE… Assignment is frequently incorrectly used in place of the equality
operator with is two equal signs. This assignment would assign the value of 10 to a, this
non zero value is interpreted as true!!!!!
Short circuit evaluation; The evaluation of multiple logical expressions ( with the &&
and ||), evaluation stops as soon as the truth of the expression is known:
P && Q if P is true then Q is evaluated. If P is false there is no need to evaluate Q.
P || Q if P is false then Q is evaluated. If P is true then there is no need to evaluate Q.
Ada
In Ada, the general format of the IF statement is:
if condition then statement (s) end if;
The relational operators are:
=, /=, <, <=, >, >=
The logical operators are: and, or, not
Short circuit evaluation of expressions is NOT performed, there are special “short circuit
operators”: and then, and the or else
Sample 1- C:, simple if with one executable statement.
#include <stdio.h>
int main(void)
{
int num;
printf ("enter a number: ");
scanf ("%d", &num);
if (num > 0)
printf("number is positive");
printf ("All done");
return;
}
with Text_Io;
package Int_io is new Text_io.Integer_io (num=>Integer);
procedure if_demo is
num: integer;
begin
Text_io.Put(“enter a number: ”);
text_io.new_line;
Int_io.Get(item=> num);
if (number > 0 ) then
Text_io.put(“number is positive”);
end if;
text_io.New_line;
Text_io.put(“All done”);
end if_demo;
The second general from of the IF statements is the “if then else” construct. Which
specifies a series of actions to perform if the expression is true, and an alternate
group of statements if the expression is false.
If E Then S1 Else S2;
False
true
E
S1
S2
If then Else example
C
#include <stdio.h>
int main (void)
{
int magic;
int guess;
int i;
magic = 1325;
printf ("Enter your guess: ");
scanf ("%d", &guess);
if (guess == magic)
printf (" You are RIGHT!!!");
else
printf ("... Sorry you are wrong..");
}
return;
}
Ada
with Text_Io;
package Int_io is new Text_io.Integer_io (num=>Integer);
procedure if_demo is
number, guess:
integer;
begin
number := 2;
Text_io.Put(“Guess a number between 1 and 10”);
text_io.new_line;
Int_io.Get(item=> guess);
if number = guess then
Text_io.put(“you guessed correctly good for you!”);
else
Text_io.put(“Sorry, you guessed wrong”);
end if;
end if_demo;
Multiple executable statements in an if clause:
C
#include <stdio.h>
int main (void)
{
int magic;
int guess;
int i;
magic = 1325;
printf ("Enter your guess: ");
scanf ("%d", &guess);
if (guess == magic)
{
printf (" You are RIGHT!!!");
printf (“the number was: %d, magic);
}
else
printf ("... Sorry you are wrong..");
}
return;
}
ada
with Text_Io;
package Int_io is new Text_io.Integer_io (num=>Integer);
procedure if_demo is
number, guess:
integer;
begin
number := 2;
Text_io.Put(“Guess a number between 1 and 10”);
text_io.new_line;
Int_io.Get(item=> guess);
if number = guess then
Text_io.put(“you guessed correctly good for you!”);
Text_io.put(“You are so smart!”);
else
Text_io.put(“Sorry, you guessed wrong”);
Text_io.put(“You big dummy!”);
end if;
end if_demo;
Nesting of If statements:
It is possible to include additional if-then-else constructs inside the set of executable
statements for an if statement. When this occurs this is called “nesting”, because one if
statement in contained inside another:
C
#include <stdio.h>
int main(void)
{
int a,b;
char ch;
printf ("Do you want to Add, Subtract, Multiply or
Divide?\n");
printf ("Please enter the first letter of what you would
like to do?");
ch = getchar();
printf ("Enter first number: ");
scanf ("%d", &a);
printf ("Enter second number: ");
scanf ("%d", &b);
if (ch == 'A')
printf ("Answer is %d", a+b);
else {
if (ch == 'S')
printf ("Answer is %d", a-b);
else {
if (ch == 'M')
printf ("Answer is %d", a*b);
else {
if (ch == 'D' && b!=0)
printf ("Answer is %d", a/b);
}
}
}
return;
}
Ada
with Text_io;
procedure nestedif is
package Int_io is new Text_Io.Integer_Io(Num=>Integer);
number1, number2, result: integer:=0;
operator: char;
begin
Text_io.put(“please enter 2 integer numbers: “);
Int_Io.Get(number1);
Int_Io.Get(number2);
Text_Io.new_line(2);
Text_Io.put(“Please enter an arithmetic operator”);
Text_Io.get(operator);
if operator = '*' then result := number1 * number2
elsif operator = '/' then result := number1 / number2
elsif operator = '+' then result := number1 + number2
elsif operator = '-' then result := number1 - number2
else Text_Io.put(“invalid operation”);
end if;
text_io.put(“the result is: “);
int_io.put(result);
text_io.new_line;
end nestedif;
Switch/Case statements can be used to simplify the logic of nested/multiple if statements
when only ONE execution path will be executed between all of the alternatives:
C:
#include <stdio.h>
int main(void)
{
int a,b;
char ch;
printf ("Do you want to Add, Subtract, Multiply or
Divide?\n");
printf ("Please enter the first letter of what you would
like to do?");
ch = getchar();
printf ("Enter first number: ");
scanf ("%d", &a);
printf ("Enter second number: ");
scanf ("%d", &b);
switch(ch)
{
case 'A':
printf ("Answer is
break;
case 'S':
printf ("Answer is
break;
case 'M':
printf ("Answer is
break;
case 'D':
if (b!=0)
printf ("Answer
break;
}
%d\n", a+b);
%d\n", a-b);
%d\n", a*b);
is %d\n", a/b);
Ada
with Text_io;
procedure nestedif is
package Int_io is new Text_Io.Integer_Io(Num=>Integer);
number1, number2, result: integer:=0;
operator: char;
begin
Text_io.put(“please enter 2 integer numbers: “);
Int_Io.Get(number1);
Int_Io.Get(number2);
Text_Io.new_line(2);
Text_Io.put(“Please enter an arithmetic operator”);
Text_Io.get(operator);
case operator is
when ‘+’ =>
result = number1+ number2;
when ‘-‘ =>
result = number1-number2;
when ‘* ‘=>
result = number1*umber2;
when ‘/ ‘=>
result = number1/number2;
when others =>
Text_Io.put(“invalid operation”);
end case;
text_io.put(“the result is: “);
int_io.put(result);
text_io.new_line;
end nestedif;
Iteration: Iteration specifies that a sequence of commands may be executed zero or
more times. At run time the sequence is repeatedly executed, the number of times the
repetition occurs is determined by a logical expression. Examples of these statements are
while, for, repeat, and loop.
“Definite Iteration “.
In a “definite” iteration the loop is executed a predetermined number of times. In
other words by the time control reaches the loop, the number of iterations is already
known. The classic construct for definite iteration is the classis “FOR” loop. These
type of loop constructs typically specify an index variable, and range of values
which the index variable will be assigned. The index is assigned the value of the
lower bound during the first iteration through the loop. Then the index variable is
incremented (or decremented) during each successive iteration, until the “upper
bound” is reached. In Ada, the “for” loop is a definite loop construct:
ADA
--For loops which increment the index variable by 1
for index in lower .. upper loop
statements in loop body
end loop;
-- for loops which “decrement” the index variable by -1
for index in reverse lower .. upper loop
statements
end loop;
EXAMPLE
For I in 1..10 loop
Int_Io.Put(I);
end loop;
Differences with Ada:
1) the Index variable “I” is automatically declared for you, and is a local variable inside
the loop.
2) It is ILLEGAL to change the value of the index variable inside the loop. I can appear
in the right hand side of expressions, but can not be assigned a value inside the loop.
3) After the loop terminates, the index variable ceases to exist.
Note the for loop in C is not a definite loop construct.
Indefinite Loop constructs:
An “indefinite” iteration is one for which the number of iterations through the loop is not
know when the control reaches the loop. The number of iterations is determined through
the computations performed inside the loop. The classic indefinite iteration construct is
the WHILE loop.
PRE-TEST LOOPS:
The classis while loop is also one type of “pre-test” loops. Pre-test loop are loop
constructs where the exit condition is checked at the BEGINNING of each iteration.
Therefore the body of a pre-test loop can be executed ZERO OR MORE times.
Ada While Loop:
while condition loop
statements;
end loop;
Example:
I := 10;
while (I <=100) loop
Int_IO.put(I);
I := I+10;
end loop
POST TEST LOOPS
A post-test loop construct checks the exit condition at the END of each iteration through
the loop. This means the body of the loop will ALWAYS be executed at least ONCE.
ada:
label:
loop
statements;
exit label when condition;
end label;
example: sum the numbers from 1 to 10
sum, I: integer;
I := 1;
Sum := 0;
Sumit:
Loop
Sum := sum +I;
I := I +1;
Exit sumit when I > 10;
End sumit;
NOTE: In ada the “loop” construct is a generic loop, the exit condition can appear
anywhere inside the body of the loop.
Abstraction: A sequence of commands that is named and the name is used to invoke the
sequence of commands causing them to be executed : functions, procedures,
subprograms
Download