For vagy while?

Csendes Dávid · 2019.09.21.

Mikor használunk while-t, és mikor for-t?

for vagy while?

Mikor használunk while-t, és mikor for-t? Először is tisztázni kell – ahol for használható, ott while is ugyanúgy működik, és fordítva. Ezt hamar beláthatjuk, ha egy for ciklust átírunk:

// for ciklussal
for (int i = 0; i < max; i = i + 1) {
    // ciklustörzs
}

// ugyanez while ciklussal
int i = 0;
while (i < max) {
    // ciklustörzs
    i = i + 1;
}

Működés szempontjából emiatt mindegy, melyiket használjuk, de kód szépsége szempontjából (egyes esetekben) nagyon nem!

Mégis akkor mi alapján lehet eldönteni, melyiket érdemesebb használni? Röviden: ha a for ciklus fejlécében valamelyik rész üresen maradna, akkor érdemesebb a while, ha mind kitölthető, akkor for.

Milyen esetekben fordulhat elő, hogy a for ciklus fejlécének 3 része közül valamelyik üresen marad?

  1. Például a ciklusváltozónk már létezik korábbról (és használjuk is ott, nem inicializálhatjuk a ciklus kezdeténél). Ha ezt for-ral írnánk, akkor az első része üresen maradna – érdemesebb ilyenkor while-t használni.
  2. A ciklusváltozó léptetése valamilyen különleges módon / feltételhez kötve történik. Ebben az esetben a for harmadik része üres lenne, mert ezt a komplexebb logikát a ciklustörzsbe írtuk le – ismét a while egy nyerőbb választás.
  3. Egyes esetekben nincsen konkrét ciklusváltozónk. Ekkor egyértelmű a while használata, hisz csak a feltételünk van meg, for esetén a két szélső rész üresen maradna.

Egy példa az utóbbira:

while (scanf("%d", &szam) == 1)

Mikor lesz kitöltve a for ciklus fejléce teljesen? Tulajdonképpen bármilyen olyan esetben, ami az előzőekből kimaradt. De különös hangsúllyal arra, mikor egy tárolót kell végigjárni, vagy egy olyan ciklusról van szó, ahol az a lényeg, hogy a ciklustörzsben lévő kód adott számú alkalommal fusson le (számlálás alapú ciklus). Ebben a két esetben mindenképp for ciklust használjunk!

int tomb[10];

for (int i = 0; i < 10; i = i + 1)
    tomb[i] = 1;

for ciklus ciklusszámlálója

Honnan indítsuk a ciklusváltozónkat? Meddig menjen? Ez egy jóval egyszerűbb kérdés, mint az előző volt.

for (int i = 0; i < 5; i = i + 1)
// vagy
for (int i = 1; i <= 5; i = i + 1)

Mind a kettő teljesen ugyanazt végzi – 5 alkalommal futtatja le a ciklustörzset. De mégis melyiket válasszuk?

Mind a két variációnak van létjogosultsága: az első esetben azt mondhatjuk, hogy a ciklusváltozó azt mutatja, hány iteráció fejeződött már be, míg a második esetben azt, hogy épp hányadik iteráció fut.

Azonban van kettő (plusz egy) indok, hogy miért a 0-val inicializált verziót használjuk:

  1. egy karakterrel rövidebb :)
  2. tömbökkel történő munka során muszáj 0-tól indulni, ha minden elemmel akarunk dolgozni, hisz ezeknek az indexelés 0-tól indul.
  3. ez csak extra – hagyományosan az informatikában minden 0-tól indul (erről bővebben itt).

Előfordulhat olyan eset, hogy az 1-gyel inicializált verzió könnyebben átlátható kódot eredményez a ciklustörzsben (arról nem is beszélve, hogy valami konkrét értékről kell indítani a ciklusváltozót), de általában biztonsággal használható a 0 kezdetű – érdemes megszokni!

Egy valamit ne csináljunk semmiképp sem:

for (int i = 1; i < 6; i = i + 1)

Ha a ciklusunk számlálásos, a feltételben lévő szám tükrözze mindenképp azt, hogy hányszor fut le a ciklus. Erről nem lehet ránézésre megmondani, hogy 5-ször fut le!

Ha nem 0-ról/1-ről indul a ciklusváltozó, jellemzően az a célunk, hogy a kezdeti értéktől a lezáró értékig bezárólag minden előforduló számmal csináljunk valamit (például kiíratni a számokat visszafelé).

for (int i = 23; i >= 4; i = i - 1)
    printf("%d", i);

A fenti kódrészlet 23-tól 4-ig (beleértve mindkettőt) kiírja az összes számot. Honnan lehet tudni? Onnan, hogy mind a két szám szerepel a fejlécben! Azok az értékek, melyek a feladatban megjelennek, érdemes a kódban is előfordulniuk, lehetőleg módosítás nélkül.

// így mi is lesz az utolsó kiírt szám? :(
for (int i = 23; i > 3; i = i - 1)
    printf("%d", i);