Ciklusok I.
Ahogy a legutóbbi lecke elején ígértem, most belevágunk az "igazi" programozásba!
Ciklusok létrehozása
A programozás leglényegesebb elemei a ciklusok! A működésüket és hasznukat az alábbi probléma megoldásán keresztül mutatom meg:
Mit tegyünk ha ki akarjuk íratni 2-től 100-ig az összes páros számot? Az eddigi ismeretek alapján a megoldás ez lenne:
$n = 2; print $n; //2 $n = $n + 2; print $n; //4 $n = $n + 2; print $n; //6 $n = $n + 2; // ... stb. ... $n = $n + 2; print $n; //98
Amint látjuk, másolás-beillesztés sorozatokat kellene csinálnunk éjjel-nappal! Tulajdonképpen már a hatványozó program esetén is láthattunk hasonló dolgot, bár ott csak háromszor kellett megismételni ugyanazt. Mivel a programozásban igen gyakran előfordul az ismételgetés, ezért ki kellett találni egy nyelvi elemet, amely segítségével csak egyszer kell leírni az ismételendő műveletet. A magyar nyelvben valami ilyesmit mondanánk:
$n = 2; ismételd az alábbi műveletsort addig, amíg $n kisebb mint 100: print $n; $n = $n + 2; vége
Ez PHP nyelven az alábbi módon hangzik:
$n = 2;
while ($n < 100){
print $n;
$n = $n + 2;
}
A < kacsacsőr jelentése "kisebb mint", akárcsak a matekban! A PHP-ben egy ciklus általános esetben így néz ki:
while (feltétel){ utasítások }
A while egy kulcsszó, ami azt jelzi hogy most egy ciklus jön, és azonosítja a ciklus típusát (többféle ciklus is van a PHP-ben, ezek közül a while ciklus a legegyszerűbb; a "while" angol szó, jelentése "amíg"). A while után kerek zárójelek közt szerepel egy feltétel (ez a ciklusfeltétel). Amíg a feltétel teljesül, addig a kapcsos zárójelek közti utasítások végrehajtódnak, majd a feltétel újra megvizsgálódik (a kapcsos zárójelek közti utasítások listáját ciklusmagnak nevezzük). Amint a feltétel hamissá válik, a ciklus véget ér. A ciklus ezen működését részletesen megnézzük az alábbi példán:
Hozzuk létre az alábbi kimenetet ciklus segítségével: 1, 2, 3, ...
$szam = 1;
while ($szam < 4){
print $szam;
print ", ";
$szam = $szam + 1;
}
print "...";
Hogy működik a fenti kód? Először is beállítjuk a $szam változó értékét 1-re. Ezután jön a feltételvizsgálat: a $szam változó kisebb-e mint 4? Mivel 1 kisebb mint 4, ezért elkezdődik a kapcsos zárójelek között lévő utasítások (ciklusmag) végrehajtása. Kiírjuk a $szam változó értékét majd a vesszőt, utána pedig növeljük a változót 1-gyel. Vége a ciklusmagnak, most megint megvizsgálódik a feltétel. $szam értéke már 2, de mivel 2 < 4 teljesül, ezért a ciklusmag újra végrehajtódik: kiíródik a 2-es, és a $szam értéke 3 lesz. A feltétel megint teljesül, megint lefut a ciklusmag, kiíródik a 3-as. Most viszont $szam értéke a ciklusmag végén 4 lesz. A feltétel ismét megvizsgálódik: 4 < 4 hamis, ezért a ciklusmag már nem fog lefutni, hanem átugrunk a mag utáni első utasításra (vagyis arra, ami már a kapcsos zárójelen kívül van). Ez pedig a print "..."; vagyis az eddig kiírt sor végére kiírjuk a "..." karakterláncot.
Természetesen a fenti kódot lerövidíthetjük a legutóbb tanult összefűző és növelő operátorok segítségével:
$szam = 1;
while ($szam < 4){
print $szam.", ";
++$szam;
}
print "...";
Formai javaslatok
A fenti kódokban a ciklusmag utasításait beljebb írtam, mint a többi sort. Ezt azonban nem írja elő a PHP nyelvtana, mint ahogy a kerek zárójel előtti vagy a kacsacsőr körüli szóközöket sem. Az utasításokat sem szükséges külön sorba írni, a fenti program így is működik:
$szam=1;
while($szam<4){print $szam.", "; ++$szam;}
print "...";
Sőt, akár a ciklus előtti és utáni utasításokat is írhatnánk egy sorba a ciklussal, de úgy sokkal áttekinthetetlenebb lenne a program. A ciklusmag utasításainak behúzása azt a célt szolgálja, hogy mutassa a program hierarchikus felépítését, és persze hogy könnyen látható legyen hogy hol a ciklus eleje és vége.
Összehasonlító operátorok
Miket írhatunk a ciklusfeltételbe (vagyis mik lehetnek a kerek zárójelek között)? Olyan operátorokat kell itt használni, amelyekről eddig nem volt szó, most viszont gyorsan lerendezzük őket! A fontosabb összehasonlító operátorok:
operátor jelentés < kisebb mint > nagyobb mint <= kisebb vagy egyenlő >= nagyobb vagy egyenlő == egyenlő != nem egyenlő
Az első kettőtől remélem senki nem kap szívrohamot, ugyanúgy néznek ki mint a matematikában és ugyanúgy is kell őket használni! A 3. és 4. esetén a használat szintén ugyanígy megy, csak kicsit furán néznek ki, mivel a matekban az egyenlőségjelet a kacsacsőr alá írjuk. Egy szövegszerkesztőben viszont ezt nem lehet, így az egyenlőségjelet utána kell raknunk! Az egyenlőség operátor azért dupla egyenlőségjel, mert a szimpla (=) az értékadó operátor (a kettő közti különbséget az "Elágazások" tananyagban fogjuk megvizsgálni, ciklusokban általában nem szokták használni). A nem egyenlőt, ami a matekban egy áthúzott egyenlőségjel, pedig úgy is fel lehet fogni hogy kisebb vagy nagyobb.
Mindegyik összehasonlító operátor kétoperandusú, a két oldalán egyaránt állhatnak kifejezések (más operátorok segítségével gyártott összetett kifejezések is), számok és karakterláncok is. A == és != operandusai felcserélhetők, a többié viszont csak akkor, ha az operátort ellenkezőjére változtatjuk (pl. $n < 5 egyenértékű az 5 > $n feltétellel). Nézzünk pár példát ezek használatára:
// számok kiírása csökkenő sorrendben:
$n = 5;
while ($n >= 0){
print $n;
--$n;
}
Ennek az eredménye ez lesz: 543210. Ha a >= helyett a > operátort használjuk, akkor az $n nulla értékénél a feltétel már nem teljesül, és ezt kapjuk: 54321.
$x = 0;
$szam = 99;
while ($x != ($szam + 1)){
print "Hörb";
++$x;
}
Ez meg 100-szor kiírja azt hogy Hörb (ráadásul sortörés nélkül). A program kipróbálása kötelező! :D
A ciklus addig megy, amíg $x értéke ($szam + 1)-gyel, vagyis 100-zal nem egyenlő. Bár itt a $szam + 1 kifejezést nem muszáj zárójelbe rakni, mivel az aritmetikai operátorok (+, -, *, /) az összehasonlító operátoroknál szorosabban kötnek, de kezdők számára ajánlott a zárójelezés, és a program így talán jobban olvasható is.
Az összehasonlító operátorok karakterláncok esetén is használhatók, de azokra a ciklusok esetén nem sok jó példát lehet mutatni, itt van esetleg ez:
print "Itt kezdődik!<br />";
$szoveg = "";
while ($szoveg != "XXXXX"){
print $szoveg."<br />";
$szoveg = $szoveg."X";
}
Az alábbi kimenetet produkálja a böngészőben:
Itt kezdődik!X
XX
XXX
XXXX
Ez egy idétlen program, de tartalmaz egy-két újdonságot is. A 2. sorban a $szoveg változónak egy üres karakterláncot adunk értékül. Azért érdemes ezt tenni, mert ha nem kap semmilyen értéket, akkor nem használható biztonsággal a feltételvizsgálatban! Így viszont (mivel "" != "XXXXX" teljesül) a ciklus biztosan elindul. A ciklusmag első végrehajtásánál a print $szoveg."<br />"; jelentése print ""."<br />"; Az üres karakterlánc az összefűző operátor szempontjából olyan, mintha ott se lenne, így először csak egy sortörés (<br />) kerül kiírásra. Utána viszont hozzáfűződik az X betű, a ciklus újbóli végrehajtása során pedig az eddig felépített karakterlánchoz fűződik hozzá egy X karakter, és így tovább. Amikor pedig a $szoveg változó már 5 db X betűt tartalmaz, vagyis úgy néz ki hogy "XXXXX", a feltétel nem teljesül, és átugorjuk a ciklust.
Házi feladat
Mivel nagyon fontos hogy a ciklusok működését megértsük, javaslom hogy az összes fenti példaprogramot próbáld ki! Úgy is, hogy itt-ott megváltoztatsz benne egy-két dolgot (például a ciklusfeltételben más operátort használsz, a ciklusmagba beillesztesz további utasításokat, stb.)! Azért csak óvatosan, mert előfordulhat hogy hibaüzenetet kapsz, ezekről a következő leckében lesz szó. Ha pedig eleget szórakoztál, próbáld meg megoldani ezeket a feladatokat:
1.) Írjuk ki csökkenő sorrendben a negatív számokat (-1)-től (-50)-ig a következő formában:
-1, -2, -3, ... , -49, -50.
A ... helyén persze a többi számnak kell lennie. Próbálj a fentivel azonos kimenetet produkálni, azaz a számokat vesszővel válaszd el egymástól, de a -50 után pontot írass ki! Nem kell megijedni a negatív számoktól, ezek nem igényelnek különleges bánásmódot.
Egy lehetséges megoldás:
$szam = -1;
while ($szam > -50){
print $szam.", ";
--$szam;
}
print $szam.".";
A ciklus belsejében nincs semmi különös, (-1)-től indulunk, mindig kiírjuk a számot, utána a vesszőt, majd csökkentjük eggyel. A (-50)-es számot viszont már nem írja ki a ciklusmag, mivel ha ezt megengednénk, akkor utána kerülne a vessző. Ahhoz, hogy a (-50)-es szám után pontot írjunk, az ezt kiíró utasítást a cikluson kívül kell elhelyezni. A ciklus utáni sorban a $szam változó értékét használtam a -50 kiírására, de persze lehet azt is írni, hogy:
print (-50).".";
Azért lehet az utolsó sorban a $szam változót használni, mert a ciklusból akkor keveredünk ki, amikor a feltétel hamissá válik. Ez akkor történik, amikor a $szam (-50)-nel egyenlő. Ekkor már nem fut le a ciklusmag, hanem átugrunk a ciklus utáni első utasításra, ahol természetesen továbbra is használhatjuk a változót.
2.) Írassuk ki az 1 és 100 közötti 3-mal osztható számokat növekvő sorrendben! Próbáljuk meg úgy megcsinálni, hogy a számokat felváltva, egyszer vessző, egyszer pontosvessző választja el egymástól:
3, 6; 9, 12; 15, 18; ... , 96; 99,
Figyelem! A 102-t már nem írhatjuk ki! Majd meglátod hogy ezt miért mondtam! :D
Tipp: ne használd a nem egyenlő (!=) operátort, helyette inkább a < -et.
A 3-mal osztható számokat úgy írhatjuk ki, hogy az elsőt 3-nak választjuk, majd a számot mindig 3-mal növeljük. Ha csak ennek a feltételnek akarunk eleget tenni, a program így nézhet ki:
// 2. házi - félkész változat
$szam = 3;
while ($szam < 100){
print $szam.", ";
$szam = $szam + 3;
}
Ez a következő kimenetet adja: 3, 6, 9, 12, 15, 18, ... 96, 99,
Azért nem szerencsés, ha a != operátort használjuk, mert a $szam változó sosem lesz 100, így sosem érne véget a ciklus (ilyen problémákról a következő tananyagban lesz szó).
Ha felváltva akarunk vesszőt és pontosvesszőt írni, akkor a ciklusmagban két számot kell kiíratni, mivel az ismédlődés két számonként következik be. Ezt úgy értem hogy nem az ismétlődik hogy $szam.", " hanem az hogy $szam.", ".$szam."; ".
// 2. házi - majdnem kész változat
$szam = 3;
while ($szam < 100){
print $szam.", ";
$szam = $szam + 3;
print $szam."; ";
$szam = $szam + 3;
}
Az írásjelek váltakozó kiírása jól adja, viszont most kiírta a 102-es számot is! Nyilván le kell csökkentenünk a ciklusfeltételben lévő számot, hogy hamarabb véget érjen a ciklus. Ha például 99-et írunk oda, akkor már nem írja ki a 102-est, de a 99-es is eltűnt mivel a ciklusmag egyszerre két számot is kiír, és most eggyel kevesebbszer futott le. A 99-es számot megint csak a ciklus után írva tudjuk berakni:
// 2. házi - végleges változat (A verzió)
$szam = 3;
while ($szam < 99){
print $szam.", ";
$szam = $szam + 3;
print $szam."; ";
$szam = $szam + 3;
}
print $szam.",";
A ciklusmagot azonban máshogy is meg lehet írni, nem feltétlenül kell kétszer növelni a változót. Lehet úgy is, hogy kiírjuk a $szam-ot, utána a vesszőt, majd a ($szam+3)-at és ezután a pontosvesszőt. Ilyenkor persze a ciklusmag végén a $szam-ot 6-tal kell növelnünk:
// 2. házi - végleges változat (B verzió)
$szam = 3;
while ($szam < 99){
print $szam.", ".($szam + 3)."; ";
$szam = $szam + 6;
}
print $szam.",";
3.) Gyártsuk le a 3-as szorzótáblát! A 3-as számot változóban add meg, és próbáld meg úgy csinálni, hogy ennek az egy változónak az átírásával egy másik szorzótáblát írjon ki! Pl. ha a 3-ast átírom 8-ra, akkor a 8-as szorzótáblát dobja elém. A kimenet lehet valami ilyesmi:
1 x 3 = 3
2 x 3 = 6
3 x 3 = 9
...
9 x 3 = 27
A 3-as számot változóban kell tárolni, és nem változtathatjuk meg, mivel a második oszlop 3-asait ezzel kéne kiíratni, és a szorzatok kiszámításához is ez kell. A feladat lényege, hogy be kell vezetni még egy változót, amit az első oszlop kiírására (és persze a szorzatok kiszámítására) használunk:
// Szorzótábla
$szam = 3;
$n = 1;
while ($n < 10){
print $n." x ".$szam." = ".($n * $szam)."<br />";
++$n;
}
Az $n a futó változó, ami kezdetben 1 és folyamatosan növekszik a ciklusban. Ha a $szam változó értékét átírjuk, akkor pedig egy másik szorzótáblát kapunk, mivel a cikluson belül sehol sem használtuk a 3-as számot, csak a változót!
Na, azt hiszem ennyi elég lesz egyszerre. Némelyik feladat nem is olyan nehéz, mint első látásra tűnik! Ha a harmadik nagyon nem megy, akkor először próbáld meg ciklus nélkül megcsinálni (hasonlóan a 4. leckében lévő hatványozó programhoz). Kellemes fejtörést! :)







