Ciklusok szerkesztés

A ciklus, vagy iteráció a számítógép-programozás és az algoritmusok egyik alapvető eszköze, amely az ismétlődő (azonos vagy hasonló) tevékenységek megvalósítására szolgál. A ciklus beépítését a programba ciklusszervezésnek is nevezik. A ciklust az egyes programozási nyelvek különböző kulcsszavakkal valósítják meg.

Típusai szerkesztés

A ciklus részei szerkesztés

Alább egy egyszerű BASIC nyelvű ciklust láthatunk, amelyik 2-től 5-ig egyesével haladva kiírja a számokat és a négyzetüket:

FOR i=2 TO 5 STEP 1
 PRINT i," négyzete: ",i*i
NEXT i

Ebben a ciklusban az i a ciklusváltozó, amely a ciklus kezdetén értéket kap. A szerepe kettős: egyrészt vezérli a ciklust, mivel a ciklusváltozó értékétől függ, hogy folytatódik-e a futás, másrészt a pillanatnyi értéket a program felhasználja. A ciklus futásának kezdetén tehát az i értéke 2 lesz; mivel ez kisebb, mint 5, ezért a ciklusmag lefut, vagyis a program kiírja a képernyőre a

2 négyzete: 4

sort. Ezután i értéke 3-ra változik, és ismét lefut. Ez addig ismétlődik, amíg az i értéke 5 lesz. Ekkor még utoljára lefut a ciklus, tehát a képernyőn még megjelenik az 5 négyzete is, majd az i értéke 6 lesz, de ez már nagyobb, mint 5, ezért a program kilép a ciklusból, és a futás a következő sorral folytatódik.

Ebben a ciklusban a ciklusváltozónak van kezdőértéke (2), végértéke (5) és lépésköze (1). Nem minden ciklusban van ciklusváltozó. Egyes programnyelvekben több is lehet belőle.

A ciklus első sorát ciklusfejnek nevezik. Általában ez vezérli a ciklust; itt kap helyet a ciklusváltozó(k) definíciója, valamint a futási feltétel is. A középső sor a ciklusmag, vagyis a ténylegesen ismétlődő utasítások meghatározása. Ennek a ciklusnak a magja egyetlen utasításból áll. Végül az utolsó sor a ciklusvég; az elöl tesztelő és a számlálós ciklus esetében ez puszta lezáró utasítás, amely a ciklusmag végét jelzi (egyes programnyelvekben esetenként el is maradhat), a hátul tesztelő ciklus esetén pedig ez a rész tartalmazza a futási feltételt.

Feltételes ciklusok (WHILE) szerkesztés

A feltételes ciklusok olyankor használatosak, amikor nem ismert előre, hogy hányszor kell a ciklusnak lefutnia. Azt viszont tudjuk, hogy milyen feltétel teljesülése esetén kell tovább futnia vagy leállnia. (Ez a kettő egymással ekvivalens, hiszen a további futás, illetve a leállás feltétele egymás tagadása.) A feltétel teljesülését vizsgálhatjuk a ciklusfejben vagy a ciklusvégben is; a különbség abban fog állni, hogy legalább egyszer lefut-e a ciklus.

Elöl tesztelő ciklus szerkesztés

 

Az elöl tesztelő ciklus sémája:

Ismételd, amíg a feltétel igaz
  utasítások
ciklus vége

Az elöl tesztelő ciklus tehát először megvizsgálja, hogy a feltétel fennáll-e. Ha igen, akkor lefuttatja a ciklusmagot, és újból kezdődik; ha nem, akkor a program a ciklus utáni ponton folytatódik, azaz a ciklusmag kimarad. Lehetséges tehát, hogy az elöl tesztelő ciklus egyszer sem fog lefutni.

Az elöl tesztelő ciklus tipikus példája az adatállományok beolvasása; előfordulhat ugyanis, hogy az állomány üres, és ilyenkor nincs mit beolvasni. Hasonló a helyzet a könyvtárak listázásakor is, hiszen a könyvtárban nem biztos, hogy van állomány.

Az elöl tesztelő ciklus tipikus kulcsszava a while. Általános alakja a következő:

while(feltétel){
	utasítás(ok);
}

Példa (awk):

while (i<10){
 print i;
}

Hátul tesztelő ciklus szerkesztés

 

A hátul tesztelő ciklus sémája:

Ismételd
  utasítások
amíg a feltétel igaz

Mivel a feltételvizsgálat a ciklusmag után áll, ezért a hátul tesztelő ciklus legalább egyszer mindenképpen lefut.

A konkrét programnyelvi megvalósítástól függ, hogy a hátul tesztelő ciklusban a folytatás vagy a kilépés feltételét kell-e megadni. A ciklus az első esetben addig fut, amíg a ciklusvégben megadott feltétel igaz (ennek tipikus kulcsszava a while), a másik esetben pedig addig, amíg igazzá nem válik (tipikus kulcsszava az until).

Általános alakja a következő:

do
{
    utasítás(ok);
}while(feltétel);

Jellemző példa a hátul tesztelő ciklusra az adatbevitel ellenőrzése. Tegyük fel, hogy regisztrálni szeretnénk egy ingyenes postafiókot az interneten. A szerveren futó programnak először ellenőriznie kell, hogy szabad-e még a választott azonosító, majd azt is, hogy kitöltöttük-e az összes kötelező adatmezőt, és addig kell ismételnie ezt a lépést, amíg az összes adat helyessé nem válik. Sok szolgáltató ezt egy lépésben végzi el, vagyis először ki kell töltenünk az űrlapot, aztán tudjuk meg, hogy szabad-e még az azonosító. Ebben az esetben a ciklus a következőképpen nézhet ki:

Ismételd
 Olvasd be az adatokat
 Ha az azonosító foglalt, írd ki, és add vissza az űrlapot
 Ha egy kötelező mező hiányzik, írd ki, és add vissza az űrlapot
amíg hibás az űrlap

Mivel a feltételt csak az adatbeolvasás után ellenőrzi a program, ezért az adatok beolvasása legalább egyszer mindenképpen megtörténik. Ha sikerült elsőre jól kitölteni az adatlapot, akkor tovább lehet lépni.

Zavart okozhat a szöveges leírásokban a magyar amíg szó két, egymással lényegében ellentétes jelentése. Az algoritmusok leírásában az amíg szót mindig a 'mialatt', 'miközben' értelmében használjuk, ami az angol while-nak felel meg. A fenti eljárást úgy is fogalmazhatnánk, hogy „olvasd be az adatokat, ahányszor kell, amíg jók lesznek” – ebben az esetben az amíg szót az angol until értelmében használtuk, ami szintén lehet a hátul tesztelő ciklus kulcsszava. Ezért előfordulhat, hogy a programkódban épp a szöveges algoritmusban látható feltétel tagadását kell megfogalmaznunk.

Számláló (FOR) ciklus szerkesztés

 

A számláló ciklus általánosságban olyan elöl tesztelő ciklust jelent, amely egy felsorolható típus adott intervallumán léptet végig, speciálisan egész számokon. Üres intervallumra nem fut le.

C-ben a for ciklus majdnem teljesen ekvivalens az elől tesztelő ciklussal, de más nyelvekben nem feltétlenül van ez így: a for ciklus átírható más ciklussá, de visszafelé általában nem. A for ciklusnak kisebb lehet a kifejezőereje, de könnyebb olvasni: ezért a használata javasolt minden olyan esetben, ahol csak lehetséges.

Számok összegzése forciklussal C-ben:

int sum = 0; // Kezdetben a szumma 0
int i;
for(i=0; i<200; ++i) // Kezdőérték; feltétel; növelés
   sum += i; // Az i hozzáadása sum-hoz

Számok összegzése whileciklussal C-ben:

int sum = 0;
int i = 0;
while(i<200){
    sum += i;
    ++i;
}

Az ADA nyelvben ez nem áll fent, a for ciklus itt egy szigorúan kötött, ellenőrzött konstrukció, például nem lehet a ciklusváltozót változtatni:

for I in 1..200 loop
  SUM := SUM + I;           --első 200 szám összege, ADA for ciklussal
end loop;

Iteráló ciklus (FOR IN, FOREACH) szerkesztés

Egyes nyelvekben a foreach kulcsszót kell használni. Arra való, hogy egy egy tároló (pl.: tömb, lista, bináris fa, stb., stb.) elemeit bejárjuk. Erre egy egyszerű példa PHP-ban:[1]

$arr = array(1, 2, 3, 4);   // Tömb az 1,2,3,4 számokból
foreach ($arr as &$value) { // A tömb bejárása
    $value = $value * 2;    // Minden elem megszorzása 2-vel
}
// A $arr elemei itt rendre 1, 2, 3 és 4

Egy lista bejárása (AutoLISP):

(foreach n '(a b c) (print n))

Egyenértékű a

(print a)
(print b)
(print c)

megadásával. Mivel egy lista elemszáma nem kötött, az előny nyilvánvaló.

Néhány programozási nyelv a for inutasítással valósítja meg a tömbök, listák bejárását, pl. awk: (már létezik a szavak nevú tömb)

for (x in szavak) {
     if (length(x) > 12) { # ha a szó hosszabb, mint 12 karakter
         print x           # akkor kiírjuk
      }
}

Ez a példa egy MS-DOS kötegelt állományában szerepel, és törli az aktuális könyvtárból az ideiglenes állományokat néhány tipikus kiterjesztés alapján:

 for %%c in (*.bak *.tmp *.$$$ *.wbk) do del %%c

Beavatkozás a ciklus menetébe szerkesztés

Egy ciklus menetébe beavatkozni többféleképpen lehet:

  • a ciklusváltozó növelésével, ill. csökkentésével;
  • a break utasítással;
  • a continue utasítással.

Mindhárom módszer használható a for és a while segítségével létrehozott ciklusokban. Az egyetlen követelmény, hogy a ciklus törzén belül kell elhelyezni,különben hibajelzést kapunk.

Ciklusváltozó módosítása szerkesztés

Gyakran előfordul, hogy n darab különböző számot kell generálnunk vagy bekérnünk. Ilyenkor kézenfekvő a for ciklus használata, ugyanakkor ismétlődés vagy hibás adat esetén szükség lehet a visszalépésre.

using namespace std;
set<int> lottoSzamok;
for(int i=0; i<5; ++i) {
    int aktualis;
    cout << (i+1) << ". lottó szám: ";
    cin >> aktualis;
    if(aktualis>=1 && aktualis<=90 && lottoSzamok.find(aktualis)==lottoSzamok.end()){
        lottoSzamok.insert(aktualis);
    } else {
        cerr << "A szám nem megfelelő vagy már volt." << endl;
        --i;  // visszalépés
    }
}

A BREAK utasítás szerkesztés

Ez a speciális, ciklusok esetén használható utasítás azonnal megszakítja a ciklus futását, és függetlenül a ciklus vezérlő feltétel értékétől, függetlenül minden mástól azonnal (erőszakosan) befejezi a ciklus futását. A program futása ettől nem szakad meg, folytatódik a ciklusra rákövetkező utasítás végrehajtásával.

A CONTINUE utasítás szerkesztés

A break-hez hasonló utasítás a code<>continue. Ennek használata esetén a ciklus futása nem szakad meg (fejeződik be) mint a break, sőt, ellenkezőleg. A continue hatására a ciklusmag maradék utasításai ebben a menetben már nem hajtódnak végre, de a ciklus futása folytatódik, mintha elértük volna a ciklusmag végét, vagyis újra a vezérlő feltétel kiértékelése következik. Például szeretnénk kihagyni az 1234-es irányítószámot:

kimarad = 1234;
start = 1230;
end = 1240;

for(i= start; i<=end; i++){
 if(i== kimarad){continue} else{ 
   print i,"\n";
 }
}

A continue utasítás pl. menük ,,kiszürkítésére" is jól használható.

Néhány nevezetes alkalmazás szerkesztés

Egymásba ágyazott ciklusok szerkesztés

Egymásba ágyazott ciklusokat tipikusan akkor szoktunk használni, amikor egy területen (például egy kép képpontjain, vagy egy mátrixon) kell műveleteket végeznünk. Bizonyos rendező algoritmusok (pl. buborékrendezés) is egymásba ágyazott ciklusokat használnak. Egy számtáblázat celláinak az összegzése pl. így néz ki:

int **t,n,m;
// <-- Beolvasás n-be, m-be (méretek) és t-be
int sum = 0;
for(int i=0; i<n; ++i)
    for(int j=0; j<m; ++j)
        sum = sum + t[i][j];
std::cout << "A cellák összege: " << sum << std::endl;

A ciklusokat használó programok rendszerint korllátozzák a ciklusok egymásba ágyazhatóságának számát. Egyrészt a kiértékelések száma hatványozódik, ami drámaian megnöveli a program futásidejét (kibírhatatlanul lassúvá válik). Másrészt pedig a kiértékeléshez használt veremtár betelhet a sok átmeneti adattól, ami pedig a program működését akadályozza meg (elszáll a program).

A végtelen ciklus szerkesztés

A végtelen ciklus olyan ciklus, melynek futása külső esemény bekövetkezte nélkül sohasem zárulna le.

Játékok és egyéb eseményvezérelt programok (például szolgáltatások) használják, szerepe miatt főciklusnak (angolul main loop vagy event loop) szokták nevezni. Bizonyos események hatására (pl. a felhasználó ESC-et nyom) mégis megszakítsák saját futásukat, azaz kilépjenek a végtelen ismétlésből hagyományos módon vagy kitörjenek pl. goto vagy break használatával.

Hagyományos

bool escLenyomva = false;
for(;!escLenyomva;){
    // Lenyegi rész
    // Ha esc-et nyomnak, akkor escLenyomva = true
}

Kitörés

for(;;){
   // Lenyegi rész
   // Ha esc-et nyomnak, akkor break;
}

Végtelen ciklusnak neveznek egy ciklust akkor is, ha a programozónak más volt a szándéka, de mégis olyan ciklust sikerült írnia amely néhány (esetleg mindegyik) helyzetben nem lép ki. Tágabb értelemben véve végtelen ciklus több résztvevővel is kialakulhat, amikor például két vagy több párhuzamosan futó program újra és újra ugyanazt a kommunikációt ismétli meg egymás között vég nélkül.

A vakciklus szerkesztés

Vak- vagy várakozó ciklusnak az olyan ciklust nevezik, amelynek a magja üres. Az ilyen ciklusokat a program futásának lassítására vagy várakozáshoz szokták használni.

Például az ABC 80 BASIC nyelve nem tartalmazott várakozó utasítást. Időnként szükség lehet egy program futásának szándékos szüneteltetésére. Ilyen lehet például a képernyőre írás után vagy egy játékprogram, ahol különböző nehézségi szintek vannak megadva. Az alábbi számláló ciklus elszámol tízezerig, és ezzel lassítja a futást.

FOR I=10 TO 10000
NEXT I

Hasonló példa a Pascalban írt alábbi hátul tesztelő végtelen ciklus is, amely egy billentyű lenyomására várakozik (addig ismétli a semmit, amíg egy billentyűt meg nem nyomnak).

repeat until keypressed;

A többfeladatos operációs rendszerek általános elterjedése óta a vakciklusok nem igazán jó megoldások időzítésre vagy várakozásra, mert pazarolják a processzort mint erőforrást. Azonban manapság is szükség lehet erre a módszerre, amikor a feladatváltás időköltségénél kevesebbet szeretnénk várakozni.

Üres ciklus szerkesztés

Üresnek neveznek egy ciklust akkor, ha a magja egyszer sem fut le.

Ciklus ugró utasítással (GOTO) szerkesztés

Ugró utasítással akkor lehetséges ciklust szervezni, ha az adott nyelv támogatja a címkék elhelyezését, továbbá van olyan utasítás, amellyel egy már megadott címkére lehet ugrani. Ez azt jelenti, hogy a program az adott címkétől folytatódik. Használata kerülendő.

Az alábbi program egy ciklust valósít meg BASIC-ben a GOTO ugró utasítás segítségével.

10 PRINT "Meddig irjam ki a szamokat? ";
20 INPUT N
30 I = 1
40 IF I > N THEN GOTO 80
50 PRINT I
60 I = I + 1
70 GOTO 40
80 REM "PROGRAM VEGE"

Kapcsolódó szócikkek szerkesztés

Források szerkesztés

  1. Archivált másolat. [2009. február 13-i dátummal az eredetiből archiválva]. (Hozzáférés: 2010. január 19.)


Kategória:Programozási alapfogalmak