XI. Ciklusok

A REXX-ben használatos ciklusok fajtái

Korábban már volt szó a DO-END párosról, amely segítségével szerkezetek csoportját definiáljuk. A DO-END ugyanakkor egymás után többször is végrehajtott szerkezetcsoportok, más szóval ciklusok megvalósítására is felhasználható. A legtöbb ciklus feltételvezérelt. Ez azt jelenti, hogy egy feltétel határozza meg, hogy mikor fejezôdjön be a ciklus. Amikor a feltétel a ciklus elején kerül kiértékelésre, akkor do-while típusú ciklusról van szó, ami azt jelenti, hogy a ciklus addig kerül végrehajtásra, amíg a feltétel teljesül. Ennek az ellentettje a do-until konstrukció, amikor a feltétel a ciklus törzsének végrehatása után kerül megvizsgálásra. Ha a feltétel nem teljesül, akkor a ciklus törzse újra végrehajtódik, egészen addig, amíg a feltétel igazzá nem válik. Lényeges különbség a két forma között, hogy a do-until esetben a ciklus törzse legalább egyszer végrehatásra kerül, míg a do-while ciklus esetében ez egyáltalán nem garantált. Egy harmadik típus a számlálóhoz kötött ciklus. Ebben az esetben elôre megadjuk, hogy hányszor akarjuk végrehajtani a törzset és ezt egy számlálóval kontrolláljuk. Egyes programnyelvekben a számláló definiálásáról, értékének növelésérôl és a határérték elérésének vizsgálatáról a programozónak kell gondoskodni. Ebben az esetben nem is nagyon van értelme errôl a harmadik típusról külön megemlékezni, mivel ez tulajdonképpen visszavezethetô az elôzô két típus valamelyikére:

szam = 0
DO WHILE szam < 10
	SAY 'I am busy!'
	szam = szam + 1
END

A REXX-ben szerencsére a számlálóval nem kell külön törôdnünk, mivel a fenti feladat e nélkül is megvalósítható:

DO 10
	SAY 'I am busy!'
END

A do-while és do-until ciklusok

A REXX programokban a do-while és do-until típusú ciklusok a DO WHILE END, illetve a DO UNTIL END utasításhármassal valósíthatók meg. Az elôzôekben láttunk már egy példát a DO WHILE END használatára, amikor a számlálókhoz kötött ciklusokról volt szó. Most lássunk egy komolyabb példát a DO UNTIL END alkalmazására. Az alábbi példában szereplô program bankszámlánk egyenlegét tartja nyílván:

/* Egyenlegszámítás */

SAY ''
SAY 'Kérem az induló egyenleget!'
PULL egyenleg
SAY 'A tranzakciókat a  <összeg> formában kell megadni!'
SAY 'A következô kódok használhatók: F - pénz felvétel'
SAY '                                B - pénz berakás'
SAY '                                E - egyéb kiadás'

DO UNTIL kod = ''
	SAY Right('Egyenleg:', 20) Format(egyenleg,,2)'Ft'
	PARSE UPPER PULL kod osszeg
	SELECT
	WHEN kod = 'F' THEN
		egyenleg = egyenleg - osszeg
	WHEN kod = 'B' THEN
		egyenleg = egyenleg + osszeg
	WHEN kod = 'E' THEN
		egyenleg = egyenleg - osszeg
	OTHERWISE
		NOP;
	END
END

EXIT

A futtatáskor a program bekéri a nyitó egyenleget, majd elkezdi végrehajtani a ciklus törzsében található utasításokat. A ciklustörzs minden egyes végrehajtásakor kiírja az aktuális egyenleget és vár a következô tranzakcióra. A tranzakciók a SELECT utasításban megadott kódok alapján befolyásolják az egyenleget. A hibás beviteli adatokat a program figyelmen kívül hagyja. A ciklus akkor fejezôdik be, amikor a felhasználó üres sort visz be.

Számlálók

Az elôzôekben már említettük, hogy a ciklusok egy részét számláló vezérli. Ez azonban fordítva is igaz lehet, mivel sokszor pontosan azért hozunk létre ciklusokat, hogy valamit számláljunk velük. A számlálóval vezérelt ciklusok kiemelkedô szerepük miatt külön csoporttá nôtték ki magukat a REXX-ben. A DO TO BY FOR END utasítások variálásával a számlálóvezérelt ciklusok igen változatos példányait fogalmazhatjuk meg könnyen és tömören. A leggyakrabban használt párosítás a DO TO END:

DO i = 1 TO 5
	SAY i
END

Ebben az esetben egyszerûen arról van szó, hogy 5-ször hajtjuk végre a ciklust, mivel 1-tôl 5-ig számlálunk az i-vel. Ha nem egyesével akarjuk a számláló értékét növelni, akkor a növekedés értékét a BY utasítással adhatjuk meg:

DO i = 1 TO 9 BY 3
	SAY i
END

Itt 3-szor fog a ciklus lefutni, mivel 1-tôl számolunk 9-ig, 3-as növekedéssel. A BY paramétere lehet negatív is. Ekkor minden lépésben csökkenni fog a számláló értéke a BY után megadott negatív szám abszolút értékével:

DO i = 10 TO 1 BY -1
	SAY i
END

Egy másik lehetôség a FOR használata, amellyel kerek-perec megmondhatjuk, hogy hányszor akarjuk a ciklust végrehajtani:

DO i = 1 BY 3 FOR 5
	SAY i
END

Ebben az esetben tehát ötször fut le a ciklus. A számláló értéke 1-rôl indul és ötször növekszik 3-mal. Elvileg a FOR és a TO egy szerkezetben is használható. Ekkor a ciklus végrehajtása akkor fog leállni, amikor az egyik szabályozó feltétel teljesül. A számláló nevét megadhatjuk a ciklust lezáró END paramétereként. Ez hasznos lehet akkor, ha egymásba ágyazott ciklusokkal dolgozunk:

DO i = 1 TO 9 BY 3
	DO j = 1 FOR 4
		SAY i j
	END j
END i

Ilyen esetben ügyelnünk kell arra, hogy ne cseréljük fel a számlálókat az END utasítások mellett, mivel akkor szintakszis hibát fog jelezni az értelmezô.

Végtelen ciklusok

A végtelen ciklusok általában úgy jönnek létre, hogy olyan feltételtôl tesszük függôvé a ciklusból való kilépést, amely sohasem teljesül:

i = 1
DO WHILE i < 5
	SAY i
END

A fenti példában az i értéke a ciklus végrehajtása alatt végig 1 marad, így a kilépést kontrolláló feltétel (i < 5) végtelen ideig igaz marad. Egy ilyen ciklusból csak akkor tudunk kiszabadulni, ha megszakítjuk a program futását a CTRL-BREAK megnyomásával. Egy másik (hiba)lehetôség végtelen ciklus létrehozására a TO vagy FOR nélküli BY:

DO i = 1 BY 2
	SAY i
END

A végtelen ciklusok azonban hasznosak is tudnak lenni. Ha például nem tudjuk elôre, hogy hányszor kell egy ciklust végrehajtani (pl. várunk egy bizonyos billentyû leütésére), akkor általában kénytelenek vagyunk a várakozást végtelen ciklussal megoldani és valamilyen más módon gondoskodunk róla, hogy a kérdéses billentyû megnyomásakor mégiscsak elhagyjuk a ciklust. Ha szándékosan hozunk létre végtelen ciklust, akkor azt lehetôleg a DO FOREVER konstrukcióval tegyük:

DO FOREVER
	SAY 'Ez itt egy szándékos végtelen ciklus!'
END

Kiugrás a ciklusokból

Mint ahogy azt a szándékosan létrehozott végtelen ciklusok esetében is láttuk, idônként szükség lehet arra, hogy a ciklusból egy ún. kiskapun keresztül is kiléphessünk. Erre az esetre hozták létre a LEAVE utasítást, mely végrehajtása azonnal leállítja a ciklus futását:

DO FOREVER
	SAY 'Ez itt egy szándékos végtelen ciklus, amelybôl'
	SAY 'csak a STOP paranccsal lehet kilépni.'
	PULL parancs
	IF parancs = 'STOP' THEN LEAVE
END

Egymásba ágyazott ciklusok esetén, a ciklus számlálóját a LEAVE paramétereként megadva szabályozhatjuk, hogy melyik ciklusból ugorjunk ki:

DO i = 1 TO 25
	DO j = 1 TO 100
		IF i * j > 100 THEN LEAVE i
	END j
END i

A fenti példában i-t adtuk meg paraméternek, ezért mindkét ciklusból kiugrunk, ha az i*j > 100 feltétel teljesül. Egy másik hasznos ciklusokkal kapcsolatos utasítás az ITERATE. Ezt akkor szoktuk használni, amikor valamilyen feltétel teljesülése esetén nem akarjuk már a ciklus maradék részét végrehajtani, hanem kezdeni akarjuk a következô iterációt. Azt is lehet mondani, hogy az ITERATE utasítással a vezérlés egybôl a ciklus elejére ugrik. A következô példában az ITERATE használatával kikerüljük a SAY utasítás végrehajtását:

DO 1000
	SAY 'Eleged van már?'
	PULL valasz
	IF valasz <> 'YES' THEN ITERATE
	SAY 'Nem hinném!'
END

Az ITERATE utasítást szinte mindig az IF vagy a SELECT utasítások valamelyikével kombináljuk. A LEAVE használatával kapcsolatban annyit érdemes megjegyezni, hogy lehetôleg kerülni kell alkalmazását, mivel a GOTO-hoz hasonlóan nehezen áttekinthetôvé teszi a programot. Csak akkor használjuk, ha ezzel jelentôsen egyszerûsíthetô a program!


REXX GYÍK:

K1. Hogyan döntsem el, hogy WHILE vagy UNTIL típusú ciklust használjak?
V1. Ökörszabályként azt lehet mondani, hogy ez attól függ, hogy a ciklus törzsét a ciklusfeltétel ellenôrzése elôtt vagy után kell végrehajtatni. Ha ez mellékes és a két megvalósítási forma bonyolultsági fokát tekintve sincs lényeges különbség, akkor használjunk WHILE ciklust!

K2. Miért nem csinál a DO i = 1 to 10 BY -1 semmit?
V2. A kiértékeléskor az értelmezô elôször megnézi a BY paraméterének elôjelét, hogy megállapítsa, hogy melyik irányba kell változtatni a számláló értékét. Ezután összehasonlítja a számláló kezdô és végértékét. Ebben az esetben azonban a kezdôérték már eleve kisebb, mint a végérték, így további csökkentésnek már nincs semmi értelme.


Gyakorlatok:

1. A következô program egy háromszöget nyomtat ki. Alakítsa át a programot, hogy a háromszög a 'feje tetejére' forduljon!

/* Háromszög */
string = '*********'
DO i = 1 TO Length(string) BY 2
	SAY Center(Left(string, i), Length(string))
END
EXIT

2. Készítsen egy programot, amely bekér egy pozitív egész számot és egészen addig ismétli a kérést, amíg a felhasználó a feltételeknek eleget tevô adatot nem visz be!

3. Készítsen egy programot, amely bekér egy karakterláncot és megszámolja a karakterláncban található mássalhangzókat!

Kádár Zsolt
1998. 04. 18.
[ Elôzô lecke | Következô lecke | Tartalom ]