Example

advertisement
procedure examples
This simple program sums a range of integer numbers. The user is requested to input an
integer number “N”, and then the program calculates the sum of the integers from one to
N, and stores the value in the variable “sum”
Ada “main” procedure, with definitions:
with Text_Io;
use Text_Io;
procedure Myprog is
package Int_Io is new Text_Io.Integer_Io(Num=>Integer);
use Int_Io;
Sum, N: Integer:=0;
begin
The declarative portion of
a procedure is the region
between the procedure
statement and the
keyword “begin”.
It is where “local”
variables, packages, and
nested procedures are
declared.
Put("please enter an integer value: ");
Get(N);
New_Line;
for I in 1..N loop
Sum:= Sum +I;
end loop;
Put ("the sum of the numbers from 1 to ");
Put(N,2);
Put(" is: ");
Put(Sum);
New_Line;
end Myprog;
The body of a procedure
is contained between the
keywords “begin” and
“end”.
Ideally there should be
only one exit point from
the body of a procedure.
Remember: in the for
loop in ada the index
variable (I in this
example) is automatically
declared for you, and does
not exist after the loop
exits.
C main function: to sum the numbers from 1 to N
#include <stdio.h>
int main(void)
{
int sum=0, n=0;
int i;
printf(“please enter an integer value: \n”);
scanf(“%d”, &n);
for ( i = 1; i <=n; i++)
{
sum = sum + i;
}
printf(“the sum of the numbers from 1 to %d is: %d\n”, n, sum);
}
For an example of a simple subprogram, we can move the portion of the program which
performs the calculation of sum into a separate subprogram, which I will call sumit.
Procedures and functions in ADA
In ADA, there are two choices for the implementation of sumit. Sumit can either be
implemented as a procedure or a function.
Sample Procedure
name
procedure Sumit(Sum: out Integer; N: in Integer) is
begin
body
sum:=0;
for I in 1..N loop
Sum:= Sum +I;
end loop;
end Sumit;
formal parameter list
Sample function
name
function Sumit(N: in Integer) return Integer is
Sum: Integer:=0;
begin
for I in 1..N loop
Sum:= Sum +I;
end loop;
return(Sum);
end sumit;
Result
type
Formal parameter list
Return the result
Formal parameters are variables declared in a procedure specification.
Actual parameters are variable names, expressions or literal associated with a formal
parameter name in a call to a procedure.
Formal parameter lists indicate for each formal parameter, the parameter name and
type. (in some languages such as ADA, we might also need to indicate how the actual
parameter value will be used);
parameter ame:
sum:
mode type;
out integer;
The mode for ADA is one of in, out or inout:



In: The value of the actual parameter is copied into the formal parameter when the
procedure is called. The value is transferred into the called procedure and is
essentially treated as a constant. The value of the parameter can not be changed and
the parameter can only appear on the right hand side of an assignment statement. IN
is the only parameter mode allowed in function specifications.
out: The value of the formal parameter is copied into the actual parameter after the
last statement in the procedure has been executed. The value is transferred out of the
called procedure. Out mode parameters can only appear on the left hand side of an
expression.
in out: The value of the actual parameter is copied into the formal parameter when
the procedure is called. After the last statement in the procedure has been executed,
the value of the formal parameter is copied back into the actual parameter. So two
different data transfers are done with an in out parameter. A value is transferred into
the procedure and a modified value is transferred out.
If a subprogram needs to return more than one value to the calling program then
you should use a procedure.
Sample use of sumit:
with Text_Io;
use Text_Io;
procedure Myprog is
package Int_Io is new Text_Io.Integer_Io(Num=>Integer);
use Int_Io;
Sum, N: Integer:=0;
procedure Sumit(Sum: out Integer; N: in Integer) is
begin
Sum:=0;
for I in 1..N loop
Sum:= Sum +I;
end loop;
Put("here is sum in sumit ");
Put(Sum);
end Sumit;
begin --begin for procedure myprog
Put("please enter an integer value: ");
Get(N);
New_Line;
Sumit(Sum, N);
Put ("the sum of the numbers from 1 to ");
Put(N,2);
Put(" is: ");
Put(Sum);
New_Line;
end Myprog;
NOTE, sumit is a
“nested” procedure since
it is wholly contained
inside the declarative
portion of procedure
myprog.
procedure call with actual parameters
sum & n.
The execution of the procedure body is
called an activation: An activation
causes an “activation” record to be
pushed on the stack: An activation
record contains:
the “return value” – point in the calling
program, and space for the local
variable and formal parameters
contained in the subprogram.
Sample output:
please enter an integer value: 5
the sum of the numbers from 1 to 5 is:
15
C implementation
#include <stdio.h>
int sumit ( int);
int main (void)
{
int sum=0, n=0;
Function Prototypes: A function prototype is basically a
declaration of a function . It names the function, indicates
the return type of the function, and the number and type of
formal parameters. In C, we do not need to include the
variable name of formal parameters, just their type. We can
however if we wish to. This could have been written as:
int sumit(int n);
printf(“please enter an integer value: \n”);
scanf(“%d”, &n);
sum = sumit(n);
printf(“the sum of the numbers from 1 to %d is: %d, n, sum);
}
int sumit( int n)
{
int i;
int result=0;
for (i=1; i <= n; i++) result = result + i;
return(result);
}
Separation of main programs and the subprograms they call
Subprograms can be included in the sample compilation unit (file) as the main program
or written/stored in a separately compiled source file.
C example
In C, function sumit can be stored in a separate file with the extension of .c, and the
prototype of function sumit can be placed in a user defined header file.
“main.c”
#include <stdio.h>
#include “sumit.h”
int main (void)
{
int sum=0, n=0;
printf(“please enter an integer value: \n”);
scanf(“%d”, &n);
sum = sumit(n);
printf(“the sum of the numbers from 1 to %d is: %d, n, sum);
}
“sumit.h”
int sumit(int);
“sumit.c”
int sumit( int n)
{
int i;
int result=0;
for (i=1; i <= n; i++) result = result + i;
return(result);
}
To compile the program, we would need to include BOTH source files in the gcc
command. Also, sumit.h would need to be in the same directory as the files.
gcc main.c sumit.c
Ada examples
In Ada, we have 2 choices for separately compiled subprograms. We can either declare
them as “separate” or we can put them into a package.
As in C, we can and should declare subprograms. (We will see later when discussing
scope rules, a variable/subprogram is not visible/known until it is declared.) A
subprogram declaration has the format:
procedure name (formal parameter list);
function name (formal parameter list) return type;
for example: using the previous example of sumit:
procedure Sumit(Sum: out Integer; N: in Integer);
In the previous example, we could declare function sumit as “separate” . Sumit is still a
child procedure of procedure myprog (logically nested inside it), but this allow us to take
the body of sumit, and place it in a physically separate source file. There are advantages
to doing this:

In improves the readability of procedure myprog. This is especially important if
nested subprograms are very long.
Example
File: myprog.adb
with Text_Io;
use Text_Io;
procedure Myprog is
package Int_Io is new Text_Io.Integer_Io(Num=>Integer);
use Int_Io;
Sum, N: Integer:=0;
procedure Sumit(Sum: out Integer; N: in Integer) is separate;
begin --begin for procedure myprog
Put("please enter an integer value: ");
Get(N);
New_Line;
Sumit(Sum, N);
Put ("the sum of the numbers from 1 to ");
Put(N,2);
Put(" is: ");
Put(Sum);
New_Line;
end Myprog;
file: sumit.adb
This names the parent procedure.
separate (myprog)
procedure Sumit(Sum: out Integer; N: in Integer) is
begin
Sum:=0;
for I in 1..N loop
Sum:= Sum +I;
end loop;
Put("here is sum in sumit ");
Put(Sum);
end Sumit;
To compile the program I could use: ada95 myprog.adb sumit.adb
Packages
Alternately, subprograms can be separated into packages. A package is similar to the
header file/source file construct in C. A package is composed of two separate files. A
“specification” file (with the extension .ads) which contains the definitions of user
defined data types, variables, constants, and subprograms that the package will make
available to the user. The package “body” contains the implementation of subprograms
declared in the specification. Optionally the package body may contain the declaration of
additional types/variables which are ONLY available to the subprograms contained in the
package.
Fraction Package
To illustrate packages, we will use a slightly more complex example which implements a
“fraction” data type, and provides some basic arithmetic operations on variables of those
types.
The “ads” file is equivalent to a “header” file in C. It contains type declarations, and
function/procedures specifications (prototypes). The “adb” file contains the actual
implementation of the bodies of the functions/procedures declared in the ads file.
Fraction_package.ads
package Fraction_Package is
type Fraction_Type is private;
The implementation of private types are
hidden from the users of the package.
The only way users of this package can
manipulate fractions is via the
operations provided by the package.
function Add( A: in Fraction_Type; B: Fraction_Type) return Fraction_Type;
procedure Set(A: out Fraction_Type; Numerator: in Integer; Denominator: in Integer);
procedure Print(A: in Fraction_Type);
private
type Fraction_type is
record
Numerator: Integer :=0;
Denominator : Integer :=0;
end record;
end Fraction_Package;
Actual declaration of type
Fraction_type.
Fraction_package.adb
with Text_Io;
use Text_Io;
with Ada.Integer_text_Io;
use Ada.Integer_text_Io;
package body Fraction_Package is
function Add(A: in Fraction_Type; B: in Fraction_Type) return Fraction_Type is
Result : Fraction_Type;
GCD : Integer;
begin
if (A.Denominator > B.Denominator) then
Gcd := A.Denominator;
else
Gcd := B.Denominator;
end if;
Result.Numerator := ((A.Numerator * B.Denominator) +
(B.Numerator * A.Denominator))/gcd;
Result.Denominator := (A.Denominator * B.Denominator)/gcd;
return Result;
end Add;
procedure Set(A: out Fraction_Type; Numerator: in Integer; Denominator: in Integer) is
begin
A.Numerator := Numerator;
A.Denominator := Denominator;
end Set;
procedure Print(A: in Fraction_Type) is
begin
Put("the fraction is: ");
Put(A.Numerator,3);
Put(" /");
Put(A.Denominator,3);
New_Line;
end Print;
end Fraction_Package;
Sample of using package fraction_package
with Text_Io;
use Text_Io;
with Ada.Integer_text_Io;
use Ada.Integer_text_Io;
with fraction_package;
use fraction package
procedure use_fractions is
A, B, C: fraction_type;
Begin
Put(“WE will initialize two fractions, A & B, add them and store the result in C”);
Set (a, 1, 2);
Set (b, 1, 4);
--set A to one-half
--set B to one-fourth
C := add (A, B);
Put(“the value of C is: ” );
Print(C);
End use_fractions;
Scope rules examples
Essentially, in any language a variable/subprogram is “known” or accessible only from
the point in which it is declared onward until the end of the construct in which it was
declared. Variables declared in the declarative portion of a subprogram or inside a block
({} in C, and Begin end in Ada) are LOCAL to that block or procedure. Which means
they can only be accessed inside that procedure/block and any procedures nested inside
the parent procedure. Global variables are declared outside the body of any procedure
and are accessible to ALL subprograms contained inside the compilation unit.
use Text_Io;
with Ada.Integer_Text_Io;
use Ada.Integer_Text_Io;
procedure Scope is
X: Integer :=89;
Y: Integer:=3;
procedure Ado(Z: in out Integer) is
X: integer;
begin
X:= 2341;
Y:= 654;
end Ado;
begin
Put("X in the main program is: ");
Put(X);
New_Line;
Put("Y in the main program is: ");
Put(y);
Variables declared inside a procedure are
local to that procedure and any subprograms
nested inside the BODY of the procedure. So
X and Y are visible to both procedure SCOPE
and procedure ADO.
However the formal parameter X in Ado,
supercedes the declaration of X in Scope. If a
local variable is declared which has the same
name as a global variable, or variable in the
parent procedure. The local declaration
supersedes the previously declared variable.
In this instance the local copy of X in Ado is
the one changed to 2341.
Typically the scope of a variable for nested
procedures is from the point which it is
declared until the end of the construct in
which it was declared
New_Line;
Ado(X);
Put("X after the call to ado is: ");
Put(X);
New_Line;
Put("Y after the call to ado is: ");
Put(y);
New_Line;
end Scope;
The programs output is:
X in the main program is:
Y in the main program is:
X after the call to ado is:
Y after the call to ado is:
89
3
89
654
C Scope Example
In C since we do not have the issue of nested procedures, all variables are either local to a
specific function or global
#include <stdio.h>
int x = 89;
int y = 3;
int main (void)
{
printf(“X in the main program is: %d\n”, x);
printf(“Y in the main program is: %d\n”, y);
ado(x);
printf(“X after the call to ado is: %d\n”, x);
printf(“Y after the call to ado is: %d\n”, y);
return;
}
int ado(int z)
{
int x;
x = 2341;
y = 654;
return
}
C pointer example:
#include <stdio.h>
int change(int *x);
int changevalue(int *y);
int main(void)
{
int *a, *b;
b = (int *) malloc(sizeof(int));
*b = 5;
printf("here is b before change: %d\n", *b);
change(b);
printf("here is b after change: %d\n", *b);
changevalue(b);
printf("here is b after changevalue: %d\n", *b);
return 0;
}/*main*/
int change(int *x)
{
x = (int *) malloc(sizeof(int));
*x = 12;
return 0;
}/*end change*/
int changevalue(int *y)
{
*y = 234;
return 0;
} /* end changevalue*/
The output of running this example is:
here is b before change: 5
Here is b after change: 5
here is b after changevalue: 234
Download