Procedúry a funkcie

Pri vytváraní programov mnohokrát prichádza k situácii, že program obsahuje niekoľko (dva alebo viac) výpočtov podľa rovnakého postupu len s rozdielnymi hodnotami alebo s rozdielnymi funkciami. Táto situácia by mohla byť riešená tak, že všetky príkazy výpočtov zopakujeme toľkokrát, koľkokrát je potrebné, bude to dobré, ale nešetrí to prácu programátora a program stráca na prehľadnosti. Elegantnejšie riešenie poskytuje PASCAL tým, že je možné používať procedúry a funkcie. Postup výpočtu preddefinujeme v procedúre, ktorú pomenujeme menom (na pomenovanie slúži identifikátor) a na potrebných miestach procedúru zavoláme, aby podľa nej prebehol výpočet. Aby bolo možné meniť aj hodnoty, s ktorými má výpočet prebehnúť, procedúra môže mať parametre, pomocou ktorých túto zmenu je možné uskutočniť.

Okrem tejto situácie procedúry a funkcie majú rozsiahle použitie pri návrhu veľkých programových systémov, na ktorých pracuje viacero programátorov. Pokiaľ si definujú, čo ktorá procedúra robí, aké má vstupné parametre a aké má výstupné parametre, každý programátor môže programovať samostatne a môže použiť vlastné metódy pri programovaní tela procedúry.

Procedúry a funkcie sú základom hierarchickej štruktúry programu. Hierarchická štruktúra programu úzko súvisí s postupným návrhom programu metódou zhora nadol. Táto metóda spočíva v opakovanom rozklade zložitejších problémov na menšie podproblémy pričom sa tiež prihliada na to, aby abstraktné príkazy (ktoré riešia zložitejšie problémy) boli postupne pretransformované na problémy menej abstraktné (ktoré riešia menšie podproblémy). Týmto spôsobom prechádzame od globálneho návrhu algoritmu riešenia daného problému postupným rozpracovávaním abstraktných príkazov až k zápisu algoritmu v programovacom jazyku. Abstraktné príkazy, o ktorých tu hovoríme, môžu byť zrealizované práve pomocou procedúr a funkcií.

Deklarácia a volanie procedúr

Deklarácie procedúr v pascalovskom programe musia byť uvedené pred ich prvým volaním, t.j. pred prvým výpočtom podľa nich.

Najjednoduchšia deklarácia procedúry sa skladá z hlavičky procedúry ukončenej bodkočiarkou a tela procedúry, za ktorým nasleduje bodkočiarka. Úplná deklarácia pomocou syntaktických diagramov je znázornená na obr. \ref{proc1}

Najprv sa budeme venovať najjednoduchšiemu tvaru procedúr a potom popíšeme použitie všetkých možných parametrov, ktoré sa vyskytujú pri deklarácii pomocou syntaktických diagramov.

Najjednoduchší tvar procedúry je nasledujúci:

procedure identifikátor (fp_1, fp_2, ..., fp_n);

blok;  

kde (fp_1, fp_2, ..., fp_n) je vlastne zoznam špecifikácií formálnych parametrov. Pretože telom procedúry je blok, je možné v procedúre použiť tiež deklarácie (premenných, konštánt, typov, procedúr a funkcií).

Príklad: Predpokladajme, že je definovaný typ BOD nasledovne:

type BOD = record X, Y: real; end;

Potom je možné vytvoriť nasledujúcu procedúru:

procedure priamka (B1, B2: BOD; var A, B, C: real);

{ Procedúra vypočíta koeficienty A, B, C rovnice priamky prechádzajúcej dvoma rôznymi bodmi B1, B2. V prípade chybného zadania bodov, t.j. ak sú body totožné procedúra vypíše o tom správu a všetky tri koeficienty A, B, C sa rovnajú 0.}

begin

if (B1.X=B2.X) and (B1.Y=B2.Y) then

begin

writeln(' Zadane body su totozne ');

A:=0; B:=0; C:=0;

end else

begin {Vypocet koeficientov priamky }

A:=B2.y-B1.y; B:=B1.X-B2.X;

C:=-A*B1.X-B*B1.Y

end

end; {priamka}

 

Postupnosť príkazov v tele procedúry je celkom zrozumiteľná, pretože je taká, ako v programe bez procedúr. Potrebujeme si ozrejmiť zadávanie formálnych parametrov pri deklarácii procedúry a ich nahradenie skutočnými parametrami pri volaní procedúry, t.j. pri spustení výpočtu podľa procedúry.

V príklade si všimnime, že špecifikácie formálnych parametrov sú oddelené bodkočiarkou. Vo všeobecnosti môže byť špecifikovaných viacej premenných toho istého typu (prípadne bez typu) sú oddelené čiarkami. Môže byť viacej špecifikácií formálnych parametrov, ktoré sú oddelené bodkočiarkami. Každá špecifikácia predstavuje skupinu parametrov (aspoň jedného) určitého druhu. Podľa druhu rozlišujeme

V našom príklade sú formálne parametre B1 a B2 typu BOD a sú to parametre volané hodnotou, parametre A, B, C sú typu real a zároveň sú to parametre volané menom. Procedúrové a funkcionálne parametre naša procedúra nemá.

Pre vyvolanie procedúry slúži príkaz procedúry, v ktorom za identifikátorom procedúry je uvedený zoznam skutočných parametrov. Jednotlivé skutočné parametre sú oddelené čiarkou a ich počet musí súhlasiť s počtom formálnych parametrov procedúry.

Každý skutočný parameter musí byť prípustným skutočným parametrom a substituuje sa do tela procedúry za odpovedajúci formálny parameter. Prípustnosť skutočného parametra a mechanizmus jeho substitúcie do tela procedúry sú dané špecifikáciou parametra v hlavičke procedúry.

Vysvetlenie direktív, ktoré sa vyskytujú v syntaktických diagramoch procedúr a funkcií:

  1. forward povoľuje riešiť situácie, keď je použitá vzájomná rekurzia dvoch alebo viacerých procedúr či funkcií. Vyjadruje, že podprogram bude dodefinovaný neskôr. Pri dodefinovaní už nie je nutné znova uviesť zoznam formálnych parametrov;
  2. external umožňuje väzbu so samostatne kompilovanými podprogramami, ktoré môžu byť zapísané aj v inom programovacom jazyku;
  3. inline povoľuje zapísať priamo inštrukcie strojového kódu namiesto tela procedúry;
  4. asm umožňuje zapísať do pascalovského programu sekvencie napísané v assembleri;
  5. interrupt sa používa pri tvorbe obslužných rutín prerušenia MS DOSu;
  6. far a near vyjadrujú vzdialené alebo blízke volanie procedúr alebo funkcií, čo súvisí s ukladaním adries volaných procedúr a funkcií do zásobníka.

 

Parametre volané hodnotou a menom

Formálny parameter vlastne predstavuje v procedúre údajový objekt určitého typu. Pri volaní procedúry dochádza k rôznym spôsobom spracovania týchto parametrov v závislosti od ich druhu. Spôsobom spracovania hovoríme tiež mechanizmy volania parametrov. Pascal nám poskytuje dva mechanizmy volania parametrov, a síce volanie hodnotou a volanie menom. Rozdiel medzi nimi spočíva v tom, že formálny parameter volaný hodnotou predstavuje v tele procedúry lokálnu premennú, ktorá má na začiatku vykonávania procedúry priradenú hodnotu, ktorú má skutočný parameter. Formálny parameter volaný menom predstavuje v tele procedúry vždy tú konkrétnu premennú, ktorá je určená skutočným parametrom a ktorej adresa umiestnenia v pamäti sa vypočíta na začiatku vykonávania procedúry.

Z popísaných rozdielov vyplýva najčastejšie používanie týchto parametrov, a síce

  1. pomocou parametrov volaných hodnotou reprezentujeme v procedúre jej vstupné hodnoty,
  2. pomocou parametrov volaných menom reprezentujeme v procedúre jej výstupné premenné, ktorých hodnoty budú po vykonaní procedúry definované.

 

Ako sme už spomínali, je možné v procedúre definovať tiež ďalšie premenné, konštanty, procedúry, atď. (v rámci bloku). Tieto deklarácie sú však lokálne, čo znamená, že po skončení výpočtu podľa procedúry sú už nedefinované a nemôžu byť použité.

Špecifikácia parametra volaného menom sa začína slovom var. Upozorňujeme, že var má platnosť len po bodkočiarku. Teda, ak chceme, aby ďalšia špecifikácia určovala parametre volané menom, je nutné uviesť var znovu. Prípustným skutočným parametrom je len premenná, ktorej typ je totožný s typom formálneho parametra. To znamená, že je prípustná aj premenná, ktorá je položkou v zázname alebo v poli atď. Vtedy nastáva hneď na začiatku vykonávania procedúry je vyhodnotená aktuálna adresa tejto premennej a s ňou sa pracuje.

Špecifikácia parametra volaného hodnotou nemá žiadne špeciálne slovo, obsahuje len identifikátory a typ. Prípustným skutočným parametrom pre parameter volaný hodnotou je ľubovoľný výraz, ktorého hodnota je kompatibilná vzhľadom na priradenie s typom formálneho parametra. Kompatibilita vzhľadom na priradenie je prednášaná pri typoch údajov. Bezpečnosť použitia zaručujú totožné typy. Totožné typy sú kompatibilné.

Deklarácia a volanie funkcií

Algoritmy, ktorých vykonaním je vypočítaná jediná hodnota určitého typu, môžu byť zapísané v programe ako funkcie. Deklarácia funkcie sa skladá z hlavičky funkcie ukončenej bodkočiarkou a tela funkcie, za ktorou nasleduje bodkočiarka. V hlavičke funkcie je definovaný identifikátor funkcie, sú uvedené špecifikácie formálnych parametrov a je tiež nutné uviesť aj typ vypočítanej hodnoty, čo vyjadruje typ funkcie. Syntaktické diagramy pre deklaráciu funkcie sú na obr. \ref{funkc1} Typ funkcie nesmie byť štruktúrovaný typ a musí byť označený identifikátorom typu. Telo funkcie tvorí blok. V tomto bloku musí byť obsiahnutý priraďovací príkaz, ktorý priradí hodnotu identifikátoru funkcie alebo vo vyšších verziách Pascalu do premennej Result a po vykonaní tohto príkazu je definovaná výsledná funkčná hodnota.

Vyvolanie funkcie sa určuje výrazom, ktorý nazývame zápis funkcie a ktorý má tvar

identifikátor funkcie (zoznam skutočných parametrov)

Prípustnosť skutočných parametrov, ich substitúcia za formálne parametre a spôsob vykonávania tela funkcie pri jej vyvolaní sa riadi rovnakými pravidlami ako pre procedúry. Treba však pripomenúť, že vyvolanie procedúry je príkaz avšak vyvolanie funkcie—zápis funkcie je výraz označujúci hodnotu, ktorá je výsledkom vykonania tela funkcie a musí byť použitý takým spôsobom ako sa používajú výrazy.

Príklad: Vytvorte funkciu, ktorej výsledkom bude hodnota určujúca obsah plochy ohraničenej priamkami: x=a, x=b, y=0, a funkciou y=f(x), pre ktorú platí f(x) >= 0, x in <a, b>. Na výpočet použiť obdĺžnikovú metódu, interval <a, b> deliť na n, n>1 dielikov, a, b, n a f sú parametre funkcie.

Predpokladajme, že máme definovaný nasledujúci typ funkcie:

type fun = function (x: real): real;

ktorý vyjadruje, že sa jedná funkciu s jedným argumentom, ktorý je typu real rovnako ako jej výsledok.

Funkcia, ktorú navrhneme by mohla mať nasledujúci tvar:

function obdl_prav(a, b: real; n: integer; f: fun): real;

var s: real; {priebezny sucet uz vypocitanych obdlznikov }

d: real; {dlzka dielika}

x: real; {priebezny argument}

i: integer; {riadiaca premenna cyklu }

begin

s:= 0;

d:= abs(b-a)/n;

if a<b then x:=a else x:=b;

for i:= 1 to n do begin

s:= s + d*f(x);

x:= x + d;

end;

obdl_prav:= s

end; {obdl_prav}

 

Procedúrové typy

Tieto typy sú rozšírením štandardnej definície jazyka Pascal. Ich zavedením sa zjednodušilo používanie procedúr a funkcií ako formálnych parametrov v definíciách iných procedúr a funkcií. Dôvodom pre zavedenie bola myšlienka zaviesť typ, ktorý umožní kontrolu parametrov, resp. typu funkcie.

Deklarácia procedúrového typu má syntax podobnú ako deklarácia procedúry alebo funkcie s tým rozdielom, že je vynechané meno (identifikátor) procedúry alebo funkcie.

Príklad:

type

Proc = procedure;

Sproc = procedure ( var X, Y: integer);

Strproc = procedure (s: string);

Mfun = function (X: real): integer;

 

Identifikátory, ktoré vystupujú na mieste formálnych parametrov, majú len pomocný charakter a nemajú vplyv na ostatné deklarácie. Ak je takýto typ deklarovaný je možné používať premenné tohto typu.

Príklad:

var

P: Sproc;

F: Mfun;

 

Premenné procedúrového typu majú veľkosť 4 byty a predstavujú vlastne adresu. Tieto premenné môžu byť použité na priradenie adresy namiesto mena procedúry alebo funkcie, pritom sú kontrolované počty a kompatibilita parametrov procedúr a funkcií a tiež typ výsledku u funkcií. Pri používaní týchto typov je potrebné dodržiavať nasledujúce pravidlá:

  1. na pravej strane priraďovacieho príkazu nesmie byť použité meno štandartnej procedúry alebo funkcie,
  2. procedúry a funkcie musia byť prekladané s direktívou prekladača {F+},
  3. deklarácia procedúry alebo funkcie musí byť uvedená na najvyššej úrovni, t.j. nesmie byť lokálna vzhľadom na ďalšiu procedúru alebo funkciu,
  4. nesmie to byť tzv. inline alebo interrupt procedúra alebo funkcia.

 

Príklad:

Predpokladajme, že máme vyššie uvedené deklarácie a deklaráciu nasledujúcej procedúry:

{$F+} {Nastaví vzdialené volanie}

procedure vymena( var A, B: integer);

var T: integer;

begin

T:= A; A:= B; B:= T

end; {vymena}

{$F-} {Zrusí vzdialene volanie}

 

Je povolená nasledujúca postupnosť príkazov:

P:= vymena; {Skontruje sa kompatibilita}

P(I, J); je rovnaké ako vymena(I, J);