Kétféle alprogramot különböztetünk meg. Léteznek eljárások és függvények. A kettő közötti különbség az, hogy a függvénynek van
visszatérési értéke az eljárásnak nincs. De mik is ezek valójában? Tegyük fel van egy programrész amit több helyen is fel
szeretnénk használni. Akkor nem kell mindenhova bemásolni, hanem elég egyszer megírni és hivatkozni rá. Sőt még változókat is
lehet átadni neki. Az alprogramokat a főprogram előtt kell deklarálni. Lássuk akkor először az eljárásokat.
Eljárás: Nem ad vissza semmilyen értéket, de természetesen lehet átadni neki paraméterben változókat.
Az eljárás neve és paraméterlistája alkotja a fejét. Az eljárás törzse lesz az a rész ahova kódot írnuk és ez fog végrehajtódni,
amikor meghívjuk az eljárást. Nézzünk rá egy példát:
Program eljaras;
Uses crt;
{ Itt kezdődik az eljárás }
Procedure kiir_zold(szoveg : string; X,Y : integer); { Az eljárás feje. }
Begin
TextColor(green);
GoToXY(X,Y);
Write(szoveg);
End;
{ Itt ér véget az eljárás. }
BEGIN
ClrScr;
{ Itt használom fel az eljárásomat a programban. }
kiir_zold('Hello Vilag!', 40, 5);
{ Itt mégegyszer megívom, csak más paraméterekkel. }
kiir_zold('Ezt a programot HUNIgor készítette.', 2, 20);
ReadKey;
END.
Lássuk mi is történt. A procedure kulcsszót követően meg kell adni a nevét. Ezután zárójelben a formális paraméter listát.
Mitől lesz formális? Mivel konkrét értéket nem tartalmaz, csak jelezzük szándékunkat, hogy amikor meghívjuk majd az eljárást
akkor ilyen típusú és ennyi darab változót szeretnénk neki átadni, valamint, hogy az eljáráson belül ilyen néven fogom hívni.
Amilyen sorrendben adtam meg a változókat itt, olyan sorrendben kell majd megadni az aktuális paramétereket is amikor meghívom
az eljárást. Az aktuális paraméter tehát az amikor az eljárást felhasználom valahol (a továbbiakban meghívom) és a neve után
zárójelben megadom neki a konkrét értéket. A fenti példában ez a: ('Hello Vilag!', 40, 5). Sajnos eleinte könnyű keverni ezt a
két fogalmat. De jusson eszünkbe, hogy a formális az nem konkrét, tehát csak név + típus. Az aktuális pedig konkrét érték, ami
azért aktuális mert az eljárást több helyen is meghívhatom és így hívásonként más-más értékeket is megadhatok. Tehát mégegyszer
a formális paraméter az eljárás deklarciójában található, míg az aktuális paraméter az eljárás meghívásánál.
Természetes igény lehet, hogy egy alprogramon belül nem csak azokat a változókat használjuk amik szerepelnek a paraméterei
között. Lehet létrehozni változót az alprogramon belül is.
Procedure kiir_random_szin(szoveg : string; X,Y : integer); { Az eljárás feje. }
var szin : integer;
Begin
szin := Random(6);
TextColor(szin);
GoToXY(X,Y);
Write(szoveg);
End;
Itt most véletlen számot adunk meg színnek. Volt szó korábban arról, hogy nem csak a színek angol neveit lehet használni, hanem
számokat is. Tehát szin változót az eljáráson belül hoztuk létre. Ez felvet egy nagyon fontos kérdést. Hol használhatjuk a szin
változót? Használhatunk-e egy olyan változót amit nem az eljáráson belül hoztunk létre? Ezt hívják láthatósági problémának.
Lássuk a megoldását!
A Pascalban létezik globális változó. Ezek azok, amikkel korábban találkoztunk. Ezeket a változókat bárki elérheti,
akár eljárás, akár függvény, akár maga a főprogram. Ettől lesz globális. Szeretném azonban hangsúlyozni, hogy egy alprogramban
nem szép globális változókat használni. Nagyobb programoknál hatalmas káoszt tud okozni, ha rászokunk erre. Így törekedjen
mindenki a lehető legkevesebbszer ilyenhez folyamodni. Az alprogramoknak lehet lokális változója is. A
példánkban a szin is ilyen. Ezt a változót csakis az alprogramon belül érjük el. Tehát szin felhasználása a főprogramban vagy
más alprogramokban nem lehetséges. Vagy mégis? Mi a helyzet akkor ha egy alprogramon belül létrrehozok még egy alprogramot?
Mondjuk így:
Program eljaras;
Uses crt;
{ Ennek ugyan az a neve mint az alprogramban található változónak. }
var szin : integer;
Procedure kiir(szoveg : string; X,Y : integer);
var szin: integer; { Két változó ugyanazzal a névvel? }
Procedure setup_color; { Ez itt egy eljárás az eljáráson belül. }
var i : integer; { Neki is van egy változója. }
Begin
i := Random(6) + 1;
szin := i;
textColor(szin);
End;
Begin
setup_color;
GoToXY(X,Y);
Write(szoveg);
End;
BEGIN
Randomize;
ClrScr;
szin := 0;
kiir('Hello Vilag!', 40, 5);
writeln;
writeln(szin);
ReadKey;
END.
Remélem a példa megfelelően illusztrálja a helyzet komolyságát. Van két szín nevű változónk. Ráadásul az eljárásunkon belül is
lett egy eljárás aminek szintén van egy változója és használja szin változót. Na de melyiket? Mindenki megnyugtatására az
alprogramon belül létrehozott szin változó elfedi a főprogramban létrehozottat. Így amikor az alprogramon belül írunk olyat,
hogy szin akkor az eljáráson belül létrehozottat használja. Ha a főprogramban írunk olyat, hogy szin akkor a globálisat
használja. A setup_color a kiir eljáráson belül van. Így számára (mármint a setup_color számra) a szin változó globális.
Hogy érthetőbb legyen nézzük meg az alábbi táblázatot.
Főprogram
var szin, x: integer;
procedure a
var szin: integer;
procedure b
var i: integer;
begin
i := { Megengedett, hiszen
ebben az eljárásban hoztam létre. }
szin := { procedure a -ban
létrehozott változó elfedi a globálisat. }
x := { mivel x globális és nincs semmi ami
elfedi így globális x kapna itt értéket. }
end;
|
begin
i := { HIBA!! i itt még nem "él",
ezért fordítási hibát eredményez. }
szin := { Az itt létrehozott szin
változó, NEM a globális. }
x := { mivel x globális és nincs semmi ami elfedi
így globális x kapna itt értéket. }
end;
|
BEGIN
i := { HIBA!! i itt még nem "él", ezért fordítási hibát eredményez. }
szin := { Itt globális színt haszálja, mivel a procedure a -ban
létrehozott el van rejtve. }
x := { mivel x globális és nincs semmi ami elfedi így globális x
kapna itt értéket. }
END.
|
Függvény: Abban különbözik az eljárástól, hogy van visszatérési értéke. A függvény
célja tehát, hogy a kapott paraméter(ek) alapján előállítson egy értéket. Vegyük például az abszolút érték
kiszámítását. Ugyan a Pascal tartalmazza ezt és felesleges megírni (lásd: Pascal help -> index -> Abs) de
példának jó lesz. Egy szám abszolút értéke önnmaga, ha a szám nemnegatív és ellentettje, ha negatív. A
függvénytől elvárjuk, hogy a kapott változó abszolút értékét előállítsa és visszaadja azt. Nézzük az alábbi kódot!
Function abszolut_ertek(szam : integer) : Integer;
Begin
If (szam>=0) Then
begin
abszolut_ertek := szam;
end
Else
begin
abszolut_ertek := (-1) * szam;
end;
End;
BEGIN { Főprogram }
eredmeny := abszolut_ertek(l); { Itt használjuk a függvényünket. }
WriteLn(abszolut_ertek(-17); { Itt is. }
abszolut_ertek(77); { Szabályos, de nem sok értelme van. }
END.
Az első sor a függvény feje. Procedure kulcsszó helyett function van. Majd a függvény neve, zárójelben a függvény
formális paraméterlistája. Eddig semmi különös. A fő különbség a zárójel utáni rész. Kettőspont után jelezzük
függvényünk visszatérési értékének a típusát. A függvényekben ugynúgy hozhatunk létre változókat, sőt másik
függvényt is, sőt eljárást is, de akár eljárásban is hozhatunk létre függvényt. A változók láthatóságára ugyanaz
érvényes mint az eljárások esetében.
Felhasználásuk különbözősége az eljárásokéhoz képest abból ered, hogy van visszatérési értéke, amit az esetek
többségében használunk is valamire. Ezért szerepelnek legtöbbször értékadás jobb oldalán, esetleg write
paraméterében. Meghívhatjuk ugyan úgy is mint az eljárást, nemtörődve a visszatérési értékével. Egy függvény
esetében azonban ez ritka, hiszen pont azért készítünk belőle függvényt, mert kell a visszatérési értéke.
Ennyit az alprogramokról. Ha bármi nem volt világos, vagy kimaradt, akkor írjátok meg a vendégkönyvbe. Ha túlságosan
is érthető és (már fárasztóan) szájbarágós akkor azt is.
Következő lecke még ettől is izgalmasabb lesz, úgyhogy most már senki se kapcsoljon el, a mindent magába szívó
tisztasági betét és inteligens mosópor után jövünk vissza!