7. Vlastné procedúry, funkcie a jednotky

Procedúry

procedure NázovProcedúry(Parametre);
Definícia a deklarácia;
begin
Zložený príkaz;
end;

Definície a deklarácie sú rovnaké ako v bežnom programe, s výnimkou, že nesmieme používať uses. A nemali by sme definovať ani ďalšie procedúry a funkcie (stráca sa prehľadnosť, kvôli ktorej práve procedúry zavádzame). V programe potom používame nasledovné premenné:

– miestna deklarácia (v procedúre) – Ak potrebuje určitý dátový typ iba určitá procedúra, je lepšie ho definovať priamo v nej. Premenné sa potom vyskytujú iba v tele (medzi beginom a endom) procedúry a sú prístupné iba v nej samotnej.

– globálna deklarácia (v programe) – Premenná je potom dostupná aj v procedúre aj v programe.

Príklad na takúto deklaráciu:

Program Ukazka;
var z1,z2 :char; {Globálna deklarácia}
Procedure PrehodZnaky;
var pom : char; {Lokálna deklarácia}
begin
pom := z1;
z1:= z2;
z2 := pom;
end;
begin
Write('Zadaj dva znaky');
readln(z1,z2);
Writeln(z1,' ',z2);
Prehodznaky;
readln;
Writeln(z1,' ',z2);
readln;
end.

Funkcie

function Názov(Parametry):VýslednyTyp;
Deklarácie a definície
begin
Zložený príkaz;
end.

O funkciách platí všetko, čo bolo povedané o procedúrach. V tele samotnej funkcie sa ale musí použiť priradzovací príkaz NázovFunkcie:=NejakáHodnota; Pretože to je výsledok funkcie. Jeho hodnota sa už ďalej nesmie meniť. Pred i po priradení ale môžu prebiehať akékoľvek príkazy, ktoré s výsledkom funkcie nemajú nič spoločné.

Formálne a skutočné parametre

Program, ktorý využíva procedúry alebo funkcie, môže byť napísaný dvojako. Ukážeme si to na príklade: program Objem1; var polomer,vyska : real; function ObjemValca: real; begin ObjemValca:= pi*sqr(polomer)*vyska; end; begin Writeln('Zadaj polomer valca a vysku valca'); readln(polomer,vyska); Writeln(ObjemValca); end. alebo program Objem2; var polomer, vyska : real; function ObjemValca(Polomer,vyska : real) : real; begin objemValca := pi*sqr(polomer)*vyska; end; begin Writeln('Zadaj polomer a vysku valca'); readln(polomer, vyska); Writeln(objemValca(polomer,vyska)); Writeln(ObjemValca(polomer*2,vyska)); end. Druhý spôsob zápisu sa ukazuje ako jednoduchší, keď je potrebné použiť rovnakú procedúru pre rôzne poomery valca. V tomto prípade sa neprepisuje procedúra, prípadne sa nemusí prepočítavať premenná vopred, ale stačí uviesť správnu hodnotu premennej pri volaní procedúry. Parametre v mieste deklarácie funkcie označujeme ako predpísané (formálne) a v mieste volania funkcie ako skutočné parametre. Ich názvy a nemusia absolútne zhodovať.

Parametre nahradené hodnotou a odkazom

Ak rozlišujeme predpísané a skutočné parametre, musíme tiež rozlišovať medzi parametrami nahradenými hodnotou a nahradenými odkazom. Rozdiel si ukážeme na dvoch programoch, vrátime sa k prvému ukážkovému programu: Program Ukazka3; var z1,z2 :char; Procedure PrehodZnaky (x1,x2 : char); var pom : char; begin pom := x1; x1:= x2; x2 := pom; end; begin Write('Zadaj dva znaky'); readln(z1,z2); Writeln(z1,' ',z2); Prehodznaky; Writeln(z1,' ',z2); end. Pri prvom programe budú hodnoty prehodené vo vnútri procedúry, ale nebudú späť „exportované“ do nadradeného programu. Parameter, ktorý je nahradzovaný hodnotou sa chová ako miestny. Takže vo výpise hodnôt z1, z2 sa neukáže prehodenie poradia. Problém odstránime jednoducho, pri deklarácii procedúry napíšeme vyhradené slovo var: Program Ukazka4; var z1,z2 :char; Procedure PrehodZnaky (var x1,x2 : char); var pom : char; begin pom := z1; z1:= z2; z2 := pom; end; begin Write('Zadaj dva znaky'); readln(z1,z2); Writeln(z1,' ',z2); Prehodznaky; readln; Writeln(z1,' ',z2); readln; end. Takýto parameter nahradzovaný odkazom sa bude chovať inak. Parametre procedúry už predstavujú konkrétnu hodnotu, tú, ktorú sme uviedli v zozname skutočných parametrov. Zmena hodnoty uvedená vo vnútri procedúry bude platiť aj po navrate do hlavného programu. Pre tento typ nahradenia sa rozhodujeme vždy v týchto prípadoch: 1. Parameter nahradzovaný odkazom použijeme vždy pre každú výstupnú hodnotu. Aby výsledok výpočtu v procedúre bol „importovaný“ aj do nadriadeného programu. 2. Premenné dátového typu súbor musia byť vždy deklarované ako parametre nahradzované odkazom. 3. Pri práci s veľkými datovými štruktúrami využívame parametre nahradzované odkazom, pretože sú menej naročnejšie na pamäť.

Rekurzia a rekurzívne programy

Pri procedúrach a funkciách sa veľmi často sa používa rekurzia. Ide prípady, kedy funkcia alebo procedúra sa priamo alebo nepriamo (ak ide o cyklycký odkaz viacerých podrogramov) odkazuje sama na seba. Najprv ukážka funkcie, typickým príkladom sú faktorály: function Factorial(N:byte):longint; begin  if N >0 then Factorial:= N * Factorial(N-1) else Factorial:=1; end; Najdôležitejšie pri využívaní tohto algoritmu je nezabudnúť ukončiť cyklus! Problém ale nastáva, ak máme dve procedúry, z ktorých prvá využíva druhú a naopak, teda keď ide o nepriamu rekurziu. V Pascale sa totiž môže používať iba to, čo sme si dopredu zadefinovali. Ako to vyriešiť? Oznámime existenciu danej procedúry pomocou  procedure NázovA(parametre); forward; Potom dodefinujeme procedúru procedure NázovB (v ktorej používame NázovA). A nakoniec uvedieme samotné telo NázvuB (procedure NázovA; (tu už nemusíme vypisovať parametre...) Radšej si to ukážme na jednoduchom príklade: procedure NicNerobi(A:integer);forward; procedure NiecoRobi(A:integer); begin If A > 0 then NicNerobi(A-1); writeln(A); end; procedure NicNerobi; begin If A < 0 then NiecoRobi(A); writeln(A); end;

Procedúry bez lokálnych objektov a bez parametrov

- používajú len globálne objekty (zavedené v nadradenej časti), hovoríme aj, že komunikuje s okolım len pomocou globálnych premenných. Na mieste, kde chceme, aby došlo k vykonaniu príkazov uvedených v procedúre, stačí uviesť meno procedúry - hovoríme o tzv. volaní procedúry. Napríklad v príkazovej časti hlavného programu:

BEGIN
VSTUP;
VYMENA;
VYSTUP;
END.

Vidíme, že volanie procedúry je na úrovni príkazu (mena procedúr sme použili ako nami definované príkazy). Všetky použité premenné musia byť deklarované v úseku definícií a deklarácií hlavného programu. Ako v celom Pascale (až na malo výnimiek), aj pri podprogramoch platí, že každy objekt musí byť najprv definovaný alebo deklarovaný a až potom ho môžeme použiť.

procedure nazovprocedury;
begin
príkaz1;
príkaz2;
...
end;

Príklad:

procedure VSTUP;
begin
A := StrToInt ( InputBox (’Vstupď,’Zadaj prve cıslo: ’,’1’));
B := StrToInt ( InputBox (’Vstupď,’Zadaj druhe cıslo: ’,’2’);
end;
procedure VYMENA;
begin
POM := A; A := B; B := POM
end;

procedure VYSTUP;
begin
Label1.Caption := IntToStr (A) + ´ ´ + IntToStr (B)
end;

Procedúry s lokálnymi objektami a bez parametrov

Keď sa pozrieme na procedúru VYMENA, ľahko zistíme, že premennú POM potrebujeme len počas vykonavania tejto procedúry. Takýchto objektov môže byť viacej a nie je dôvod zaťažiť pamäť počítača počas behu celého programu vyhradením pamäťových miest objektom, ktoré používame len lokálne. Preto takéto objekty stačí definovať a deklarovať len v danej procedúre, hovoríme, že sú lokálne, čo znamená, že sú použiteľné len v danej procedúre (alebo v podriadených procedúrach).

Deklarácia procedúry slokálnymi objektami má tvar:

procedure mp;
usek definícií a deklarácií
blok
príkazová časť

kde mp je meno procedury.

Pamäťovo efektívnejšíı zápis procedúry VYMENA (s lokalnou premennou POM):

procedure VYMENA;
var POM : integer;
begin
POM := A; A := B; B := POM
end;

Volanie procedúry s lokálnymi objektami je rovnaké ako procedúry bez lokálnych objektov. Procedúra naďalej komunikuje s okolím len cez globálne premenné . Ak použ ijeme rovnaké pomenovanie pre lokálnu aj globálnu premennú, dôjde k tzv. zatieneniu globálnej premennej lokálnou premennou v danej procedure, čo znamená, že daná globálna premenná je nepoužiteľna v danej procedúre.