9. ELJÁRÁSOK ÉS FÜGGVÉNYEK A mintafeladatokban láttuk, hogy a Pascal program a végrehajtható utasításokat a program törzsében tartalmazza. Mielőtt rátérnénk az eljárások és függvények tárgyalására oldjunk meg egy egyszerű feladatot, amelyen bemutatjuk az eljárások és a függvények készítését. Legyen a feladat a háromszög kerületének és területének kiszámítása, ha ismert a háromszög három oldala. A program a következő részfeladatok végrehajtását tartalmazza: - olvassa be a háromszög három oldalának adatait, A beolvasó programrész gondoskodjon arról, hogy ne fogadjon el olyan adatot, amellyel nem lehet háromszöget szerkeszteni. A háromszög megszerkeszthetőségének feltétele: a háromszög bármely két oldalának összege nagyobb kell legyen, mint a harmadik oldal. Ha a feltétel nem teljesül, akkor azt a program jelezze és újra kérje az adatokat. - számítsa ki a háromszög kerületét, - számítsa ki a háromszög területét, - írja ki az eredményeket. A program megírásához szükséges algoritmus a következő: 1. Egy a,b,c oldalú háromszög kerülete k= a+b+c 2. Ha ismerjük a háromszög három oldalát, akkor a háromszög területetét legegyszerűbben a Heron képlettel határozhatjuk meg: Definiáljuk a félkerületet: {EMBED Equation |} akkor a háromszög területe a Heron képlettel: {EMBED Equation |} A következő lépés, megtervezni a program szükséges változóit. a_oldal A oldal, b_oldal B oldal, c_oldal C oldal adatainak tárolásárára h_kerulet kerület, h_terulet terület eredményének tárolására s a fél kerület tárolására f az adatellenőrzéshez szükséges logikai változó számára. Mivel egy a háromszög oldalainak hossza nem csak egész szám lehet, így a változókat real típussal deklaráljuk. A HAROMSZ.PAS program listája: program haromszog; (* Globális deklaráció *) var a_oldal,b_oldal,c_oldal, h_terulet, h_kerulet : real; f: boolean; s: real; begin (* A program törzse *) (* Az adatok beolvasása *) writeln('A haromszog oldalainak megadasa'); repeat write('A oldal: '); readln(a_oldal); write('B oldal: '); readln(b_oldal); write('C oldal: '); readln(c_oldal); (* Szerkeszthetőség ellenőrzése *) if(a_oldal+b_oldal>c_oldal) and (a_oldal+c_oldal>b_oldal) and (b_oldal+c_oldal>a_oldal) then f:=true else begin f:=false; writeln('Hibas adatok'); end; until f; (* A háromszög kerületének számítása *) h_kerulet:=a_oldal+b_oldal+c_oldal; (* A félkerület számitása *) s:=(a_oldal+b_oldal+c_oldal)/2; (* A háromszög területének számítása *) h_terulet:=sqrt(s*(s-a_oldal)*(s-b_oldal)* (s-c_oldal)); (* Első eredmény kiiratása *) writeln; writeln('A haromszog adatai'); writeln('A oldal :',a_oldal:10:2); writeln('B oldal :',b_oldal:10:2); writeln('C oldal :',c_oldal:10:2); writeln; writeln('A haromszog kerulete : ',h_kerulet:10:2); (* Második eredmény kiiratása *) writeln; writeln('A haromszog adatai'); writeln('A oldal :',a_oldal:10:2); writeln('B oldal :',b_oldal:10:2); writeln('C oldal :',c_oldal:10:2); writeln; writeln('A haromszog terulete : ',h_terulet:10:2); end. Sokszor szükséges, hogy adott műveleteket többször végrehajtsunk a program különböző helyein. Például ugyanazon adatokat többször szükséges beolvasni, eredményeket kiírni (lásd a fenti mintaprogramot), részfeladatokat leíró utasítássorozatokat többször kell végrehajtani stb. Az utasításcsoportok többszöri felesleges ismétlését helyettesíti az alprogram. Az alprogram egyszerűen az utasításoknak egy blokkja, amely azért készül, hogy a programozó kivánalmainak megfelelően többször legyen végrehajtva. Az alprogramnak szintén van neve és a főprogramon vagy más alprogramon belül lehet hívni, hogy végrehajtsa az utasításait. A Pascal program szerkezete áttekinthetőbb, rövidebb és struktúráltabb, ha a logikailag összetartozó utasításokat alprogramokba foglaljuk. Az Pascal nyelvben a procedure kulcsszó, amely az alprogram fejét vezeti be, hasonlóan a program kulcsszóhoz, eljárásnak nevezzük. Már megismerkedtünk a szabványos függvényekkel, mint péládul az sqr a négyzetre emelés, az sqrt a gyökvonás, stb. Lehetőség van saját tervezésű függvényt készítésére is. Erre szolgál a function kulcsszó, amellyel a szabványos függvényekhez hasonlóan felhasználható függvényeket készíthetünk. Másik nagy előnye a függvényeknek és az eljárásoknak, hogy a programban többször, különféle paraméterekkel aktiválhatjuk, ezáltal sok munkát takarítunk meg, mivel nem kell ugyanazokat a programrészeket feleslegesen, kis változtatással többször leírni. A Pascal-ban tehát kétfajta alprogram van: az eljárás és a függvény. A két alprogram közötti fő különbség a hívás módjában jelentkezik. Az alprog-ramokat a program deklarációs részében kell megadni (lásd a 4. fejezetet). Az alprogram utasításainak végrehajtásához szükséges bemenő adatokat, valamint azt, hogy az eredmény hol keletkezzen, pontosan meg kell adni. Ezeket az információkat az ún. paraméterlistán adjuk meg. A paraméterlistán keresztül küldünk és kapunk adatokat, mivel a paramétereken keresztül bonyolódik le az adatcsere. Nagyon fontos, hogy megértsük a paraméterek megadási módját, hiszen a paraméterek biztosítják az adatok cseréjének lehetőségét az alprogram (eljárás, függvény) és az őt hívó külső program között. Az alprogram definíciójában a paramétereket formális, az alprogramot hívó utasításban szereplő paramétereket aktuális paramétereknek nevezzük. Fontos szabály, hogy a formális és az aktuális paramétereknek darabszámban, típusban és a megadási sorrendben meg kell egyezniük. A paraméterek átadásának kétféle módja van: - érték (értékparaméter) és - cím szerint (változóparaméter). Érték szerinti paraméterek Az érték szerinti paraméterátadásnál a formális paraméterek számára a memóriában a Pascal mindig helyet foglal. Ezt talán úgy lehet könnyen megmagyarázni, hogy amikor hívjuk az eljárást, akkor az érték szerint átadott aktuális paraméterek értéke átmásolódik a megfelelő formális paraméterbe. Az alprogram ezekkel az átmásolt értékekkel számol, mintegy védelmet biztosít a felhasználónak arra nézve, hogy az ilyen módon megadott aktuális paramétereinek tartalma ne íródjon felül. Ha mégis ezek közül a paraméterek közül az alprogram törzsében felülírás történik, tehát a paraméter az értékadó utasítás bal oldalán is szerepel, akkor ez a felülírás nem rontja el az aktuális paraméter tartalmát, hiszen az alprogram által más címen lefoglalt formális paraméterben történt a változás. Egyébként szokás az érték szerinti paramétereket az alprogram bemenő paramétereinek is nevezni, hiszen ezekben adjuk meg azokat az értékeket, amelyekkel az alprogramnak számolnia kell, tehát az alprogram törzsében lévő utasítások ezeknek az adatoknak az ismeretében új értékeket állítanak elő, végeznek műveletet. Az értékparaméterek helyén a híváskor megadhatunk konstanst, változót, ill. kifejezést is. Ha kifejezést adtunk meg, akkor az először kiértékelődik, majd annak az értéke kerül a formális paraméterbe. Az alprogram a megadott adatokból új értékeket képezhet, ezek fogják alkotni az alprogram "eredményeit". Az ilyen értékeket nevezzük az alprogram kimenő paramétereinek. A paraméterlista megadásánál az alábbi szabályokat kell figyelembe venni: - a paramétereket kerek zárójelbe kell tenni, - az azonos típusú paramétereket felsorolva vesszővel lehet elválasztani, - az utolsó paraméter után kettőspontot téve a paraméterek típusát kell megadni. A típus csak egyszerű típus, vagy felhasználói típus (Type) lehet. - ha különböző típusú paraméterek szerepelnek a listán, akkor a különböző típusú paraméterek közé pontosvesszőt kell tenni. Legyen a példában az alábbi ötféle típusú értékszerinti paraméter: (a,b,c: real; i:integer; b:boolean; c:char; sz:string) Ha egy alprogramnak csak bemenő paraméterei vannak, ahogy az előző példa mutatta, akkor semmilyen eredmény nem kerül ki az alprogramból. Ilyen esetben lehet, hogy a számítás eredményeit csak kiírja az alprogram. Cím szerinti paraméterek A cím szerinti paraméterátadásnál az aktuális és a formális paraméterek az memóriában ugyanazon a címen helyezkednek el, ilyen esetben az alprogram a paraméter címét veszi át. Az alprogram törzsben ezek a paraméterek alkotják a kimenő paramétereket, hiszen az értékadó utasítás bal oldalán valójában felveszik a jobb oldali kifejezés értékét. A paraméterlistán a cím szerinti paramétereket az érték szerinti paraméterektől a paraméterek felsorolása előtt megadott var kulcsszó különbözteti meg. A cím szerinti aktuális paraméter csak változó lehet, és nem lehet sem konstans, sem kifejezés. Ha különböző típusú kimenő paramétere van az alprogramnak, akkor mindegyik típus elé ki kell tenni a var kulcsszót. (c,b,d:real; k: integer; var x,y: real; var n:integer); Összefoglalva az elmondottakat: A bemenő paraméterek, amelyek érték szerint kerülnek átadásra az alprogramnak, kötelezően kell, hogy rendelkezzenek a típusúknak megfelelő értékkel, hiszen ezek a paraméterek az értékadó utasítás jobb oldalán szerepelnek. A kimenő paraméterek, melyeket a var kulcsszóval jelöltünk, nem kell, hogy az alprogram hívása előtt rendelkezzenek kezdőértékkel, hiszen éppen az a cél, hogy az alprogram törzsében lévő utasításokkal ezeknek a paramétereknek adjunk értéket. Példa (a,b : real; var ered: real) az alprogram törzsében szerepelhet az alábbi értékadás: ered:= a+b; így az alprogram eredményként bejövő a és b paraméterek értékének összegét szolgáltatja az ered változóban. Idáig olyan példákat használtunk a paraméterlistán, amelyek egyszerű típusúak voltak : integer, real, char, boolean. Ha az alprogram paramétere összetett típusú pl. array (tömb), set (halmaz), record (rekord), file, akkor azt csak előredefiniált típusnévvel adhatjuk meg. Nézzünk egy példát arra, hogyan lehet tömb patamétert megadni az alprogram paraméterlistáján. Ha az alprogram egyik paramétere egy 20 elemű egész típusú több, akkor a tömb számára először létre kell hozni egy tomb típust, ezután az alprogram paraméterlistáján már szerepelhet tomb típusú paraméter. type tomb= array[1..20] of integer; .... (x,y : tomb; n:integer; var s: real); Tekintsük azt az esetet, amikor bemenő paraméter egy nagyméretű tömb, így ebben az esetben is készül erről egy másolat a megfelelő formális paraméterbe. Ha azonban a programozó nem tartja szükségesnek ezt a védelmi módszert és inkább kevesebb tárterületet kíván használni, akkor ezt a bemenő paramétert teheti is var listára, ily módon az cím szerint kerül átadásra. Śgy a programozónak kell ügyelnie arra, hogy a tömbből csak olvasson az eljárás a törzsében, vagyis csak az értékadó utasítás jobb oldalán használja azt. 9.1. Függvények Már megismerkedtünk és használtunk a szabványos függvényeket (Sqr, Sqrt, Sin, Cos, Abs stb.) Pascal programokban. Például: w:= a+b*sin(x)+sqr(2+b); Láthatjuk, hogy a függvényeket az értékadó utasítás jobb oldalán hívtuk. Feltételezzük, hogy szeretnénk köbre emelő függvényt használni, ez viszont nincs a szabványos függvények között a Pascalban. Ha {EMBED Equation |} matematikai képletet átírjuk át Pascal kifejezéssé, Cube:= x*x*x; akkor ezt az utasítást beírhatjuk azokra a helyekre, ahol szükséges. Sokkal egyszerűbb lenne azonban az, ha az x négyzetreemelését elvégző sqr(x) függvényhez hasonlóan írni egy Cube(x) függvényt. Erre van lehetőség, létrehozhatunk egy saját Cube függvényt, amelyet felhasználó által definiált függvénynek nevezünk. A függvény egy olyan alprogram, amely aktiválásakor a nevével ad vissza értéket a hívó programnak. A Cube függvénynek az lesz a feladata, hogy az x értéknek meghatározza a köbét. Ki is írathatjuk a képernyőre writeln(Cube(x)); Nézzük meg a függvény általános leírását: function függvény_neve(paraméterlista ): függvény_típusa: lokális deklarációs rész {label, const, type, var, procedure, function } begin a függvény törzse (végrehajtható utasítások) függvény_neve:= .....; end; Láthatjuk, hogy a felhasználó által definiált függvény hasonlít a Pascal programhoz. Megtaláljuk benne a deklarációt és a törzsben a végrehajtható utasításokat. A függvény fejléce A függvény fejléce a function kulcsszóval kezdődik, ezután következik a függvény azonosítója (a neve), a formális paraméterlistája és a függvény típusa. A függvény azonosítója A függvény azonosítóját a Pascal azonosítóképzés szabályai szerint kell kialakítani. A példánkban a függvény neve a Cube, és a hívásakor egy értéket köbre kell emelnie. A függvény nevére vonatkozik a függvény típusának a megadása, hiszen a típusnak megfelelő eredmény kerül bele. A paraméterlista A függvény paraméterlistája tartalmazza azokat a paramétereket, amelyeket át kell vennie a hívó programtól. A paraméternek nemcsak nevet kell adni, hanem a típusát is meg kell határozni. A függvénynél a paramétereket általában név szerint adjuk át, hiszen ebben adjuk meg az értékekeket, amivel a függvény számol. Bonyolultabb esetben a cím szerinti paraméterátadás is használható, például hibajelzés céljából. Nézzünk néhány paraméterlistát: (x,y : integer) (a,b: real; i:integer) (ch: char; n: integer; sz:string) (s: string; v: integer; var hibakod: integer) A függvény típusa A függvény fejlécében meg kell adni a függvény típusát is. Ez magától érthetődő, hiszen a függvény általában egyetlen értéket állít elő és ezt a függvény nevével adja vissza, a definiált típusnak megfelelően. A Cube köbreemelő függvénynek egyetlen bemenő paramétere lesz, amelyben megadjuk azt az értéket, amelyet köbre kell emelni. A formális paraméter neve legyen x, típusa real, a függvény real típusú eredményt fog szolgáltatni. Nézzük meg a függvény teljes fejlécét: function Cube(x: real): real; A függvény lokális deklarációi A függvény fejléce alatt a függvény számára szükséges deklarációk következnek, amelyeket csak a függvény használ. A példánkban a Cube függvény nem használ lokális változókat. A függvény törzse Végül eljutottunk a függvény törzséhez, amely tartalmazza azokat a műveleteket, amelyeket a függvénynek végre kell hajtani ahhoz, hogy megadja a visszatérési értékét a hívó programnak. Ezeket az utasításokat begin és end közé kell tenni és pontosvesszővel lezárni. A Cube függvény törzsében szerepelnie kell a Cube:=x*x*x; utasításnak. Az alábbi két dolgot nem tehetjük meg: 1. A függvény neve függvény törzsén belül nem szerepelhet az értékadás jobb oldalán, például Cube:= Cube * x; Kivéve azt az esetet, ha szándékosan rekurzívan kívánjuk hívni. A rekurzív hívással külön részfejezetben foglalkozunk. 2. A függvény azonosító neve nem szerepelhet az értékadó utasítás bal oldalán a függvény törzsén kívül Cube:=x*x*x; Ez megengedett a függvényen belül, de tilos a függvényen kívül. A köbreemelő függvényünk teljes listája: function Cube(x : real) : real; begin Cube:= x*x*x; end; Példaként nézzük meg a Cube függvény különböző hívásait, ez azért lehetséges, mert a paraméterét érték szerint veszi át: m:= Cube(3); értékadó utasítás jobb oldalán, paramétere számkonstans. writeln(Cube(3)); writeln eljárásban y:=3; m:=Cube(y); paramétere változó y:=3; w:=2+Cube(y+1)*2; paramétere aritmetikai kifejezés if Cube(y)>27 then feltételes utasításban is szerepelhet. Az FUGGVENY.PAS program tartalmazza a Cube függvény hívási módjait: program fuggveny; var m,y,w : real; function Cube(x : real) : real; begin Cube := x*x*x; end; begin m:=Cube(3); writeln('m: ',m:6:1); writeln('Cube(3): ',Cube(3):6:1); y:=3; w:=Cube(y); writeln('w: ',w:6:1); y:=3; w:=2 + Cube(y)*2; writeln('w: ',w:6:1); if Cube(y) > 27 then writeln('Cube(y) > 27') else writeln('Cube(y) <= 27'); end. Az program futási eredménye: m: 27.0 Cube(3): 27.0 w: 27.0 w: 56.0 Cube(y) <= 27 9.2. Eljárások Az alprogramok másik fajtája az eljárás. Az eljárás eltérően a függvénytől a nevén keresztül nem ad vissza értéket. Az eljárás felépítésének általános formája: procedure eljárásnév( formális paraméterek listája); Az eljárás lokális deklarációi {const, label, type, var, procedure, function } begin az eljárás törzse (utasítások) end; Most nézzük meg részletesen az eljárás felépítését: Az eljárás fejléce Az eljárás kulcsszava a procedure, ezzel kell kezdeni az alprogramot. Az eljárásnak nevet kell adni, a névnek betűvel kell kezdődnie, a második karaktertől betű és szám is előfordulhat benne, valamint tartalmazhat _ (aláhúzás) karaktert is. A formális paraméterek listája Kerek zárójelben kell felsorolnunk az eljárás paramétereit, majd ; zárja az eljárás fejlécét. Śrhatunk olyan eljárást, amelynek nincsenek paraméterei, ilyen eljárások általában valamit kiírnak, például: procedure fejlec; begin writeln('Az egyenletrendszer megoldasa'); end; A gyok_kiir eljárás átveszi a két paraméterének megfelelő aktuális értékeket, a képernyőre kiírja, azonban semmilyen értéket nem ad vissza: procedure gyok_kiir(x1,x2 : real); begin writeln('Az egyenlet valos gyokei'); writeln('x1 : ',x1); writeln('x2 : ',x2); end; A tömb a paraméterlistán csak előredefiniált típusként szerepelhet. Nézzünk példát egy rendez eljárásra, ahol a be_tomb a rendezendő adatokat, a ki_tomb eredményként a rendezett adatokat tartalmazza, tehát a ki_tomb-nek a var kell listán kell szerepelnie: procedure rendez(n: integer; be_tomb:tomb; var ki_tomb:tomb); Ha a be_tomb nagy méretű, a program kevesebb helyet foglal a memóriában, ha a be_tomb is cím szerinti paraméter lesz: procedure rendez(n: integer; var be_tomb,ki_tomb:tomb); Irhatunk olyan rendez eljárást, hogy a be_tomb-ben keletkezzen a rendezett adat, vagyis a bemenő adat felülírásra kerül - ezt megengedi a cím szerinti paraméterátadás: procedure rendez(n: integer; var be_tomb:tomb); Lokális deklaráció Az eljárás fejléce után következik az eljárás törzsben használt, tehát az eljárásra nézve lokális konstansok, változók deklarációja. A lokális változók az eljárás aktiválásakor kapnak értéket, de értékük kívülről hozzáférhetetlen, amire nincs is szükség. Ezek a változók az algoritmus beprogramozásához szükséges munkatárakat jelentik. Soha nem szabad olyan eljárást írni, amelyben például a ciklus változója a főprogramban deklarált globális változó. Gondoljuk meg milyen bonyodalom származik abból, ha az eljárást a főprogramból ciklusban hívjuk, ahol a ciklus változó i, és a ciklus i változóját a hívott eljárás módosítja, mert az eljárásban nem deklaráltunk egy lokális i változót. Nem általános az az eljárás, amelynek nincs paramétere. Az ilyen eljárások használatának az oka talán az, hogy a programozó nem értette meg a paraméterek átadási módjait és a főprogramban deklarált globális változókat használja az eljárása, olvas a globális változókból, illetve ír a globális változókba. Ez a módszer azért sem jó, mivel az eljárásnak nincsenek paraméterei, nem lehet az eljárást dinamikusan más paraméterekkel aktíválni. Kerüljük ezt a módszert. Az eljárás törzse Amikor már elneveztük a bemenő és kimenő paramétereket, megállapítottuk a típusukat, valamint az eljárás lokális változóit, következik az eljárás algortimusának Pascal utasításokra való átírása. Bonyolultabb algoritmushoz blokkdiagramot is készíthetünk, ahol ellenőrízhetjük a működési elvet, jobban át tudjuk gondolni a végrehajtási sorrendet. A blokkdiagram azért is jó, mert valóban bonyolultabb algoritmus esetén mint dokumentáció is megmarad, amely szükséges az ejárás esetleges további javításához, bővítéséhez. Könnyebb bizonyos idő után emlékezni az eljárás készítésével kapcsolatos gondolatmenetekre. Ne felejtsük el, hogy az eljárás törzsét begin és end; utasítások közé kell zárni. Példaprogram az eljárás készítésére Példaként dolgozzuk át a fejezet elején ismertetett HAROMSZ.PAS programot úgy, hogy az adatok beolvasását, a háromszög kerületének ill. területének számítását, valamint az eredmény megjelenítését foglaljuk eljárásokba. A főprogram feladata legyen az eljárások hívásának bemutatása. a. A háromszög kerületének kiszámítása eljárással Az eljárás neve legyen: haromszog_kerulet Tervezzük meg az eljárás paraméterlistáját és egyben döntsük el a paraméterek típusát. Ahhoz, hogy a változók ne csak egész számokat, hanem valós számokat is tudjanak tárolni, ezért a paramétereknek real típusúaknak kell lenni. Azok a paraméterek, amelyekből az eljárás számol, a bemenő paraméterek. Az a paraméter, amely az eredményt adja vissza, a kimenő paraméter. Az eljárás paraméterei: bemenő paraméter az érték szerinti paraméter, a háromszög 3 oldala: a, b, c : real; kimenő paraméter a cím szerinti paraméter a háromszög kerülete: var ker : real; Az a,b,c változók lesznek az érték szerint átadott paraméterek, hiszen ekkor ezeket egyaránt megadhatjuk konstanssal és kifejezéssel is. Az eredmény a ker változóban keletkezik, amelyet cím szerinti paraméterként kell megadni. Az eljárás törzsében a háromszög kerületének kiszámítását jelentő algoritmust kell Pascal kifejezéssé átírni és az eljárás törzsét begin és end közé zárni. A eljárás utasításai: procedure haromszog_kerulet(a,b,c : real; var ker:real); begin ker:= a+b+c; end; b. A háromszög területének kiszámítása eljárással Az eljárás neve legyen: haromszog_terulet Az eljárás paraméterei: A bemenő paraméterei azonosak a haromszog_kerulet eljáráshoz, a háromszög 3 oldala : a, b, c : real; A kimenő paraméter pedig a háromszög területe : var ter : real; A ter változót cím szerint adjuk át az eljárásnak, mert ebben keletkezik az eredmény, a háromszög területe. Az algoritmus programozásánál beláthatjuk, hogy érdemes lefoglalni egy s lokális változót, amelyben egyszer kiszámítjuk a háromszög félkerületét, és a terület kiszámítását végző kifejezésben inkább négyszer használjuk a tartalmát, és nem kell a félkerületet mindig újra kiszámítanunk. Az eljárás listája: procedure haromszog_terulet(a,b,c:real; var ter:real); var s: real; begin s:=(a+b+c)/2; ter:=sqrt(s*(s-a)*(s-b)*(s-c)); end; Ha az eljárás működését ellenőrizni akarjuk, meg kell írnunk hozzá egy főrprogramot, amely az eljárást hívja. Az eljárások gyakorlására írjunk még két eljárást, az egyik az adatokat olvassa be, a másik az eredményt írja ki. d. Az adatokat beolvasó eljárás Az eljárás feladata legyen az, hogy a háromszög három oldalának adataira kérdezzen rá és eredményként adja vissza a háromszög oldalaira beolvasott adatokat. Ennek az eljárásnak csak kimenő paraméterei lesznek, ezért a paramétereket var listára kell tenni, így az eljárásban beolvasott értékek valóban beíródnak a paraméterekbe. Az eljárás neve: olvas . Kimenő paraméterek: a,b,c . Az a,b,c paraméterek real típusúak és var listán kell lenniük. Az egyszerű olvas eljárás, amely ellenőrzés nélkül olvassa az adatokat: procedure olvas(var a,b,c: real); begin writeln('A haromszog oldalainak megadasa); write('a oldal: '); readln(a); write('b oldal: '); readln(b); write('c oldal: '); readln(c); writeln; end; d. Az eredményeket dinamikusan kiíró eljárás Tervezzük meg az eredményt kiíró eljárást is. Az eljárásnak legyen az a feladata, hogy írja ki a képernyőre a háromszög oldalainak az adatait, egy string paraméterben megadott szöveget, valamint egy real típusú változó tartalmát. Śgy ezzel a kiíró eljárással például nemcsak a háromszög területének értékét, hanem a kerület értékét is kiirathatjuk. Mennél ügyesebben szervezzük meg egy eljárás paramétereit, annál sokrétűbb feladatok végrehajtására lesznek alkalmasak. Az eljárás neve: kiir Bemenő paraméterei: a,b,c, ered real típusú szoveg string típusú procedure kiir(a,b,c,ered: real; szoveg:string); begin writeln('A haromszog adatai'); write('a oldal : ',a:10:2); write('b oldal : ',b:10:2); write('c oldal : ',c:10:2); writeln; write(szoveg,' ',ered); writeln('Nyomj Enter-t …'); readln; end; Az eredmény kiírása után a program az Enter leütésére vár. A főprogram készítése A programnak a neve legyen haromszog_szamitasok; A programban az eljárásokat aktivizáló aktuális változóknak kell helyet foglalni, amelyek szükségesek ahhoz, a beolvasott adatokat illetve az eredményt tárolják: a_oldal, b_oldal, c_oldal a háromszög oldalainak adatait tartalmazzák, (real típusúak) h_terulet a háromszög területének eredményét fogja tárolni, real típusú h_kerulet a háromszög kerületének eredményét fogja tárolni, real típusú fejlec az eredmény kiírásához biztosítja a szöveget, string típusú A ELJARAS1.PAS file a teljes programot tartalmazza: program haromszog; uses crt; var a_oldal,b_oldal,c_oldal, h_terulet,h_kerulet: real; fejlec: string; procedure olvas(var a,b,c: real); begin writeln('A haromszog oldalainak megadasa); write('a oldal: '); readln(a); write('b oldal: '); readln(b); write('c oldal: '); readln(c); writeln; end; procedure kiir(a,b,c:real; szoveg:string; ered:real); begin writeln('A haromszog adatai'); write('a oldal : ',a:10:2); write('b oldal : ',b:10:2); write('c oldal : ',c:10:2); writeln; write(szoveg,' ',ered:10:2); writeln('Nyomj Enter-t …'); readln; end; procedure haromszog_kerulet(a,b,c : real; var ker:real); begin ker:= a+b+c; end; procedure haromszog_terulet(a,b,c:real; var ter:real): var s: real; begin s:=(a+b+c)/2.; ter:=sqrt(s*(s-a)*(s-b)*(s-c)); end; (* foprogram blokkja *) begin clrscr; (* a kepernyo torlese *) (* a haromszog adatainak beolvasasa *) olvas(a_oldal,b_oldal,c_oldal); (* a haromszog teruletenek szamitasa *) writeln('Az eljaras hivasa: valtozokkal '); haromszog_terulet(a_oldal,b_oldal,c_oldal, h_terulet); kiir(a_oldal,b_oldal,c_oldal, 'A haromszog terulete: ',h_terulet); (* eljaras hivasa konstanssal *) writeln('Az eljaras hivasa: konstasokkal'); haromszog_terulet(3,4,5,h_terulet); kiir(3,4,5,'A haromszog terulete: ',h_terulet); (* eljaras hivasa kifejezessel *) writeln('Az eljaras hivasa: kifejezesekkel '); haromszog_terulet(a_oldal+1,2*b_oldal,c_oldal, h_terulet); kiir(a_oldal+1,2*b_oldal,c_oldal, 'A haromszog terulete:',h_terulet); (* a haromszog keruletenek szamitasa *) haromszog_kerulet(a_oldal,b_oldal,c_oldal, h_kerulet); kiir(a_oldal,b_oldal,c_oldal, 'A haromszog kerulete:',h_kerulet); end. Az ELJARAS.PAS program futási eredménye: Mivel az eredmény hosszabb, mint egy képernyő, ezért egy paraméter nélküli readln eljárással felfüggesztjük a program futását a kiértékelés számára és Nyomj Enter- t … szöveg jelzi, hogy a program az Enter leütésére vár. A haromszog oldalainak megadasa a oldal: 3 b oldal: 4 c oldal: 5 Az eljaras hivasa: valtozokkal A haromszog adatai a oldal: 3.00 b oldal: 4.00 c oldal: 5.00 A haromszog terulete: 6.00 Nyomj Enter-t Az eljaras hivasa: konstansokkal A haromszog adatai a oldal: 3.00 b oldal: 4.00 c oldal: 5.00 A haromszog terulete: 6.00 Nyomj Enter-t Az eljaras hivasa: kifejezesekkel A haromszog adatai a oldal: 4.00 b oldal: 8.00 c oldal: 5.00 A haromszog terulete: 8.18 Nyomj Enter-t A haromszog adatai a oldal: 3.00 b oldal: 4.00 c oldal: 5.00 A haromszog kerulete: 12.00 Nyomj Enter-t Módosítsuk először a beolvasó eljárást úgy, hogy ellenőrizze az adatokat a háromszög megszerkeszthetősége szempontjából. Három oldalból csak akkor szerkeszthető meg a háromszög, ha páronként két oldal összege nagyobb, mint a harmadik oldal. Tehát az alábbi feltételeknek kell teljesülni: (a+b) > c és (a+c) > b és (b+c) > a Ha ezek a feltételek nem teljesülnek adjon az olvas eljárás figyelmeztetést a felhasználónak és várja az új adatok megadását. A módosított olvas eljárás; procedure olvas(var a,b,c: real); var f : boolean; begin writeln('A haromszog oldalainak megadasa); repeat write('a oldal: '); readln(a); write('b oldal: '); readln(b); write('c oldal: '); readln(c); if (a+b>a)and (a+c>b) and (b+c>a) then f:=true else begin f:=false; writeln('Hibas adatok'); end; until f; end; Az ELJARAS2.PAS program tartalmazza ezt az olvasó eljárást, amely azt figyeli, hogy az adatok eleget tesznek-e a háromszög megszerkeszthetőségi feltételeknek. Az ELJARAS3.PAS a beolvasó eljárás olyan továbbfejlesztett változatát tartalmazza, amely nem fogad el hibásan megadott adatot. Csak összehasonlítás szempontjából írjuk át a haromszog_terulet eljárást függvénynek. A függvény neve legyen: fg_haromszog_terulet Bemenő paraméterei : a,b,c real típusúak. Az eredmény a függvény nevében, az fg_haromszog_terulet -ben keletkezik. A függvény a következő: function fg_haromszog_terulet(a,b,c:real): real; var s: real; begin s:=(a+b+c)/2.; fg_haromszog_terulet:=sqrt(s*(s-a)*(s-b)*(s-c)); end; Ha ezt a függvényt beillesztjük az előzőekben ismertetett főprogram deklarációs részébe, az fg_ter változót real típusként deklaráljuk és a kiegészítjük a főprogramot az alábbi utasításokkal: olvas(a_oldal,b_oldal,c_oldal); fg_ter:=fg_haromszog_terulet(a_oldal,b_oldal,c_oldal); kiir(a_oldal,b_oldal,c_oldal, 'A haromszog terulete fuggvennyel: ',fg_ter); A módosított programot (ELJARASF.PAS) lefuttatva az eljárásnak és a függvénynek ugyanazt az eredményt kell adnia. 9.3. Típusdefiníció használata a paraméterlistán Mint már említettük az eljárások és függvények formális paraméterlistáján csak olyan változó lehet paraméter, amelynek külön típusneve van. Ilyen például az integer, real, word, char, string, boolean stb., de nem használhatjuk az array, set, file, rekord változókat közvetlenül, ezekre típust kell definiálni, a type deklaráció segítségével. Ugyancsak felhasználói típust kell létrehoznunk a string[n] típusú paraméterek deklarálásához. type tomb = array[1..10][1..10] of real; betuk = set of 'a'..'z'; tfile = file of integer; komplex = record x,y: real; end; st12 = string[12]; var a : tomb; f : tfile; abc : betuk; w,y : komplex; fnev: st12; folv: tfile; procedure (x:tomb; olv: tfile; fn: st12); .. begin ... end; 9.4. Eljárás paramétere: függvény Az eljárás paraméterlistáján függvény is szerepelhet. Ennek megvalósításához az alábbiakat kell tennünk: - az eljárást a {$F+} fordítási opcióval kell fordítani, - meg kell adni a függvény típusát, például type fuggv= function(x:real):real; - meg kell adni a felhasználói függvényt, amelynek bemenő paramé- terei típusban és darabszámban, valamint kimenő érték típusában megegyeznek. Legyen a feladat egy táblázatkiíró eljárás írása, amely a paraméterként megkapott függvényt adott intervallumban tabellázza, fejlécként a függvény képletét is kiírja. Először olyan típust kell létrehoznunk, amely megegyezik a tabellázni kívánt függvény paramétereivel és a függvény típusával. Mivel a két tabellázandó függvényünk function tablazat1(x:real):real; function tablazat2(x:real);real; ezért az alábbi típust hozzuk létre: type fuggveny =function(x: real): real; A a kiir eljárás paraméterei: x1,x2 a táblázat kezdő és végértéke dx a táblázat lépésköze f a tabellázandó függvény szoveg a fejlécként kiirandó szöveg A kiir eljárás feje: procedure kiir(x1,x2,dx:real; f:fuggveny; szoveg: string); A FUGG_PAR.PAS program listája: {$F+} (* eljaras parametere fuggveny *) (* fugg_par.pas *) program fuggveny_parameter; type fuggveny = function(x:real): real; var x1,x2,dx : real; fejlec1,fejlec2: string; function tablazat1(x: real): real; begin tablazat1:= 3*sin(x*x); end; function tablazat2(x: real): real; begin tablazat2:=2.5 * x * x/cos(x); end; procedure kiir(x1,x2,dx:real; f:fuggveny; szoveg: string); var x:real; begin x:=x1; writeln(' x ',szoveg); while x0 A rekurzív definíció felhasználásával 4… kiszámításának lépései: 4…= 4*3… 3*2… 2*1… 1*0… 1 = 4*3*2*1*1=24 A fenti számítási menetet megvalósító Pascal függvény: function factr(n:integer):longint; begin if n=0 then factr:=1 else factr:=n*factr(n-1); end; A teljesség kedvéért közöljük a hatékonyabb interaktív megoldást is: function fact(n:integer):longint; var f:longint; begin f:=1; while (n>0) do begin f:=f*n; dec(n); end; fact:=f; end; FACTPR.PAS program bemutatja a factr és a fact függvények hívását. - Kölcsönös rekurzió Kölcsönös rekurzióról akkor beszélünk, ha egy alprogram egy általa meghívott másik alprogramból hívódik meg újra. Az ilyen megoldáshoz szükséges a forward deklaráció használata: procedure b(j:integer); forward; procedure a(i:integer); ... begin ... b(i); ... end; procedure b; ... begin ... a(j); ... end; 9.7. Globális és lokális változók, az azonosítók érvényességi köre A ELJARAS1.PAS programban is láttuk, hogy a program deklarációjában lévő változók: var a_oldal, b_oldal, c_oldal, h_terulet, h_kerulet: real; az egész programtörzsre vonatkoztak. Ezek a változók a program törzsére néve globális változók. A haromszog_terulet eljárás paraméterlistáján az a,b,c,ter változók formális paraméterek. Az eljáráson belül deklarált s változó lokális, mert csak az eljárás törzsén belül érhető el. procedure haromszog_terulet(a,b,c: real; var ter: real); var s: real; begin s:= ... end; A főprogramban az olvas eljárás hívása a globális aktuális paraméterekkel történik, amelyekre helyet foglaltunk a memóriában: olvas(a_oldal, b_oldal, c_oldal); Ezekkel az értéket kapott változókkal hívjuk tovább a haromszog_terulet eljárást: haromszog_terulet(a_oldal,b_oldal,c_oldal,h_terulet); Tekintsük meg a 9.1. ábrát, amelyben a főprogram két alprogramot tartalmaz. A főprogram deklarációjában lévő y változó globális a teljes programra néve, így az alprogramokra is. A Blokk1 alprogram deklarációjában szereplő x változó lokális az 1. alprogramon belül. {EMBED MSDraw \* mergeformat|} 9.1. ábra A változók érvényességi köre A Blokk2 alprogram x változója szintén lokális a 2. alprogramon belül. A két alprogramban lévő x változó nem zavarja egymást, hiszen teljesen más tárterületen helyezkedik el. Ezért ha két különböző személy alprogramot fejleszt, nem kell megbeszélniük, hogy milyen lokális változókat használnak az alprogramon belül, csak a paraméterek sorrendjében és típusában kell megállapodniuk. A két alprogramban viszont elérhető az y változó tartalma is. Egyébként nem tanácsos olyan alprogramokat tervezni, amelyek különböző globális változókat használnak, mivel azok csak akkor működnek, ha a globális változóik megfelelően deklarálva vannak. A 9.2. ábrán látható főprogram több alprogramot tartalmaz, sőt alprogramon belül újabb alprogram is van. Értékeljük ki itt is a változók érvényességi körét. {EMBED MSDraw \* mergeformat|} 9.2. ábra Bonyolultabb blokkszerkezet A főprogram var deklarációjában szereplő y változó globális az összes alprogramra, kivéve a Blokk4 függvényt, mivel lokális változójának neve megegyezik a főprogram y változójának a nevével. A két y változó más memóriacímre kerül, függetlenek egymástól. Egyébként az eljárásokban ill. függvényekben lévő deklaráció a saját törzsükre (begin ... end) vonatkozik, tehát lokálisak, ahhoz máshonnan nem lehet hozzáférni. Foglaljuk össze a 9.2. ábrán látható változók érvényességi körét: - y változó globális az egész programra, kivéve a Blokk4 függvényt, ahol az y (egy másik) lokális változó, - x1 lokális a Blokk1 eljárásra - x2 lokális a Blokk2 eljárásra és globális az Blokk3 függvényre, - x3 lokális az Blokk3 függvényre. A példából is látható, hogy egy változó globális és lokális lehet, ez relatív fogalom. A változók élettartama: Minden változó az őt tartalmazó blokkba belépve jön létre, és a blokkból kilépve megszünik. Legtovább a főblokkban deklarált változók élnek, amelyek a program teljes futása alatt elérhetők (statikus változók). 9.8. Sztringek használata Turbo Pascal-ban A char adattípus egyetlen byte-on tárolja a karaktert. A sztring karakter típusú elemekből épül fel. A sztring adattípus szöveges információt tárol. A szöveg hossza 255 karakterig terjedhet. Például: var nev : string[12]; begin nev:='Bernadett'; Ebben a példában a nev sztring változó 13 byte-ot foglal le a memóriából, mivel a 0. byte-ja a sztring hosszát tartalmazza: 0 1 2 3 4 5 6 7 8 9 10 11 12 Byte tartalma #9 B e r n a d e t t \ * X {SYMBOL 173 \f "Symbol"} {SYMBOL 195 \f "MS LineDraw"}{SYMBOL 196 \f "MS LineDraw"}{SYMBOL 196 \f "MS LineDraw"}{SYMBOL 196 \f "MS LineDraw"}{SYMBOL 196 \f "MS LineDraw"}{SYMBOL 196 \f "MS LineDraw"}{SYMBOL 196 \f "MS LineDraw"}{SYMBOL 196 \f "MS LineDraw"}{SYMBOL 196 \f "MS LineDraw"}{SYMBOL 196 \f "MS LineDraw"}{SYMBOL 196 \f "MS LineDraw"}{SYMBOL 196 \f "MS LineDraw"}{SYMBOL 196 \f "MS LineDraw"}{SYMBOL 196 \f "MS LineDraw"}{SYMBOL 196 \f "MS LineDraw"}{SYMBOL 196 \f "MS LineDraw"} Sztring {SYMBOL 196 \f "MS LineDraw"}{SYMBOL 196 \f "MS LineDraw"}{SYMBOL 196 \f "MS LineDraw"}{SYMBOL 196 \f "MS LineDraw"}{SYMBOL 196 \f "MS LineDraw"}{SYMBOL 196 \f "MS LineDraw"}{SYMBOL 196 \f "MS LineDraw"}{SYMBOL 196 \f "MS LineDraw"}{SYMBOL 196 \f "MS LineDraw"}{SYMBOL 196 \f "MS LineDraw"}{SYMBOL 196 \f "MS LineDraw"}{SYMBOL 196 \f "MS LineDraw"}{SYMBOL 196 \f "MS LineDraw"}{SYMBOL 196 \f "MS LineDraw"}{SYMBOL 196 \f "MS LineDraw"}{SYMBOL 196 \f "MS LineDraw"}{SYMBOL 196 \f "MS LineDraw"}{SYMBOL 180 \f "MS LineDraw"} a sztring hossza A sztring hosszát az ord(nev[0]) kifejezés adja meg. A példában a sztringbe írt szöveg hossza 9 karakter, binárisan 0000 1001. Mivel a 12 karakterre deklarált sztringbe csak 9 karaktert helyeztünk el, az utolsó három byte véletlenszerű értékeket tartalmaz. 9.8.1. Szabványos eljárások és függvények a sztringek kezelésére Chr függvény A Chr függvény integer paramétere egész számot fogad és annak megfelelő sorszámú karaktert ad vissza. Például az ASCII kód 65 az A karaktert jelöli, akkor a Chr(65) az A karaktert adja vissza. Śrjuk ki a képernyőre az Ok… szöveget. (* chrtest.pas *) program chrtest; uses crt; var s: string[20]; begin clrscr; s:= 'Ok' + chr(33); writeln(s); end. A program eredménye: Ok… Uppcase függvény Az Uppcase karakter szintű függvény, amely egyetlen kisbetű karaktert fogad 'a' .. 'z' -ig és visszatér a nagybetűs megfelelőjével. Ha az Uppcase paramétere nem kisbetű, akkor változatlanul adja vissza a karaktert. (* upcaset.pas *) program upcaset; uses crt; var s: string; i: integer; begin clrscr; s:='abcdefgHIJkl'; writeln('sztring : ',s); for i:=1 to length(s) do s[i]:=Upcase(s[i]); writeln('Upcase utan: ',s); end. A program eredménye: sztring : abcdefgHIJkl Upcase utan: ABCDEFGHIJKL Concat függvény A sztrigek összefűzésének két változata is létezik a Turbo Pascal-ban. Használhatjuk a concat függvényt, vagy a + (plus) operátort. A szabványos concat függvénnyel bármilyen számú sztring paramétert összefűzhetünk, de az összefűzött sztring hossza sem lehet 255 karakternél nagyobb. (* sztring1.pas *) program sztring1; uses crt; var s1,s2,s3,s4: string; begin clrscr; s1:='Ez pelda '; s2:='a concat'; s3:=concat(s1,s2,' fuggvenyhivasra'); writeln('concat : ',s3); s4:='Ez pelda' + ' a sztringek ' + 'osszeadasara.'; writeln('+ muvelet: ',s4); end. A program eredménye: concat : Ez pelda a concat fuggvenyhivasra + muvelet: Ez pelda a sztringek osszeadasara Ha a concat függvénnyel, vagy a + operátorral összefűzött sztring hossza túl- nő a sztring maximális hosszánál (255 karakter), akkor az eredménysztring a 255. karakter után elveszik. Copy függvény A copy függvénnyel részsztringet másolhatunk ki egy nagyobb sztringből. A copy függvénynek három paramétere van. Az első paraméter a sztring, amelyből másolni akarunk, a második a karakter sorszáma, ahonnan másolni akarunk és a harmadik paraméter, pedig megmondja, hogy mennyi karakter kerüljön másolásra. (* sztring2.pas *) program sztring2; uses crt; var s1,s2: string; begin clrscr; s1:='Elemer'; writeln('Keresztnev : ',s1); s2:=copy(s1,1,3); writeln('Copy hivasa utan: ',s2); s2:=s2+'k'; writeln('Uj nev : ',s2); end. A program eredménye: Keresztnev : Elemer Copy hivasa utan: Ele Uj nev : Elek Delete eljárás A Delete eljárás sztringből karaktereket töröl. Az eljárás első paramétere a sztring, ahonnan törölni kell, a második paramétere az első törlendő karakter helyét jelenti és a harmadik paraméterben adjuk meg a törlendő karakterek számát. (* sztring3.pas *) program sztring3; uses crt; var s1,s2: string; begin clrscr; s1:='Katoka'; writeln('Keresztnev : ',s1); Delete(s1,4,3); writeln('Delete hivas utan: ',s1); s2:=concat(s1,'inka'); writeln('Modositott nev : ',s2); end. A program eredménye: Keresztnev : Katoka Delete hivas uran : Kat Modositott nev : Katinka Insert eljárás Az insert eljárással sztringbe részsztringet szúrhatunk be. Az eljárás első paramétere a beszúrandó részsztring, a második paramétere a módosítandó sztring és a harmadik paramétere határozza meg, hogy a módosítás hányadik karaktertől kezdődjön. (* sztring4.pas *) program sztring4; uses crt; var s1,s2: string; begin clrscr; s1:='Ma az ido'; writeln(s1); insert(' szep',s1,3); writeln('insert utan: ',s1); end. A program eredménye: Ma az ido insert utan: Ma szep az ido Length függvény A length függvény a paraméterében megadott sztring hosszát adja vissza. A példaprogramban a length függvénnyel meghatározzuk a sztring végét és insert hívásával bővítjük a sztring tartalmát. (* sztring5.pas *) program sztring5; uses crt; var s1,s2: string; k : integer; begin clrscr; s1:='Ma az ido'; writeln(s1); insert(' szep',s1,3); writeln('insert utan : ',s1); s2:=', de hideg van.'; k:=length(s1); insert(s2,s1,k+1); writeln('Vegere toldva: ',s1); end. A program eredménye: Ma az ido Insert után : Ma szep az ido Vegere toldva: Ma szep az ido, de hideg van. Pos függvény A pos függvény segítségével sztringben részsztringet lehet keresni. A pos első paramétere a részsztring, a második paramétere az a sztring, amelyben keresünk és a függvény visszatérési értéke lehet - 0, ha a rész sztringet nem találta, - pozitív szám azt jelenti, hogy a részsztringet megtalálta a keresett sztringben, és az értéke a megtalálás helyének a pozíciója. (* postest.pas *) program postest; uses crt; var a:string[80]; begin clrscr; a:='Szovegben xx karaktersorozat keresese'; writeln('Az ''xx'' pozicioja: ',pos('xx',a)); writeln('Az ''XX'' pozicioja: ',pos('XX',a)); writeln; end. A program eredménye: Az 'xx' pozicioja: 11 Az 'XX' pozicioja: 0 Str eljárás Az str eljárásnak két paramétere van. Az első paramétere szám (integer vagy real), amelyet a második paraméterben megadott sztringbe karaktersorozattá alakít át. A egész szám paraméternél használhatjuk a mezőszélességet, valamint valós szám esetén a tizedek számára vonatkozó megadási módot is. Ha valós számnál 0 mezőszélességet adunk meg, akkor a szám egy egész és egy tizedes normált alakban jelenik meg. (* strtest.pas *) program strtest; uses crt; var i: integer; a: real; s: string[20]; begin clrscr; i:=15; str(i,s); writeln(s); str(i:4,s); writeln(s); a:=4.5; str(a,s); writeln(s); a:=0.05; str(a:0,s); writeln(s); str(a:10:2,s); writeln(s); end. A program eredménye: 15 15 4.5000000000E+00 5.0E-02 0.05 Val eljárás A Val eljárásnak három paramétere van: sztring, amelyet számmá kell átalakítani, numerikus változó (integer vagy real), amely a számértéket fogadja és egy egész típusú változó a hiba jelzésére. Ha a hibaváltozó értéke 0, akkor a konverzió hibátlan volt, egyébként az elsőnek előforduló hiba helyére mutat a sztringben. (* valtest.pas *) program valtest; uses crt; var s:string; x:real; j:integer; hiba:integer; begin clrscr; s:='1.53e-2'; val(s,x,hiba); if hiba=0 then writeln(s,' jo szam: ',x) else writeln(s,' valos szam ',hiba, '. helyen hibas…'); s:='1.5.3e-2'; val(s,x,hiba); if hiba=0 then writeln(s,' jo szam: ',x) else writeln(s,' valos szam ',hiba, '. helyen hibas…'); writeln; s:='102'; val(s,j,hiba); if hiba=0 then writeln(s,' jo szam: ',j) else writeln(s,' egesz szam ',hiba, '. helyen hibas…'); s:='10.2'; val(s,j,hiba); if hiba=0 then writeln(s,' jo szam: ',j) else writeln(s,' egesz szam ',hiba, '. helyen hibas…'); end. A program eredménye: 1.53e-2 jo szam: 1.5300000000E-2 1.5.3e-2 valos szam 4. helyen hibas… 102 jo szam: 102 10.2 egesz szam 3. heleyn hibas… Mint láttuk, a sztringek tárolása tömbben történik. Habár a sztringek kezelésére sok könyvtári függvény használható, sok esetben mégis egyszerűbb és gyorsabb, ha a tömbben való tárolást kihasználva a tömb elemein végezzük el a kívánt műveletet. Példaként írjunk eljárást, amely adott sztringben minden angol betűt nagybetűvé alakít. Az első eljárás (strup1) tömb elemein végzi el az átalakítást, míg az strup2 sztringkezelő függvényeket és eljárásokat használ. procedure strup1(var s:string); var i: integer; begin for i:=1 to ord(s[0]) do s[i]:=upcase(s[i]); end; procedure strup2(var s:string); var i: integer; c: string[1]; begin for i:=1 to length(s) do begin c:= copy(s,i,1); c:=upcase(c[1]); delete(s,i,1); insert(c,s,i); end; end; Az eljárások hívása a SZTRING8.PAS programban látható. Gyakorlat 1. Sztring hosszát változtassuk meg úgy, hogy a 0-dik elemét írjuk át chr függvénnyel, majd írjuk ki a sztring tartalmát. Mit tapasztalunk? (* sztring6.pas *) program sztring6; uses crt; var s: string; begin clrscr; s:='abcdefg'; writeln(s,' sztring hossza: ',length(s)); s[0]:= chr(4); writeln(s,' sztring hossza: ',length(s)); end. A SZTRING6.PAS program eredménye: abcdefg abcd 2. Szövegben való keresést és helyettesítést mutatja be a SZTRING7.PAS program. Értékeljük ki az eredményt… (* sztring7.pas *) program sztring7; uses crt; var Szoveg : string; Keres,helyez: string[20]; i: integer; begin clrscr; Szoveg:='Ma Kati hianyzott az orarol.'; Keres:='Kati'; Helyez:='Janos'; writeln(Szoveg); i:=Pos(Keres,Szoveg); Delete(Szoveg,i,length(Keres)); Insert(Helyez,Szoveg,i); writeln(Szoveg); end. A program eredménye: Ma Kati hianyzott az orarol. Ma Janos hianyzott az orarol. 3. Szövegben a # karaktert helyettesítsük a klaviatúráról beolvasott névvel. (* nevins.pas *) program nevins; uses crt; type str255=string; var uzenet1,uzenet2,uzenet3: string; nev: string[20]; function uzenet_ir(s,nev:string):string; var i:integer; begin i:=Pos('#',s); if i>0 then begin Delete(s,i,1); Insert(nev,s,i); end; uzenet_ir:=s; end; begin uzenet1:=' Hello, #…'; uzenet2:=' Az uzenet valtozatlan.'; uzenet3:=' Ez az uzenet, #, megvaltozott.'; clrscr; write('Adja meg a nevet: '); readln(nev); writeln(uzenet_ir(uzenet1,nev)); writeln(uzenet_ir(uzenet2,nev)); writeln(uzenet_ir(uzenet3,nev)); writeln; end. A NEVINS.PAS program eredménye: Adja meg a nevet: Kati Hello Kati… Az uzenet valtozatlan. Ez az uzenet, Kati, megvaltozott. 4. Sztringben az számok mögötti üres helyek törlése után a sztringet a val függvénnyel alakítsuk át számmmá. (* spacedel.pas *) program spacedel; uses crt; var s : string; i,code : integer; procedure BlankDel(var s: string); begin while (s[length(s)] = ' ') do Delete(s,length(s),1); end; end; begin clrscr; s:=' 33 '; writeln('sztring : <',s,'>'); BlankDel(s); writeln('BlankDel utan : <',s,'>'); Val(s,i,code); writeln('Ertek : ',i); end. A SPACEDEL.PAS program eredménye: sztring : < 33 > BlankDel utan : < 33> Ertek : 33 Ellenőrző kérdések: 1. Mire szolgál az alprogram készítése? 2. Hány fajta alprogram létezik a Pascal-ban? 3. Mit nevezünk formális és aktuális paraméternek? 4. Mit értünk érték szerinti paraméterátadás alatt? 5. Mit értünk cím szerinti paraméterátadás alatt? 6. Ismertesse a függvény általános felépítését? 7. Hol látszik, hogy a függvény milyen típusú értéket ad vissza? 8. A függvény hívási módjai? 9. Ismertesse az eljárás általános felépítését? 10. Mi a különbség a függvény és az eljárás hívása között? 11. Mi kell tennünk ahhoz, hogy egy függvény eljárás paramétere lehessen? 12. Mit jelent a forward kulcsszó és mikor kell használni? 13. Mit jelent a rekurzió? 14. Hogyan készítünk rekurzív alprogramot? 15. Mikor érdemes rekurziót használni? 16. Mit jelent a változók érvényességi köre? 17. Mit jelent a globlis és lokális változó fogalma? 18. Hogyan tárolja a Pascal a sztringet a memóriában? 19. Mit jelent a sztring hossza és hogyan lehet lekérdezni? 20. Milyen függvények és eljárások szolgálnak a sztringek kezelésére? Feladatok: 1. Irjon eljárást a téglalap kerületének és területének kiszámítására. Oldja meg a feladatot függvénnyel is és a főprogramban különféle paramé-terekkel is aktíválja. (TEGLALAP.PAS) 2. Készítsen programot a Pithagoras tétel alkalmazására. A derékszögű háromszög befogójának ill. átfogójának számítására. (PITAG1.PAS, PITAG2.PAS) 3. Irjon programot a Celsius és a Fahrenheit fokok oda- /visszaalakítására. (FC_CONV.PAS) 4. Śrjon programot, amely az alábbi n tagú sor összegét számítja ki: h= 1+ 1/2 + 1/3 + ... + 1/n (H.PAS) 5. Śrjon eljárást, amely egy adott mondatot szavaira bont és a szavakat sztring tömbben adja vissza. (MONDAT.PAS) 6. Śrjon eljárást, amely egy nxn-es tömb elemeit a főátlóra tükrözi (transzponálja), illetve egy másikat, amely az eredmény megjeleníti. (MATRIX.PAS) 7. Śrjon függvényt, amely adott karakterből adott hosszúságú sztringet állít elő. (REPCH.PAS) 8. Śrjon rekurzív függvényt a legnagyobb közös osztó meghatározására. (LKOPRO.PAS) 9. Śrjon eljárást, amely az adott számot törzstényezőire bontja. (TORZS.PAS) 10. Olvasson be egy n elemű tömböt. Śrjon eljárást és függvényt, amellyel kiszámítja az n elemű tömb átlagát. (ATLAG.PAS) 11. Śrjon rekurzív és nem rekurzív eljárást, amely 1-től n-ig kiszámítja az egész számok összegét. (SUM.PAS) 12. A 14. fejezet áttanulmányozása után írja meg a Hanoi tornyai probléma grafikus megoldását. (GRHANOI.PAS)