kategória | ||||||||||
|
||||||||||
|
||
A Turbo Pascal ciklusszervezõ utasításai
A ciklusokról általában:
A programok írása során gyakran felmerülõ probléma, hogy egy utasítást egymás után többször meg kellene ismételni. Az ilyen ismétlõdõ tevékenységek programnyelven történõ megfogalmazását 535j92f segítik a ciklusszervezõ utasítások. Általában minden magasszintû programozási nyelvben megtalálhatók ezek az utasítások. Az alacsonyszintû programozási nyelveknél (assembbly, gépi kód) egy feltételes utasítás és egy ugró utasítás kombinációjával lehet az ilyen jellegû feladatokat megoldani.
A Pascal nyelv háromféle ciklusszervezõ
utasítással segíti a programozást:
- For ciklus: akkor célszerû alkalmazni, amikor elõre ismerjük a
tevékenység (uatítások) ismétlésének számát
- While ... do ciklus: akkor célszerû alkalmazni, amikor nem tudjuk
elõre, hányszor kell a tevékenységet megismételni
- Repeat ... Until ciklus: a While ... do ciklushoz hasonlóan nem szükséges
elõre ismerni az ismétlések számát, mégis különbséget kell tennünk a két
ciklus között, a késõbbiek látni fogjuk, mi a különbség közöttük, mikor
melyiket célszerû alkalmazni.
A ciklusok felépítése, csoportosítása:
A ciklusok két részbõl épülnek fel:
- Az ismétlések számát meghatározó ciklusfej (amely általában a
ciklusutasítást, vagy annak egy részét is tartalmazza)
- Az ismétlõdõ utasítás(oka)t tartalmazó ciklusmag, amely az
ismétlõdõ tevékenység leírását tartalmazza
A ciklusfejben található az ún. ciklusfeltétel, amely meghatározza, hogy a
ciklus ismétlése milyen feltétel teljesülése esetén fejezõdik be.
A ciklusszervezõ utasításokat általában
a ciklusfeltétel kiértékelésének helye alapján szoktuk csoportosítani:
- Elöltesztelõ ciklus: A ciklusfeltétel kiértékelése a ciklusmag
lefutása elõtt történik. Ilyen a For és a While ... do ciklus.
- Hátultesztelõ ciklus: A ciklusfeltétel kiértékelése a ciklusmag után
történik. Ilyen a Repeat ... Until ciklus.
Pontos definíció, általános szabály nem
létezik arra, hogy mikor melyik ciklust érdemes alkalmazni, ezt mindig a
probléma jellege dönti el, mégis néhány szempontot érdemes figyelembe venni:
- Ha elõre tudjuk, hogy a ciklusmagot hányszor kell végrehajtani,
célszerû a For ciklust alkalmazni. (Példa: Az elsõ N db
természetes szám összegének meghatározása)
- Ha a ciklusmagot legalább egyszer végre kell hajtani, célszerû a Repeat
... Until ciklust választani. (Példa: Olvassunk be természetes számokat 0
végjelig.)
- Ha azt szeretnénk, hogy a ciklusmag csak egy feltétel teljesülése esetén
fusson le, illetve ha ez a feltétel nem teljesül, akkor a ciklusmagot egyszer
sem szeretnénk végrehajtani, célszerû a While ... do ciklust alkalmazni.
(Példa: Jelenítsük meg a képernyõn egy szöveges állomány tartalmát.)
A For ciklus:
A For ciklust akkor érdemes alkalmazni, amikor elõre meg tudjuk határozni az ismétlések számát. A For ciklus elõltesztelõ ciklus. A For ciklust két formában alkalmazhatjuk:
For ciklusváltozó:= kezdõérték to végérték do ciklusmag;
illetve
For ciklusváltozó:= kezdõérték downto végérték do ciklusmag;
Az elsõ változat esetén a ciklusváltozó
értéke növekedni fog (minden ismétléskor 1-gyel), amíg el nem éri a végértéket.
A második változatnál a ciklusváltozó értéke minden ismétléskor 1-gyel csökken,
amíg el nem éri a végértéket. A do foglalt szó után következõ ciklusmag
egy utaítást tartalmazhat, ha több utasítást szeretnénk a ciklusmagban
elhelyezni, a begin ... end; utasításokat kell alkalmaznunk. A ciklusmag
ismétléseinek száma a következõképpen határozható meg:
- növekvõ (to) ciklus esetén: ismétlésszám=végérték-kezdõérték
- csökkenõ (downto) ciklus esetén:
ismétlésszám=kezdõérték-végérték
A For ciklusmagjának utasításai csak akkor
kerülnek végrehajtásra, ha:
- növekvõ (to) ciklus esetében teljesül a kezdõérték<=végérték
- csökkenõ (downto) ciklus esetében teljesül a
kezdõérték=végérték
feltétel.
Egyébként a ciklusmagban elhelyezett utasítás(ok) egyszer sem kerülnek
végrehajtásra.
A For ciklus esetében a ciklusváltozó értékének változtatása automatikusan történik, a ciklusmag minden egyes végrehajtása után növekszik vagy csökken az értéke. Ezért a ciklusmagon belül nem "illik" a ciklusváltozó értékét megváltoztatni, mert ez a ciklus mûködését kiszámíthatatlanná teszi. Az elméleti lehetõsége azonban adott, a ciklusváltozó értéke a ciklusmagon belül megváltoztatható, szintaktikai hibát nem okoz (legrosszabb esetben végtelen ciklust hozunk létre). A For ciklus ciklusváltozója - az automatikus léptetés miatt - csak sorszámozott tipus lehet, más tipusok esetén 97-es kódú hibát kapunk a program fordítása során, a fordító jelzi, hogy ilyen tipusú változó a For ciklusnál nem használható.
A For ciklust alkalmazzuk általában a tömbök
kezelése során, összegzéskor, stb.
Példák a For ciklus alkalmazására:
Számítsuk ki az elsõ N db természetes szám összegét!
Var N: integer;
Sum: longint;
Begin
Write('N= ');
Readln(N);
For N:=0 to N do
Sum:= Sum+N;
Writeln('Az elso ', N, ' termeszetes szam osszege: ', Sum);
End.
Töltsünk fel egy 10 elemû tömböt [1..90] közé esõ véletlenszámokkal!
Var Tomb: Array [1..10] of integer;
I: byte;
Begin
Randomize;
For I:= 1 to 10 do
Begin
Tomb[I]:=
Random(90)+1;
Writeln('A
tomb ', I, '. eleme: ', Tomb[I];
End;
End.
Mivel a For ciklus magjában több utasítást is
elhelyeztünk, szükséges volt azokat a Begin ... End; közé elhelyezni. A
Randomize utasítás a véletlenszámok generálását teszi lehetõvé, a Random
függvény pedig a véletlenszámokat állítja elõ. A Random(MAX) függvény
egy [0..MAX-1] intervallumba esõ egész számot ad vissza, ezért kell 1-et
hozzáadni.
A While
... do ciklus:
A While ... do ciklus a For ciklushoz hasonlóan
elõltesztelõ ciklus, de az elõbbivel szemben nem
kötelezõ a ciklusba lépéskor meghatározni a ciklus iterációinak
(ismétlésének) számát. A While ... do ciklus szintaktikája:
While ciklusfeltétel do
utasítás;
A ciklusmag addig ismétlõdik, amíg a
ciklusfeltétel igaz. A For ciklushoz hasonlóan a ciklusmag itt is egy
utasításból áll, ha több utasítást szeretnénk a ciklusmagban szerepeltetni,
akkor a Begin ... End; foglalt szavak között kell õket elhelyezni. A
While ... do ciklus esetében - szemben a For ciklussal, amely ilyen értelemben
rendhagyó - a ciklusfeltétel értékét nekünk kell változtatni a ciklusmagon
belül! Amennyiben ezt nem tesszük meg, és a ciklusfeltétel igaz értéke a
ciklusmagon belül nem változik meg, akkor végtelen ciklust kapunk. Nagyon
gyakori hibalehetõség!
A While ... do ciklus ciklusmagjának utasításai csak akkor kerülnek
végrehajtásra, ha a ciklusba lépéskor a ciklusfeltétel igaz. Amennyiben a
ciklusfeltétel hamis, a ciklusmag végrehajtása egyszer sem történik meg.
A While ... do ciklus ciklusfeltétele egy logikai kifejezés vagy változó (nem
véletlenül írtam ebben a sorrendben az elsõt sokkal gyakrabban
használjuk). Ha más tipust szeretnénk alkalmazni ciklusfeltételként a fordító
40-es hibaüzenetet küld, amely azt jelzi, hogy a fordító logikai tipusú
kifejezést vagy változót vár az adott helyen.
A While ... do ciklust általában filekezelésnél használjuk, mert ha egy üres állományból olvasunk, az EOF függvény tesztelésével már a ciklus elején kiszûrhetjük ezt az információt, a program nem fut feleslegesen (programtól függõen minimum 5-6 utasítás végrehajtásának idejét megspórolhatjuk).
Példák a While ... do ciklus alkalmazására:
Olvassunk be egy számot, döntsük el, prímszám-e:
Var A: Integer;
O: Integer;
Prim: Boolean;
Begin
Write('Kerek egy egesz szamot: ');
Readln(A);
Prim:= True;
O:= 2;
While (O<Sqrt(A)) do
Begin
if (A mod
O)=0
then Prim:= False;
O:= O+1;
End;
If Prim
then Writeln('Primszam')
else Writeln('Nem primszam');
End.
A szám beolvasása után egy ciklust futtatunk,
amelyben vizsgáljuk, hogy a szám osztható-e maradék nélkül valamely
1-tõl és önmagától különbözõ számmal (ezért O:= 2, a
ciklusváltozó indulóértéke). A ciklus akkor ér véget, ha elérjük a szám
négyzetgyökét (O<Sqrt(A)). A ciklusba lépés elõtt a számról feltételezzük,
hogy prim, ezért az ún. jelzõváltozó (Prim) értékét igazra állítjuk. Ha
a ciklus futása során találunk olyan számot, amellyel az A szám maradék nélkül
osztható, a jelzõváltozó értékét hamisra állítjuk, mert mostmár tudjuk,
hogy a szám nem prímszám. Ha nem találunk ilyen számot, a jelzõváltozó
értéke a ciklus végéig nem változik. A ciklusból kilépve a Prim változó értéke
alapján tudjuk eldönteni, hogy elõfordult-e olyan szám, amely valódi
osztója volt a beolvasott számnak.
Írjuk ki a képernyõre az AUTOEXEC.BAT állomány tartalmát:
Var F: Text
S: String;
Begin
Assign(F, 'C:\AUTOEXEC.BAT');
Reset(F);
While (not Eof(F)) do
Begin
Readln(F, S);
Writeln(S);
End;
Close(F);
End.
A példban a While ... do ciklus alkalmazása
volt a legcélszerûbb, mert amennyiben az állomány üres, akkor a ciklusmagot
figyelmen kívül hagyta volna a program. A For ciklust nem tudtuk volna
alkalmazni, mert nem tudjuk elõre megmondani, hogy az állomány hány sort
tartalmaz (nem tudtuk volna hol fejezzük be a ciklust!). A ciklusfeltétel: az
Eof függvény akkor ad vissza igaz értéket, ha a file végén állunk
(bõvebben lásd a filekezelésnél), ezt a kifejezést nyilván "meg
kell fordítanunk", negálnunk kell, ezt a not operátor segítségével tettük
meg.
A Repeat ... Until ciklus:
A Repeat ... Until ciklus a Pascal nyelv egyetlen hátultesztelõ ciklusa. A While ... do ciklushoz hasonlóan nem kötelezõ elõre meghatározni az iterációk számát. A Repeat ... Until ciklus szintaktikája:
Repeat
utasítás_1;
utasítás_2;
.
.
.
utasítás_n;
Until ciklusfeltétel;
A ciklusmag addig ismétlõdik, amíg a
ciklusfeltétel hamis. Az eddigi ciklusutasításokhoz képest eltérés, hogy a
ciklusmag több utasítást is tartalmazhat, a Begin ... End; utasítászárójelek
használata lehetséges, de nem kötelezõ. A ciklusfeltétel értékét ennél a
ciklustipusnál is nekünk kell változtatni, nincs automatikus léptetés. A
ciklusfeltétel változtatása itt is a ciklusmagon belül kell történjen,
elmulasztása hasonó hibákat okoz, mint a While ... do ciklus esetében.
A Repeat ... Until ciklus ciklusmagja minden esetben végrehajtásra kerül
legalább egyszer, akkor is, ha a ciklusfeltétel a ciklusba lépéskor már igaz
(ebben az esetben azonban a ciklusmag megismétlésére nem kerül sor).
A Repeat ... Until ciklus ciklusfeltétele egy logikai kifejezés vagy változó
(hasonlóan a While ... do ciklushoz, itt is gyakrabban fordul elõ a
kifejezés). Ha más tipust szeretnénk alkalmazni ciklusfeltételként a fordító
40-es hibaüzenetet küld, amely azt jelzi, hogy a fordító logikai tipusú
kifejezést vagy változót vár az adott helyen.
A Repeat ... Until ciklust általában akkor alkalmazzuk, ha több adat beolvasására kerül sor, és az adatsor végét végjel határozza meg, ha a program végén szeretnénk várni egy billentyû leütéséig kilépés elõtt, vagy ha valamilyen több lépésbõl álló tevékenységet szeretnénk egymás után többsször végrehajtani (lásd a Pascal feladatoknál a grafikus példák 8. feladatát!).
Példák
a Repeat ... Until ciklus alkalmazására:
Olvassunk be egész sztámokat 0 végjelig, határozzuk meg a számok átlagát.
Var X, N: Integer;
Sum: Longint;
Begin
Writeln('Egesz szamokat olvasunk be 0 vegjelig.');
N:= 0;
Sum:= 0;
Repeat
Write('X= ');
Readln(X);
Sum:= Sum+X;
N:= N+1;
Until X=0;
Writeln('A beolvasott szamok atlaga: ', Sum/(N-1):10:2);
End.
Az egész számokat nem szükséges külön-külön
tárolnunk, a feladat szempontjából erre nincs szükség, ezért nem alkalmazunk
tömböt. A számokat az X nevû változóba fogjuk beolvasni. Mielõtt a
ciklust elkezdenénk futtatni, a ciklusban felhasznált változók értékeit
beállítjuk (N:= 0; - eddig egyetlen számot sem olvastunk be, Sum:= 0; - a
beolvasott számok összege 0).
A ciklusban számoljuk a beolvasott számokat (N), és a számok összegét is (Sum).
A ciklus akkor ér véget, amikor 0 kerül beolvasásra. Az átlag számításánál a
számok számából el kell venni 1-et, mert a ciklus a 0 beolvasásakor is növelte
N értékét, a végjelet pedig általában nem szoktuk a számításnál figyelembe
venni.
:
1613