Ciklus (programozás)

A Wikipédiából, a szabad enciklopédiából

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, de a működési módjukat tekintve három alaptípusba sorolhatók aszerint, hogy hányszor futnak le: ezek az elöltesztelő, a hátultesztelő és a számlálós ciklus.

A ciklus fajtája A futások száma Legkevesebb hányszor fut le?
Feltételes Elöltesztelő előre nem ismert lehet, hogy egyszer sem
Hátultesztelő előre nem ismert legalább egyszer
Számlálós előre ismert lehet, hogy egyszer sem

A ciklus részei[szerkesztés | forrásszöveg szerkesztése]

Alább egy egyszerű BASIC nyelvű ciklust láthatunk, amelyik 10-től 15-ig egynegyedes lépésközzel haladva kiírja a számokat és a négyzetüket:

FOR i=10 TO 15 STEP 0.25
 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 10 lesz; mivel ez kisebb, mint 15, ezért a ciklusmag lefut, vagyis a program kiírja a képernyőre a

10 négyzete: 100

sort. Ezután i értéke 10,25-ra változik, és ismét lefut. Ez addig ismétlődik, amíg az i értéke 15 lesz. Ekkor még utoljára lefut a ciklus, tehát a képernyőn még megjelenik a 15 négyzete is, majd az i értéke 15,25 lesz, de ez már nagyobb, mint 15, 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 (10), végértéke (15) és lépésköze (0,25). 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öltesztelő é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átultesztelő ciklus esetén pedig ez a rész tartalmazza a futási feltételt.

Feltételes ciklusok[szerkesztés | forrásszöveg szerkesztése]

A feltételes ciklusokat (néha végfeltételes ciklus néven is említik őket) olyankor használjuk, amikor nem tudjuk előre, hogy hányszor kell a ciklusnak lefutnia, 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öltesztelő ciklus[szerkesztés | forrásszöveg szerkesztése]

While-loop-diagram.svg

Az elöltesztelő ciklus sémája:

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

Az elöltesztelő 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öltesztelő ciklus egyszer sem fog lefutni.

Az elöltesztelő 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öltesztelő ciklus tipikus kulcsszava a while.

Hátultesztelő ciklus[szerkesztés | forrásszöveg szerkesztése]

Do-while-loop-diagram.svg

A hátultesztelő 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átultesztelő ciklus legalább egyszer mindenképpen lefut.

A konkrét programnyelvi megvalósítástól függ, hogy a hátultesztelő 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).

Jellemző példa a hátultesztelő 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álaszott 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 adatbeolvasás legalább egyszer mindenképpen megtörténik. Ha sikerült elsőre jól kitöltenünk 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átultesztelő 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ós (FOR) ciklus[szerkesztés | forrásszöveg szerkesztése]

For-loop-diagram.png

A számláló (vagy iteráló) ciklus általánosságban olyan előltesztelő 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++-ban a for ciklus majdnem teljesen ekvivalens az elől tesztelős ciklussal (a continue viselkedése más), de más nyelvekben nem feltétlenül van ez így: a for ciklus átírható más ciklussá, de visszafelé álatlában nem. A for ciklusnak kisebb lehet a kifejezőereje, de könnyebb olvasni ezért a használata javasolt ott ahol ez lehetséges.

Összegzés for-ral C++-ban:

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

Összegszés while-lal C++-ban:

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

Az ADÁban 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;

Ez a példa az 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

Iteráló ciklus[szerkesztés | forrásszöveg szerkesztése]

Gyakran for vagy foreach kulcsszóval szokták rendelkezésre bocsátani. Arra való egy egy tároló 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 2,4,6,8

Beavatkozás a ciklus menetébe[szerkesztés | forrásszöveg szerkesztése]

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;
    }
}

Néhány nevezetes alkalmazás[szerkesztés | forrásszöveg szerkesztése]

Egymásba ágyazott ciklusok[szerkesztés | forrásszöveg szerkesztése]

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ék rendezé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 végtelen ciklus[szerkesztés | forrásszöveg szerkesztése]

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 | forrásszöveg szerkesztése]

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 | forrásszöveg szerkesztése]

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

Ciklus ugró utasítással[szerkesztés | forrásszöveg szerkesztése]

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ásszöveg szerkesztése]

Források[szerkesztés | forrásszöveg szerkesztése]