Programozás I. Ciklusok Rendszer és Szoftvertechnológia Tanszék
Ciklusok Iteráció (Ciklus): Valamely tevékenység sorozat ismételt végrehajtását jelenti. Az ismétlés feltételhez kötött, vagy előírt a lépésszám. Három fajtája van: Elöl tesztelő Hátul tesztelő Növekményes
Elől tesztelő ciklus Ciklus amíg Lefutási feltétel Cikusmag utasításai Ciklus vége Működése A ciklusmag utasításait mindaddig kell végrehajtani. amíg a Lefutási feltétel igaz. Ha a lefutási feltétel hamissá válik, a végrehajtás a ciklus vége után folytatódik. Ha a lefutási feltétel már a ciklusba való belépéskor hamis, a ciklusmag utasításai egyszer sem hajtódnak végre. PÉLDA: Ciklus amíg van nálam "Mosópor reklám anyag" elmegyek a köv. lakásig bedobom a csomagot
Ciklusok: elől tesztelő ciklus PÉLDA: Ciklus amíg van nálam "Mosópor reklám anyag" elmegyek a köv. lakásig bedobom a csomagot Ciklus vége
Ciklusok: elől tesztelő ciklus, az előreolvasás fogalma Az elöltesztelő ciklus megvalósítása mindig előreolvasással történik: a feltételben vizsgált adatot előbb meg kell határozni, és azután megvizsgáljuk, hogy a megadott érték megfelel-e a lefutási feltételnek, a ciklusmagban pedig biztosítanunk kell a feltétel hamissá válását, különben végtelen ciklust kapunk->előreolvasás !
Ciklusok: elől tesztelő ciklus a C-ben A C nyelvi programszerkezet: while (kifejezés) //lefutási feltétel { ciklusmag utasításai } A while ciklus mindaddig ismétli a hozzá tartozó utasításokat (a ciklusmag utasításait, más szóval a ciklus törzsét), amíg a vizsgált kifejezés (lefutási feltétel) értéke nem nulla (igaz). A vizsgálat mindig megelőzi a ciklusmag utasításainak végrehajtását, ezért van olyan eset, amikor a ciklusmag utasításai egyszer sem kerülnek végrehajtásra.
Ciklusok: elől tesztelő ciklus, példa Alap-helyzet: kaptam egy összeget, amit könyvekre költhetek. Tevékenység-sorozat, amit ismétlünk: kiválasztok egy könyvet, kifizetem Feltétel: van még elég pénzem Pszeudokód-részlet: Be: penzosszeg //amit kaptam könyvekre … Be: konyv_ara //az első kiválasztott könyv ára //előreolvasás Ciklus amíg konyv_ara < penzosszeg penzosszeg = penzosszeg – konyv_ara //feldolgozás Be: konyv_ara // következő kiválasztott könyv ára Ciklus vége Kérdés: lehet, hogy egyetlen könyvet sem veszek meg ?
Ciklusok: elől tesztelő ciklus: 2.3.3. feladat Állítsunk elő 0 és 50 közötti véletlen-számokat addig, amíg a 25-ös szám generálása is megtörtént. Írassuk ki a kapott számokat. Megoldás: Elemezzük a feladatot: Állítsunk elő egy véletlen-számot, majd ismételjük az alábbi tevékenységeket: Ha a szám nem egyenlő 25-tel, akkor: írjuk ki állítsunk elő egy újabb véletlen-számot.
Ciklusok: elől tesztelő ciklus: 2.3.3. feladat void main (void) /*előltesztelő ciklus: véletlen számok előállítása, amíg 25-öt kapunk */ { int szam; randomize (); szam = random (51); while (szam != 25) printf ("\n/%d ",szam); } printf ("\n...Megvan a 25-ös !"); getch (); } // program vége Pszeudokód: Program Változók: szam (poz. egész) szam = random (51) Ciklus amíg (szam <> 25) Ki: szam Ciklus vége Ki : "Megvan a 25-ös !" Program vége
Hátul tesztelő ciklus Ciklus Ciklusmag utasításai mígnem Kilépési feltétel Ciklus vége Működése: A ciklusmag utasításait mindaddig kell végrehajtani. amíg végre a Kilépési feltétel igazzá válik. Ha a Kilépési feltétel igazzá válik, a végrehajtás a ciklus vége után folytatódik. A ciklusmag utasításait egyszer mindenképpen végrehajtja a rendszer, mivel a Kilépési feltétel kiértékelése a ciklusmag utasításainak végrehajtása után történik. PÉLDA
leszedek egy almát a fáról mígnem tele a kosár Ciklus vége Hátul tesztelő ciklus PÉLDA Ciklus leszedek egy almát a fáról mígnem tele a kosár Ciklus vége Kilépési feltétel: tele a kosár
Hátul tesztelő ciklus a C-ben Ciklusmag utasításai amíg Lefutási feltétel Ciklus vége Működése: A ciklusmag utasításait mindaddig kell végrehajtani. amíg a Lefutási feltétel igaz. Ha a lefutási feltétel hamissá válik, a végrehajtás a ciklus vége után folytatódik. A ciklusmag utasításait egyszer mindenképpen végrehajtja a rendszer, mivel a lefutási feltétel kiértékelése a ciklusmag utasításainak végrehajtása után történik
Hátul tesztelő ciklus a C-ben A C nyelvi programszerkezet: do { ciklusmag utasításai } while (kifejezés); //kifejezés: lefutási feltétel A do-while ciklus futása során mindig a ciklusmag utasításait követi a kifejezés kiértékelése. Amíg a kifejezés értéke nem nulla (igaz), addig új iteráció kezdődik. Amikor a kifejezés értéke a vizsgálat során először bizonyul nulla értékűnek (hamis), a vezérlés a while utáni utasításra adódik, a ciklus befejezi a működését.
Hátul tesztelő ciklus:2.3.3.2. feladat Készítsen programot, amely bekéri egy felnőtt testmagasság (110-210 cm) és testsúly (30-150 kg) adatait, majd kiírja azokat. Csak a megadott határok közötti értékeket fogadhat el. Elemezzük a feladatot: Külön ciklussal fogjuk bekérni a magasságot, külön a testsúlyt. Így egyszerűbb a lefutási feltételek megfogalmazása és csak a hibásan megadott adat újra bevitelét kérjük. A "bekérési" ciklus addig kell fusson, amíg hibás a kapott érték ! Ellenőrzött adat-bevitel: A hátultesztelő ciklust gyakran alkalmazzuk ellenőrzött adatbevitelre. Ez azt jelenti, hogy addig folytatjuk egy meghatározott adat bekérését, amíg az az előírt határok közé nem esik.
Hátul tesztelő ciklus:2.3.3.2. feladat Program Változók: magassag, suly (pozitív valós értékek) Ciklus Be: magasság [110-210 cm] amíg (magassag < 110 vagy magassag > 210) Ciklus vége Be: suly [30-150 kg] amíg (suly < 30 vagy suly > 150) Ki: magassag, suly Program vége
Hátul tesztelő ciklus:2.3.3.2. feladat Be: magasság [110-210 cm] amíg (magassag < 110 vagy magassag > 210) Ciklus vége do { printf ("\nKérem a testmagasságot cm-ben (110-210) :"); scanf ("%f", &magassag); fflush (stdin); } //do while ((magassag < 110) || (magassag > 210));
Hátul tesztelő ciklus:2.3.3.2. feladat void main (void) //testmagasság és testsúly adatok ellenőrzött bevitele { float magassag, suly; do printf ("\nKérem a testmagasságot cm-ben (110-210) :"); scanf ("%f", &magassag); fflush (stdin); } //do while ((magassag < 110) || (magassag > 210)); printf ("\nKérem a testsúlyt kg-ban (30-150): "); scanf ("%f", &suly); fflush (stdin); while ((suly < 30) || (suly > 150)); printf("\nKöszönöm az adatokat: %5.1f, %5.1f",magassag, suly); getch (); } // program vége
Hátul tesztelő ciklus A hátultesztelő ciklusnál a ciklusmag utasításait egyszer mindenképpen végrehajtja a rendszer. Ez nem mindig alkalmas szerkezet a feladataink megoldására. (ld. könyv vásárlás)
A lefutási feltétel és a kiugrási feltétel kapcsolata Lefutási feltétel: magasság < 110 VAGY magasság >210 Kiugrási feltétel: magasság >=110 ÉS magasság <=210 DeMorgan azonosságok: I. nem (A vagy B) = nem A ÉS nem B II. nem (A ÉS B) = nem A VAGY nem B
A lefutási feltétel és a kiugrási feltétel kapcsolata I. nem (A vagy B) = nem A ÉS nem B II. nem (A ÉS B) = nem A VAGY nem B Állítás Tagadás a <> 0 a = 0 a >0 a <= 0 a=0 ÉS b=0 a <>0 VAGY b<>0
Mit kell tudni ? Problémaosztályok, algoritmusok: pszeudokód Programozás 1: A C nyelvi szerkezetek általános alakja, magyarázattal, alkalmazások.
Ajánlott szabályok… A program első sorába megjegyzésként be kell írni a nevet, csoport-számot, EHA kódot. A program második sorában tömören meg kell adni a program által megoldott feladatot. Használjon beszédes változóneveket. Valamennyi változó deklarációja legyen a program elején, A bevitelt (scanf) mindig előzze meg egy printf , amellyel a beviendő adat tartalmára, esetleges korlátaira hívjuk fel a felhasználó figyelmét. Az összetartozó printf, scanf utasításokat egy sorban helyezzük el (Ha elférnek.) A program utolsó sorában helyezzen el egy getch (); függvényt,
Ajánlott szabályok… A forrásszöveget tagolni kell, A nyitó kapcsos zárójel mindig az őt megelőző utasítás első karakteréhez igazodik, az alatta következő utasítások két karakterrel beljebb kezdődnek. A záró kapcsos zárójel a hozzá tartozó nyitó zárójellel azonos oszlopban helyezkedik el, külön sorban van. Mögötte megjegyzésként meg kell adni, hogy milyen utasításhoz tartozik. A forrásszöveg begépelésénél minden leírt nyitó zárójelhez azonnal be kell írni a csukó zárójelet is. Már néhány programsor bevitele után menteni kell a programot a megfelelő (helyi) tárolóra. A program fordítást nem szabad elindítani addig, míg a forrásszöveget el nem mentettük.
Ellenőrző kérdések: Melyik az a három vezérlőszerkezet, amelyekből a programok felépíthetők ? Mi a lényege a "felülről-lefelé", illetve az "alulról felfelé" építkezésnek ? Milyen eszközök állnak rendelkezésre az algoritmusok megtervezéséhez ? Mit jelentenek az alábbi fogalmak ? Algoritmus Szekvencia, szelekció, iteráció Dekompozíció Lépésenkénti finomítás Moduláris program Strukturált program Pszeudokód A moduláris programozás irányelvei Az egyágú szelekció általános leírása C-ben, működése. A kétágú szelekció általános leírása C-ben, működése. A többágú szelekció általános leírása C-ben, működése. Az elől tesztelő ciklus általános leírása C-ben l, működése. A hátul tesztelő ciklus általános leírása C-ben, működése. A növekményes (számláló) ciklus általános leírása C-ben, működése.
Ciklusok Iteráció (Ciklus): Valamely tevékenység sorozat ismételt végrehajtását jelenti. Az ismétlés feltételhez kötött, vagy előírt a lépésszám. Három fajtája van: Elöl tesztelő Hátul tesztelő Növekményes
Ciklusok: elől tesztelő ciklus A C nyelvi programszerkezet: while (kifejezés) //lefutási feltétel { ciklusmag utasításai } A while ciklus mindaddig ismétli a hozzá tartozó utasításokat (a ciklusmag utasításait, más szóval a ciklus törzsét), amíg a vizsgált kifejezés (lefutási feltétel) értéke nem nulla (igaz). A vizsgálat mindig megelőzi a ciklusmag utasításainak végrehajtását, ezért van olyan eset, amikor a ciklusmag utasításai egyszer sem kerülnek végrehajtásra.
Hátul tesztelő ciklus a C-ben A C nyelvi programszerkezet: do { ciklusmag utasításai } while (kifejezés); //kifejezés: lefutási feltétel A do-while ciklus futása során mindig a ciklusmag utasításait követi a kifejezés kiértékelése. Amíg a kifejezés értéke nem nulla (igaz), addig új iteráció kezdődik. Amikor a kifejezés értéke a vizsgálat során először bizonyul nulla értékűnek (hamis), a vezérlés a while utáni utasításra adódik, a ciklus befejezi a működését.
Növekményes ciklusok Gyakran előforduló feladat, hogy valamely tevékenység(ek)et előre megadott számszor kell végrehajtani. Erre a feladatra a programnyelvek egy külön ciklus-utasítást biztosítanak, a növekményes, számláló, vagy léptetéses ciklust. Növekményes (számláló) ciklus (Ciklus ciklusváltozó =....kezdőértéktől ....végértékig .... Lépésközzel) Ciklusmag utasításai Ciklus vége Működése: A ciklusmag utasításai a ciklusváltozó kezdés végértékének, valamint a lépésszámnak megfelelő számszor kerülnek végrehajtásra.
Növekményes ciklus a C-ben A C nyelvi megvalósítás : for (init_kifejezés; feltétel_kifejezés; léptető_kifejezés) // inicializálás módosító rész { ciklusmag utasításai } A for ciklus végrehajtásának lépései: 1. Az init_kif kifejezés kiértékelése. 2. A feltétel_kif (aritmetikai vagy mutató típusú) kifejezés feldolgozása. 3. Ha a feltétel_kif értéke nem nulla (igaz), akkor végrehajtódnak a ciklusmag utasításai, majd a léptető_kif kifejezés kiértékelése következik. Minden további iterációt a feltétel_kif kiértékelése nyit meg, s annak értékétől függ a folytatás. 4. Ha a feltétel_kif értéke nulla (hamis), akkor a for utasítás befejezi a működését és a vezérlés a ciklusmag utasításait tartalmazó blokk után következő utasításra adódik.
Növekményes ciklus a C-ben A C nyelvi megvalósítás : for (init_kif; feltétel_kif; léptető_kif) { ciklusmag utasításai } A for ciklus a while ciklus egy speciális alkalmazásának is tekinthető, így a fenti ciklus átírható az alábbi szerkezetre: init_kif; while (feltétel_kif) léptető_kif
Növekményes ciklus a C-ben Készítsen programot, amely n darab * karaktert ír ki a képernyőre. Megoldás: Pszeudokód: Program Változók: n - darabszám, pozitív egész i - ciklusváltozó, pozitív egész Ciklus Be: n amíg (n<= 0) ciklus vége Ciklus i= 1 kezdőértéktől n végértékig 1 lépésközzel Ki: "*" Program vége
Növekményes ciklus a C-ben void main (void) //for ciklus: n darab * karakter kiírása { int i, n; //i a ciklusváltozó, n a darabszám do printf ("\nHány csillag legyen a képernyőn ?"); scanf ("%d", &n); fflush (stdin); } //do while (n <= 0); for (i=1; i<= n; i++) printf ("*"); } getch (); } // program vége
Növekményes ciklus a C-ben for (i=1; i<= n; i++) { printf ("*"); } Figyeljünk a szintaxisra ! A for utasításban a csukó zárójel után általában nincs pontosvessző ! Ha mégis kitesszük, az azt jelenti a fordító számára, hogy a ciklusmaghoz csak egy üres utasítás tartozik.
Növekményes ciklus a C-ben Az alábbi, egyetlen for utasítással az első n természetes szám összegét képezzük: for (i=1, osszeg=0; i <=n; osszeg += i, i++); init_kif: i=1, osszeg = 0; feltetel_kif: i<= 0; lépteto:kif: i++, osszeg += i
Ciklusok egymásba ágyazása Leggyakrabban a for ciklusokat szokás egymásba ágyazni. Feladat: készítsen szorzótáblát ! 1 2 3 4 5 6 7 8 9 10 12 14 16 18 15 21 24 27 20 28 32 36
Egymásba ágyazott ciklusok: szorzótábla Pszeudokód: Program Változók : szorzo1, szorzo2: pozitív egész Ki: "SZORZÓTÁBLA" //Következik a fejléc-sor kiírása Ciklus szorzo1 = 1 kezdőértéktől szorzó1 = 9 végértékig 1-es lépésközzel Ki: szorzo1 Ciklus vége //szorzo1 // a szorzótábla elemei Ciklus szorzo2 = 1 kezdőértéktől szorzó2 = 9 végértékig 1-es lépésközzel Ki: szorzo2 //első oszlop elemei… Ciklus szorzo1 = 1 kezdőér. szorzó1 = 9 végértékig 1-es lépésközzel Ki: szorzo1 * szorzo2 Ciklus vége //szorzo1 Ciklus vége //szorzo2 Program vége
Egymásba ágyazott ciklusok: szorzótábla void main (void) //egymásba ágyazott for ciklusok: szorzótábla kiiratás { int szorzo1, szorzo2; //a szorzótényezők, egyben a ciklusváltozók is printf ("\n SZORZÓTÁBLA\n\n "); for (szorzo1=1; szorzo1<10; szorzo1++) printf ("%3d", szorzo1); } //for szorzo1 printf ("\n"); for (szorzo2=1; szorzo2<10; szorzo2++) //Külső for ciklus printf ("\n%5d",szorzo2); for (szorzo1=1; szorzo1<10; szorzo1++) //Belső for ciklus printf ("%3d",szorzo1 * szorzo2); } //szorzo1 } //szorzo2 getch (); } // program vége
Egymásba ágyazott ciklusok: szorzótábla //egymásba ágyazott for ciklusok: for (szorzo2=1; szorzo2<10; szorzo2++) //Külső for c. { printf ("\n%5d",szorzo2); for (szorzo1=1; szorzo1<10; szorzo1++) //Belső f. printf ("%3d",szorzo1 * szorzo2); } //szorzo1 } //szorzo2
A break és a continue utasítások A break utasítás hatására az utasítást tartalmazó legközelebbi switch, while, for és do-while utasítások működése megszakad és a vezérlés a megszakított utasítás utáni első utasításra kerül. Egymásba ágyazott ciklusok, illetve a fenti utasítások egymásba ágyazása esetén a break utasítás mindig csak a legbelső utasításból való kilépést idézi elő. A continue utasítás a while, for és a do-while ciklusok soron következő iterációját indítja el, a ciklustörzsben a continue utasítást követő utasítások átlépésével. A break és a continue utasítások gyakori használata rossz programozási gyakorlatot jelent. Az egyszerűbb feladatok többnyire az áttekinthetően megoldhatók e két utasítás használata nélkül is. A continue utasításra példát a későbbiekben fogunk látni.
Kiugrás a ciklusból: 2.3.3.6. feladat: Keresse meg programmal a 2001 szám legnagyobb osztóját ! Elemezzük a feladatot: Egy egész szám osztója legalább kétszer megvan a számban, tehát a legnagyobb osztó keresését elegendő a szám felénél kezdeni, majd egyesével haladni lefelé, amíg az első olyan számot megtaláljuk, amellyel osztva 2001-et, a maradék = 0 Pszeudokód: Program Változók : oszto pozitív egész Ciklus oszto = 2001/2 kezdőértéktől 2 végértékig -1-es lépésközzel Ha (2001 mod oszto = 0) Ki: "A legnagyobb osztó:", oszto kiugrás ciklus vége Ki: "A vizsgálat befejeződött." Program vége
Kiugrás a ciklusból: 2.3.3.6. feladat: Struktúrált megoldás: Pszeudokód: Program Változók : oszto pozitív egész oszto = 2001/2 Ciklus amíg 2001 mod oszto <> 0 ÉS oszto > 1 oszto = oszto -1 ciklus vége Ki: "A vizsgálat befejeződött.” Ha oszto > 1 Ki: oszto Program vége
A break utasítás, példa void main (void) //kiugrás a ciklusmagból: egész szám legnagyobb osztója { int oszto; printf ("\n2001 legnagyobb osztóját keressük."); for (oszto = 2001/2; 1; oszto--) if (2001%oszto == 0) printf ("\n2001 legnagyobb osztója: %d", oszto);//megvan ! break; } printf ("\nA vizsgálat befejeződött."); getch (); } // program vége
FOR ciklus, példák // 1. feladat részlet //Hányszor fut le a ciklus ? //Mi jelenik meg a képernyőn ? int i, n=100; for (i=1, i==n, i++) printf (”\n i= %d”, i);
FOR ciklus, példák // 2. feladat részlet //Hányszor fut le a ciklus ? //Mi jelenik meg a képernyőn ? int i, n= 3; for (i=1, i<n, i++) printf (”\n *”); printf (”\n i= %d”, i);
FOR ciklus, példák // 3. feladat részlet //Hányszor fut le a ciklus ? //Mi jelenik meg a képernyőn ? int i, n= -3; for (i=1, i<n, i++) printf (”\n *”); printf (”\n i= %d”, i);