Alamprogrammid. Protseduur ja funktsioon

Seni vaadeldud programmid olid kõik n.ö. ühes tükis, kogu programm moodustas ühtse terviku. Enamiku reaalsete, suuremate programmeerimisülesannete juures ei ole selline lahendus otstarbekas, mõnel juhul isegi on see võimatu - kogu programm ei mahu tervikuna arvuti mällu. Programmi liigendamine väiksemateks autonoomseteks osadeks:

 

muudab enamasti programmi ülevaatlikumaks - lihtsam on lugeda kümmet 20-realist kui üht 200-realist programmi

kergendab rühmatööd (eri inimesed võivad tegeleda eraldi alam-programmide loomisega, kooskõlastades vaid andmevahetuse)

lihtsustab programmi muutmist ja uuesti transleerimist jne.

Programmi liigendamise võimalusi on mitmeid. Vaatleme esialgu variante, kus programm asub endiselt ühes failis, kuid erinevad alamtegevused on jaotatud erinevate alamprogrammide vahel.
Alamprogrammide ja peaprogrammi vaheliseks andmevahetuseks kasutatakse parameetreid. 

Näiteks ringi pindala arvutava alamprogrammi sisendparameetriks (algandmeteks) on ringi raadius, väljundparameetriks (tulemuseks) aga pindala.

Pascalis kasutatakse kaht liiki alamprogramme - protseduure ja funktsioone.

Mõlemad deklareeritakse (sisuliselt kirjutatakse valmis) programmi alguses peale var- osa. Seega on alamprogramme sisaldava programmi struktuur järgmine:

program ...
type ...
var ....
<alamprogrammid>
begin
....
alamprogrammide väljakutsed
....
end.

Alamprogrammi üldstruktuur on sarnane "päris" programmi omaga, kuid lõpus on punkti asemel semikoolon

Protseduuri määratlemise süntaks: 

'PROCEDURE' <protseduuri_nimi> [ <formaalsed_parameetrid> ] ';'
[ <deklaratsioonid> ]
'BEGIN'
<lausete_jada>
'END' ';' .
protseduuri_nimi -> <identifikaator> .
formaalsed_parameetrid -> '(' <parameetri_deklaratsioonid> ')' .
deklaratsioonid -> <deklaratsioon> [ <deklaratsioonid> ] .
deklaratsioon -> <alamprogrammi_deklaratsioon> 
                        | <konstandi_deklaratsioon> | <tüübi_deklaratsioon>
                        | <muutuja_deklaratsioon> .
parameetri_deklaratsioonid ->
<parameetri_deklaratsioon> [ ';' <parameetri_deklaratsioonid> ] .
parameetri_deklaratsioon -> 
<sisendparameetri_deklaratsioon> | 
<sisend-väljundparameetri_deklaratsioon> .
sisendparameetri_deklaratsioon -> 
<identifikaatorite_jada> ':' <tüüp> .
sisend-väljundparameetrideklaratsioon -> 
'VAR' <identifikaatorite_jada> ':' <tüüp> .
identifikaatorite_jada -> 
<identifikaator> [ ',' <identifikaatorite_jada> ].

 

Näited: 

Procedure Vaheta( var a, b : Integer );
var c : Integer;
begin
c := a; a := b; b := c;
end;


üldiselt võib öelda, et sulgudes on var-i ees sisend- ja järel väljundparameetrid. Tegelikult aga on var-parameetrid kahesuunalised - võivad olla nii sisendiks kui väljundiks. Järgnev protseduurinäide kasutab sisendandmetena kaht täisarvu a ja b ning annab väljundiks (mida võib kasutada ka teine protseduur sisendina) nende arvude summa ja korrutise.

 

procedure SumKor (a,b : integer; var Summa, Korrutis : integer);
(* muutujaid juurde pole vaja, var-osa jääb ära *)
begin
Summa := a+b;
Korrutis := a * b;
end;

NB! protseduuri või funktsiooni sees var-iga deklareeritud muutujad kehtivad ainult selle alamprogrammi piires!!!

 

Funktsiooni kasutatakse siis, kui on vaja leida mingit ühtainsat väärtust. Funktsiooni töö tulemus omistatakse sisuliselt funktsiooni enda nimele, seega peab funktsioonil olema kindel tüüp

Funktsiooni määratluse süntaks: 

'FUNCTION' <funktsiooni_nimi> [ <formaalsed_parameetrid> ] 
':' <väärtuse_tüüp> ';'
[ <deklaratsioonid> ]
'BEGIN'
<lausete_jada>
'END' ';' .
väärtuse_tüüp -> <lihttüüp> | <viidatüüp> .

Näited: 

Function Max( a, b : Integer ) : Integer;
begin
If a > b then
Max := a
else
Max := b
end;

Järgnev funktsioon arvutab ringi pindala. Leitud väärtus omistatakse funktsiooni enda nimele (Pindala).

function Pindala (r : integer) : real;
begin
Pindala := 3.141492 * r * r ;
end;

Protseduuri väljakutsumise süntaks: 

<protseduuri_nimi> [ <tegelikud_parameetrid> ] ';' .
tegelikud_parameetrid -> '(' <parameetrite_jada> ')' .
parameetrite_jada -> <parameeter> [ ',' <parameetrite_jada> ] .
parameeter -> <sisendparameeter> | <sisend-väljundparameeter> .
sisendparameeter -> <avaldis> .
sisend-väljundparameeter -> <muutuja> .

Näited: 

Vaheta(k, l);

 

koos määratlusega:

program NäideP2;
var esimene, teine, S, K : integer;
procedure SumKor (a,b : integer; var Summa, Korrutis : integer);
(* muutujaid juurde pole vaja, var-osa jääb ära *)
begin
Summa := a+b;
Korrutis := a * b;
end;
begin (* programmi algus *)
...
SumKor(esimene, teine, S,K); (* SumKor-i väljakutse *)
writeln ('Summa oli ',S:3, ', korrutis oli ', K:3);
...
end.

Funktsiooni väljakusumise süntaks: 

<funktsiooni_nimi> [ <tegelikud_parameetrid> ] .

Näited: 

M := Max(i, j);

koos määratlusega:

program NäideF2;
var r1,r2 : integer;
S : real;
function Pindala (r : integer) : real;
begin
Pindala := 3.141492 * r * r ;
end; 

begin
.....
S := Pindala( r1 );  (* S saab väärtuseks funktsiooni Pindala töö *)
                                (* tulemuse, kusjuures raadiuseks on muutuja *)
                                (* r1 reaalne väärtus. *)
.......
writeln('Pindala on ', Pindala (r2) :3 ); (* Siin on Pindala nagu *)
                                                                (* tavaline arvmuutuja *)
end.

Programminäide 13. näite protseduuriga variant. 

program LeiaPindala;
(* Programm suudab arvutada ringi, täisnurkse kolmnurga või ruudu *) 
(* pindala. Kasutaja ülesandeks on valida kujund ning anda lähteandmed *)
(* Arvutuste tegemine toimub protseduuriga ArvutaPindala. *)
var kujund : char;
a,b,S : real;
procedure ArvutaPindala (MisAsi : char; var pind : real);
(* sisend - kujundi liik, väljund : selle kujundi pindala *)
begin
case kujund of
'r' : begin
write('Sisesta ringi raadius');
readln(a);
S := 3.14 * a * a;
end;
'k' : begin
write('sisesta kolmnurga kaatetid - a, b (tühikud vahele): ');
readln(a,b);
S := (a * b) / 2:
end;
'u': begin
write('sisestage ruudu küljepikkus: ');
readln(a);
S := a * a;
end;
end;
end; (* protseduuri lõpp *)
begin (* Ja peaprogramm on nii jupike ... *)
writeln('Leiame kujundi pindala');
write('Kas kujund on ring (r), täisnurkne kolmnurk(k) või ruut (u)? ');
readln(kujund);
ArvutaPindala(kujund, S);
writeln ('Pindala on ',S:6:2);
end. (* peaprogrammi lõpp *)

Programminäide 14. Protseduur kasutab funktsiooni.

program Maksimum;
var n : integer;
mas : array [1..10] of integer;
procedure Sisesta;
            (* n-i ja mas-i ei ole vaja parameetriteks panna, kuna need on deklaree- *)
            (* ritud sama programmi deklaratsioonideosas. See lahendus aga teeb *)
            (* meie protseduuri sõltuvaks konkreetsest programmist. *)
var i : integer; (* lokaalne muutuja, kehtib vaid protseduuris *)
begin
writeln('Mitu elementi on? ');
readln(n); 
for i := 1 to n do
begin
writeln('Sisesta ' , i , '. element: ');
readln(mas[ i ]);
end;
end; (* Protseduuri lõpp *);

function MaxEl(massiiv : array [1..10] of integer; arv : integer ) : integer;
            (* erinevalt eelmisest protseduurist on see funktsioon programmist *)
            (* sõltumatu - teda võib samal kujul kasutada ka teises programmis *)
var i,suurim : integer;
begin
suurim := 0;
for i := 1 to n do
if massiiv [ i ] >suurim then
suurim := massiiv [ i ];
MaxEl := suurim ; (* Lõpuks omistame leitud arvu f-ninimele *)
end;

procedure Väljasta;
var i, suurim : integer;
begin
writeln('Massiiv oli : ');
for i := 1 to n do
write (mas [ i ] : 6 );
writeln;
suurim := MaxEl (mas);
writeln(' Maksimaalne element oli ', suurim : 4 );
end;

NB! Kui üks alamprogramm kasutab teist, peab teine alamprogramm olema deklareeritud esimesest eespool.


PROOVIGE ISE:

1.
Kirjutage protseduur ja funktsioon (programmist sõltumatud), mis sisestavad tabeli (näit, 4 x 4) ja leiavad selle maksimaalse ja minimaalse elemendi.

2.
Sama mis 1, kuid kasutada järgmiseid alamprogramme:
protseduurid Sisesta ja Väljasta, funktsioon LeiaRuumala


Kodutööde ja arvestusülesannete väljatrükk peab
sisaldama kommentaaripäist programmi tegevuse eesmärgiga ning autori nime ja rühma.

N: program Silinder:
(* programm leiab silindri pindala ja ruumala *)
(* Autor: Aadu Kadakas AV-11 *)