kategória | ||||||||||
|
||||||||||
|
||
Eljárások, függvények. Érték- és címszerinti paraméterátadás, lokális és globális változók. Rekurzivitás.
A programok írása során gyakran találkozunk olyan feladatokkal, amelyek a
programban többször megismétlõdnek, amelyeket többször végre kell
hajtani. Az ilyen problémák esetén kétféle módszer közül választhatunk:
Monolitikus programozás:
A program egyetlen blokkból épül fel, ez a blokk tartalmaz minden utasítást,
amelyet a program során végre kell hajtani. Ennél a módszernél a többször
végrehajtásra kerülõ utasítassorozatot minden egyes alakalommal újra le
kell írni. Hátránya, hogy a program forráskódja nagyon nagy méretû lehet,
illetve a módosítás nehézkessé válik.
Moduláris programozás:
Az ismétlõdõ tevékenységeket alprogramként írjuk le, így amikor
szükségünk van rá, egyszerûen hivatkozunk az alprogramra. Ennek a
módszernek nagy elõnye, hogy mivel csak egyszer írjuk le az
ismétlõdõ programrészeket, a forráskód áttekinthetõvé
válik, a késõbbi módosításkor pedig csak az alprogramot kell módosítani,
amikor hivatkozunk rá, akkor az elõzõekben módosított tevékenység
kerül végrehajtásra.
A Turbo Pascal nyelv támogatja mind a monolitikus, mind a moduláris programozási módszert. Elsõsorban nagy méretû programok, komplex feladatok esetében célszerû a moduláris technikát választani, kismértetû programoknál feleslegesen bonyolítaná a forráskódot.
A Pascal nyelv nagyon sok beépített eljárást
és függvényt tartalmaz, az 757j95h utasításkészlete viszonylag kicsi. A beépített
eljárások, függvények már a legegyszerûbb programokban is felhasználásra
kerülnek. Ilyen például a Writeln eljárás, vagy a Sin függvény. Már ezek
használata során is látható az eljárások és függvények közötti különbség. A
függvények egy értéket adnak vissza a meghívás után, Pld: X:= Sin(Alfa); az
eljárások pedig valamilyen tevékenységet hajtanak végre.
A beépített függvények, eljárások mellett a Pascal támogatja a programozó által
készített függvények, eljárások használatát is.
Eljárások:
Egy-egy jól körülhatárolt részfeladat
megoldásához készült programrészleteket eljárásoknak nevezzük.
Az eljárásokat (és a függvényeket is) a fõprogram blokkja elõtt,
a deklarációs részben kell szerepeltetni. Az eljárások általános felépítése:
Procedure Eljárásnév(formális_paraméterek);
Label ...;
Const ...;
Type ...;
Var ...;
Begin
...
End;
Az eljárások felépítése hasonlít egy Pascal program felépítéséhez, eltérés csak az eljárás fejrészében és az eljárást lezáró End szónál tapasztalható. Az eljárásfejet a procedure foglalt szó vezeti be, azt követi az eljárás neve, amelynek segítségével az eljárásra késõbb hivatkozni tudunk. Az eljárás neve után zárójelek között szerepelnek az eljárás által használt paraméterek. A paraméterek segítségével tudunk az eljárásnak értékeket átadni az eljárás hívása során. Az eljárásnak átadott paraméterek típusa csak külön névvel rendelkezõ típus lehet, típusleírást itt nem adhatunk meg (pld: nem szerepelhet: Array [1..5] of Byte). Az eljárásfejet a lokális deklarációk követik. Az eljárások (függvények) használhatnak belsõ változókat, amelyeket csak az eljárás törzsén belül lehet felhasználni. Ezek az ún. lokális változók. A lokális változók elérhetõsége az alprogram törzsére korlátozódik, élettartamuk az eljárás futásától az eljárás befejezéséig tart. (Tehát a változóknak a fordító az alprogram hívásakor foglalja le a helyet a memóriában, és az alprogram befejezésekor ezeket a memóriaterületeket felszabadítja.) Az alprogramokban deklarált lokális változók a Stack nevû memóriarészben kapnak helyet.
A fentiekben vázlatosan összefoglaltuk az alprogramok általános jellemzõit. A általános bemutatás során megpróbáltam az alprogramok összes tulajdonságát összegyûjteni, és minden lehetõséget megemlíteni. Nézzük meg néhány konkrét példán keresztül, hogyan készíthetünk saját alprogramokat.
Az alprogramok legegyszerûbb változatai a paraméter nélküli eljárások. Ezek az eljárások mindig ugyanazt a tevékenységet hajtják végre. Lássunk egy egyszerû példát:
Uses CRT;
Procedure Elvalaszt;
Var I: Integer;
Begin
For I:= 1 to 80 do
Writeln('-');
End;
Begin
ClrScr;
Elvalaszt;
Writeln('Sajat keszitesu eljaras hasznalata');
Elvalaszt;
Repeat Until Keypressed;
End.
Az Elvalaszt nevu eljaras mindig ugyanazt a
tevékenységet hajtja végre, a képernyõ teljes szélességében megrajzol
egy szaggatott vonalat. Az eljárás tevékenysége során használja az I változót,
amelyet lokális változóként deklaráltunk.
Az alprogramok további lehetõségeket
biztosítanak, ha kihasználjuk az alprogramok paraméterezhetõségét. A
paraméterek segítségével univerzális alprogramokat készíthetünk,
testreszabhatjuk az alprogramunk mûködését az átadott értékek
segítségével. Nézzünk egy példát:
Írjunk eljárást, amely kiírja a képernyõre két szám összegét.
Uses CRT;
Procedure Osszead(A, B: Integer);
Begin
Writeln('A ket szam osszege: ', A+B);
End;
Var X, Y: Integer;
Begin
ClrScr;
Write('Az elso szam: '); Readln(X);
Write('A masodik szam: '); Readln(Y);
Osszead(X, Y);
Osszead(12, 5);
Repeat Until Keypressed;
End.
A példában látható, hogy a paraméterezett alprogram fejrészében már szerepel a paraméterek felsorolása - tipussal együtt. Ez az ún. formális paraméterlista, amely az eljárás deklarációja során meghatározza, hogy a késõbbi híváskor hány és milyen típusú paramétert kell átadni az eljárásnak. A formális paraméterlistában szereplõ paraméterek azonosítója az eljárás törzsében változóként használható fel. Ha azonban a paraméterlistában egy változó nevét adtuk meg, és annak értékét az alprogram módosítja, a fõprogramba visszatérve a változó értéke változatlan marad. (Legalábbis az érték szerinti paraméterátadás esetén, merthogy ez az volna.) Az eljárás meghívása során az ún. aktuális paraméterlistában már konkrét értékeknek kell szerepelni, változó vagy konstans formájában. Ha az aktuális paraméter változó, akkor annak csak az értéke érdekes az alprogram számára.
Amennyiben a paraméterként megadott változók
értékét úgy szeretnénk módosítani az eljáráson belül, hogy a változás
megmaradjon a fõprogramba visszatérve is, akkor a paraméterátadás egy
másik módját kell választani, a cím szerinti paraméterátadást. A cím szerinti
paraméterátadás során az alprogramnak nem a változó értékét, hanem a változó
memóriabeli címét adjuk át (erre utal az elnevezés is). Tehát ha azt
szeretnénk, hogy az eljárásunk egy változó értékét megváltoztassa, akkor ezt a
paraméterátadási módot kell választani. Nagyon jó példa erre a beépített Inc és
Dec eljárás, amelyek a megadott változó értékét növelik, illetve csökkentik.
Figyelni kell arra, hogy cím szerinti paraméterátadást alkalmazva az eljárás
hívásakor az aktuális paraméterlistában csak változóneveket adhatunk meg, mivel
ezek címe kerül átadásra. Amennyiben konstans paramétereket adunk meg (Rossz
példa: Inc(10); ) a program fordításakor hibaüzentetet kapunk. Ha az eljárásnak
cím szerint szeretnénk a paramétereket átadni, a paraméterek neve elõtt
szerepeltetni kell a Var kulcsszót (foglalt szót).
Példa: Írjunk eljárást, amely egy stringet nagybetûssé alakít!
Uses CRT;
Procedure Konvert(var S: String);
Var I: Byte;
Begin
For I:= 1 to Length(S) do
S[I]:= UpCase(S[I]);
End;
Var Szov: String;
Begin
ClrScr;
Write('Kerek egy szoveget: ');
Readln(Szov);
Konvert(Szov);
Writeln(Szov);
Repeat Until Keypressed;
End.
Cím szerinti paraméterátadás esetén változók
nevét kell szerepeltetnük az aktuális paraméterek listájában. Egyetlen kivétel
a típusos konstans, amelyet még megenged a Turbo Pascal rendszer, mivel ennek
értéke a program futása során megváltozhat. (A típusos konstansokat
bõvebben lásd a 3. tételben!)
A kétféle paraméterátadási forma vegyesen is használaható, ekkor a formális
paraméterek felsorolásakor figyelni kell arra, hogy melyik paramétert hogyan
szeretnénk átadni. A paraméterlistában különbözõ tipusú paramétereket is
megadhatunk, a különbözõ tipusú paramétereket egymástól
pontosvesszõvel választjuk el.
Pld: Procedure Proba(A, B: Integer; S: String; var Log: Boolean);
Az alprogramok készítése során célszerû szem elõtt tartani, hogy az alprogramok csak egy-egy részfeladatot oldanak meg, de azt a lehetõ legjobban. Ezért célszerû a paraméterek rendszerét és az alprogram által végzett tevékenységet úgy kialakítani, hogy az esetleg egy másik program írása során is felhasználható, általános érvényû legyen.
Az eljárások általános ismertetésénél szó volt
róla, hogy az eljárások paraméterei csak olyan típusú adatok lehetnek, amelyek
elõre definiált névvel rendelkeznek. Azt azonban nem korlátozza a nyelv,
hogy a típus beépített vagy a felhasználó által definiált típus-e. Tehát ha az
alprogramoknak paraméterként egy összetett típusú változót szeretnénk átadni,
akkor ehhez elõször a típusdeklarációs részben kell meghatározni ennek a
típusnak a leírását.
Példa: Írjunk eljárást, amely kiszámítja egy 10 elemû (Byte) tömb
elemeinek összegét. Az eljárás elsõ paramétere a tömb, a második
paramétere egy változó legyen, amelyben visszaadja a tömb elemeinek összegét.
Uses CRT;
Type TTomb= Array [1..10] of Byte;
Procedure TOsszeg(T: TTomb; var Sum: Word);
Var I: Integer;
Begin
Sum:= 0;
For I:= 1 to 10 do
Sum:= Sum+T[I];
End;
Var V: TTomb;
N: Byte;
O: Word;
Begin
Randomize;
For N:= 1 to 10 do
Begin
V[N]:=
Random(255);
Writeln('A
tomb ', N, ', . eleme: ', V[N]);
End;
Writeln;
Writeln;
TOsszeg(V, O);
Writeln('A tomb elemeinek osszege: ', O);
Repeat Until Keypressed;
End.
Függvények:
Nagyon sokszor van szükségünk olyan alprogramokra,
amelyek egy számítást végeznek el, egy eredményt adnak vissza. Az
elõzõ példák között is szerepeltek már ilyenek. A probléma
megoldható eljárások segítségével is, ahogy azt fentebb láthattuk, szükség van
egy cím szerint átadott paraméterre, amelyben az eredményt elhelyezhetjük. Van
azonban egy ennél elegánsabb megoldás is a fenti problémára, a függvények
definiálása.
A függvény olyan alprogram, amely a hívás és végrehajtás után egy értékkel tér
vissza a hívás helyére. Ezt az értéket visszatérési értéknek nevezzük.
A függvény jellegû alprogramokat a változókhoz hasonló módon
használhatjuk, állhatnak egy értékadási mûvelet jobb oldalán, egy
kifejezésben, de meghívhatjuk õket az eljárásokhoz hasonló módon is -
más kérdés, hogy ilyenkor a függvény által szolgáltatott érték elvész. A Pascal
nyelv beépített függvényei (Sin, Cos, Keypressed, ReadKey, Abs, Ord, Chr, stb.)
mellett magunk is írhatunk ilyen jellegû alprogramokat. Általában nem
nehéz eldönteni, hogy egy részfeladat megoldása során eljárást vagy függvényt
alkalmazzunk-e.
A függvények felépítése alig különbözik az eljárások felépítésétõl:
Function Fgvnev(formális_paraméterek): FTipus;
Label ...;
Const ...;
Type ...;
Var ...;
Begin
...
Fgvnev:= Ertek;
End;
A függvények esetében a felrészben azt is meg kell határozni, hogy a függvény milyen típusú értékkel térjen vissza. A visszatérési érték típusa - a paraméterek típusához hasonlóan - csak elõre névvel ellátott típus lehet (összetett típus esetén elõbb típusdefiníció szükséges). A függvények másik különlegessége, hogy kötelezõen tartalmazniuk kell egy olyan sort, ahol a függvény visszatérési értékét meghatározzuk (Fgvnev:= ...). A függvény törzsén belül a függvény nevét változóként használhatjuk, a visszatérési értéket egy értékadó utasítással határozhatjuk meg. Az azonban nics kikötve, hogy a függvény a függvénytörzs hanyadik utasításaként kaphat értéket, tehát nem kötelezõen az utolsó utasítás a visszatérési érték meghatározása.
Egy példa függvények használatára:
Írjunk függvényt, amely kiszámolja két szám szorzatát.
Uses CRT;
Function Szoroz(A, B: Integer): Longint;
Begin
Szoroz:= A*B;
End;
Var E: Longint;
Begin
E:= Szoroz(5,7);
Writeln('5*7: ', E);
Writeln('9*3: ', Szoroz(9,3));
End.
A fenti példa a lehetõ
legegyszerûbb függvényt mutatja be, itt a függvénytörzsben mindössze a
kötelezõ értékadást végezzük el. Természetesen nem ilyen egyszerû
problémák esetén célszerû függvényt írni, de a példában látható a
függvények használatának lehetõsége. A függvények az eljárásokhoz
hasonlóan használhatnak paramétereket, itt is lehetséges cím és érték szerinti
paraméterátadás. A paraméterekre az eljárások esetében leírt megkötések
vonatkoznak itt is.
Példa: Írjunk függvényt, amely kiszámítja egy 10 elemû (Byte) tömb
elemeinek összegét. A függvény paramétere az összegzendõ elemeket
tartalmazó tömb.
Uses CRT;
Type TTomb= Array [1..10] of Byte;
Function TOsszeg(T: TTomb): Word;
Var I: Integer;
Sum: Word;
Begin
Sum:= 0;
For I:= 1 to 10 do
Sum:= Sum+T[I];
TOsszeg:= Sum;
End;
Var V: TTomb;
N: Byte;
O: Word;
Begin
Randomize;
For N:= 1 to 10 do
Begin
V[N]:=
Random(255);
Writeln('A
tomb ', N, ', . eleme: ', V[N]);
End;
Writeln;
Writeln;
Writeln('A tomb elemeinek osszege: ', TOsszeg(V));
Repeat Until Keypressed;
End.
A lokális és globális változók:
A moduláris programozás során a problémát
részfeladatokra bontva oldjuk meg. Minden egyes alprogram egy-egy külön
mûködõ, önálló egység, amely viszont jól illeszthetõ a
problémamegoldás, a programozás menetébe, tehát a program során jól
felhasználható. Az alprogramok fõprogrammal, illetve más alprogramokkal
történõ érintkezését általában paramétereken keresztül valósítjuk meg.
A paraméterek - akár cím szerinti, akár érték szerinti átadású paraméterek - a
Stack nevû memóriarészben helyezkednek el. Ha sok alprogram használja
egyidõben ezt a memóriaterületet, akkor az könnyen betelhet, ami
programunk futási hibával történõ leállását eredményezi. A paramétereken
keresztül történõ kommunikáció az alprogramok között a leghatékonyabb,
legáttekinthetõbb megoldást eredményezi, néha azonban mégis érdemes egy
másik módszert választanunk.
Az alprogramok közötti kommunkiáció másik lehetéséges megoldása a globális -
tehát minden alprogram által elérhetõ - változók használata, amelyeket a
fõprogram deklarációs részében szoktunk deklarálni. Ezek a változók
minden alprogram számára elérhetõek, módosíthatóak. A globális változók
használatának hátránya, hogy a nagy méretû programokat
áttekinthetetlenné, kiszámíthatatlanná teszi, hiszen ki tudja, melyik eljárás
mit csinál a változóval, és amit csinál azt a program melyik pontján csinálja.
Számtalan hiba elkerülhetõ a globális változók mellõzésével,
egyes esetekben mégis nagyon hasznos lehet, ha élünk az általuk nyújtott
lehetõségekkel.
A globális és lokális változók kapcsán ki kell térni két nagyon fontos kérdésre:
A
változók élettartama:
A változók akkor jönnek létre - akkor kapnak a memóriában területet - amikor a
változót deklaráló blokkba belépünk. Tehát ha a változó egy alprogram lokális
változója, a változóhoz tartozó memóriaterület akkor kerül lefoglalásra, amikor
az alprogramot elkezdjük végrehajtani. Ha az alprogram futása befejezõdött,
felszabadításra kerül a memóriában lefoglalt hely. Nyilván a fõprogram
változói számára a program indulásakor történik meg a memóriaterület
lefoglalása, és egészen a program befejezéséig tart a változók élettartama.
A
változók láthatósága:
Ez a kérdéskör szintén a Pascal programok blokkszerkezetével áll kapcsolatban.
A változók azon a blokkon belül láthatók, amely blokk deklarációs részében a
változót deklaráltuk. Amennyiben ez a blokk újabb blokkokat tartalmaz, akkor a
belsõ (egymásba ágyazott) blokkokból is elérhetõ ugyanaz a
változó.
Érdekes kérdés, hogy mi történik, ha két
egymásba ágyazott blokk deklarációs részében ugyanolyan néven deklarálunk két -
esetleg különbözõ típusú - változót. Problémát nem jelent, bár
célszerû elkerülni, ugyanis a külsõ blokkban a változót az ott
deklarált tipussal és az ennek megfelelõ értékekkel használhatjuk,
amikor azonban belépünk a belsõ blokkba, az újabb deklaráció hatására az
elõzõ változó elérhetetlenné válik, ugyanazon a néven egy másik -
esetleg más típusú változót érhetünk el.
A rekurzív alprogramok:
Egy speciális lehetõség az alprogramok készítése során a rekurzió
módszerének alkalmazása, amely azt jelenti, hogy az alprogramok meghívhatják
önmagukat is. A rekurzív alprogramok készítése néhány problémánál nagyon
egyszerû programozási lehetõséget biztosít számunkra. Általában
minden rekurzív problémának létezik egy iteratív (ciklussal történõ)
megodása is. Ha a két lehetõség közül választanunk kell,
célszerûbb az iteratív megoldást alkalmazni, mert a rekurzív programok
futási ideje és memóriaigénye lényegesen nagyobb, mint az iteratív megoldásé.
Ha mégis a rekurzív megoldás mellett döntünk, célszerû a lokális (az
alprogram által használt) változók számát a minimálisra csökkenteni, mivel az
alprogram minden egyes hívásakor a Stack területen foglal helyet ezen változók
számára, így ha sok a rekurzív hívás, a Stack terület hamar megtelhet, a
program futási hibával leáll.
Egy tipikusan rekurzív probléma a Fibonacci számsor problémája. Megoldása a
Feladatok lapon található, a Rekurzív alprogramok használata részben: Feladat
A másik tipikusan rekurzív probléma az N! (N faktoriális) kiszámítása. Ennek a feladatnak hatékony rekurzív és iteratív megoldása is létezik.
Számoljuk ki N! értékét rekurzív alprogram használatával:
Function Fakt(N: Byte): Word;
Begin
If N=0
then Fakt:= 1
else Fakt:= N*Fakt(N-1);
End;
Var X: Byte;
Begin
Write('A szam: ');
Readln(X);
Writeln('A szam faktorialisa: ', Fakt(X));
End.
Tehát a Fakt fügvény önmagát hívja meg egészen addig, amíg a legeszerûbb N értéket kapja meg paraméterként (N értéke minden hívásnál csökken). Amikor elérte azt az értéket, ahol már pontosan meghatározható - számolás nélkül - N! értéke, akkor a Fakt visszatérési értékét pontosan megállapítja. Ezután tér vissza a függvény futás alatt álló példányaihoz, és végzi el a szorzást lépésenként.
Az iteratív megoldás:
Function Fakt(N: Byte): Word;
Var I: Byte;
F: Word;
Begin
F:= 1;
For I:= 1 to N do
F:= F*1;
Fakt:= F;
End;
Var X: Byte;
Begin
Write('A szam: ');
Readln(X);
Writeln('A szam faktorialisa: ', Fakt(X);
End.
A rekurzió módszere használható az alprogramok
esetében is. Itt is meg kell határozni a kilépési feltételt, tehát azt a
feltételt, amelynek teljeseülése esetén az alprogram már nem kerül újból
meghívásra.
Az eddigiekben megnéztük, hogyan tudja egy függvény (vagy eljárás) önmagát újra
és újra meghívni, ezt a fajta rekurziót önrekurziónak nevezzük.
Létezik a rekurzív alprogramoknak egy bonyolultabb változata, amikor két
alprogram kölcsönösen hívja egymást. Az ilyen jellegû rekurziót kölcsönös
rekurziónak nevezzük. A kölcsönös rekurzió jellemzõ példája a Hanoi
tornyai nevû feladat.
Az alprogramok speciális lehetõségei:
A Pascal nyelvben definiáltak az alprogramok készítéséhez néhány olyan különleges lehetõséget, amely speciális alprogramok írása során nagyon hasznos lehet számunkra, a minél egyszerûbb és hatékonyabb megoldás érdekében.
Elõzetes
deklaráció:
A Pascal nyelveben minden azonosítót deklarálni kell a felhasználási helye
elõtt. Vonatkozik ez a változókra, konstansokra, típusokra, és az
alprogramokra is. Egyszerû alprogramok készítésénél ez egyszerûen
megvalósítható, semmilyen nehézséget nem okoz. A gondok akkor jelentkeznek,
amikor két, egymást kölcsönösen hívó alprogramot szeretnénk definiálni. Ebben
az esetben lehet hasznos az elõzetes deklaráció, amely lehetõvé
teszi, hogy az alprogram fejét és törzsét ne egyszerre írjuk le.
Az elõzetes deklaráció során elõször csak a függvény fejrészét
kell deklarálni, a törzs a deklarációs rész késõbbi szakaszaiban bárhol
elhelyezhetõ. Az elõzetes deklaráció a Forward opció segítségével
lehetséges. Az elõzetes deklaráció általánosan:
Procedure Eljarasnev(Form_Par); Forward;
...
...
...
Procedure Eljarasnev(Form_Par);
Var ...
Begin
...
...
...
End;
...
...
...
Példa:
Procedure Olvas(var A, B: real); Forward;
Procedure Szamol(var X, Y: real);
Var A1, B1: Real;
Begin
Olvas(A1, B1);
X:= A1+B1;
Y:= A1-B1;
End;
Procedure Olvas(var A, B: real);
Begin
Write('Az elso szam: '); Readln(A);
Write('A masodik szam: '); Readln(B);
End;
Var X, Y: Real;
Begin
Writeln('Szamolas...');
Szamol(X, Y);
Writeln('A ket szam összege: ', X);
Writeln('A ket szam különbsége: ', Y);
End.
Assembly
nyelvû alprogramok készítése:
Ha azt szeretnénk, hogy egy rutin igazán gyorsan mûködjön, érdemes
Assembly nyelven megírni. Az eljárások, függvények Assembly nyelven is
megírhatók, de ezt az alprogram fejrészében jelezni kell az Assembler opcióval.
Az Assembly nyelvû alprogramok általános felépítése:
Procedure Eljarasnev(Form_Param); Assembler;
Asm
...
...
...
End;
Assembly nyelvû alprogramok esetén az
alprogram törzsét nem a Begin ... End; hanem az Asm ... End; foglalt szavak
között kell megírni.
Megszakítás
típusú alprogramok készítése:
Ha memóriarezidens programot szeretnénk írni, mindenképpen élni kell ezzel a
lehetõséggel. A megszakítás típusú alprogramok hozzárendelhetõk
valamely megszakításhoz, és másodpercenként 18.3-szer végrehajtásra kerülnek.
Ha a programot úgy fejezzük be, hogy a megszakítás és az eljárás összerendelése
megmarad, akkor rezidens programokat írunk. (No jó ezt azért nagyon
leegyszerûsítettem, de nem kell ebbe túl mélyen belemenni.:-)) )
A megszakítás jellegû alprogramok definiálása az Interrupt opcióval
történik. Általános formája:
Procedure Eljarasnev(Form_Param); Interrupt;
Begin
...
End;
Megjegyzésként talán még annyi, hogy az ilyen jellegû alprogramok általában nem használnak paramétereket. Tehát deklarációjuk általában: Procedure Eljarasnev; Interrupt;
Találat: 1609