4. gyakorlat
Feladatok:
- Ellenőrzött beolvasás néhány módjának kipróbálása
(a programnak számokat kellene beolvasnia, de helyette egy számként nem
értelmezhető szöveg érkezik a bementről, hogyan kezelhető ez C++-ban)
- A program számítsa ki, hogy a 21-es kártyajáték szabályai szerint mennyit
érnek a "kézben tartott" lapjaink.
- Szorgalmi házi feladat a CANVAS-ban van kitűzve!
Ellenőrzött beolvasás
0. változat:
Egy 5 hosszú egészekből álló tömböt olvas be a program a standard
inputról nem ellenőriz semmit:
string s;
int a[5];
//Tömb elemei: a[0],a[1],a[2],a[3],a[4]
//0-dik változat: nincs ellenőrzés
for(int i=0;i<5;++i){
cout<<i+1<<". adat:";
cin>>a[i];
}
|
Tesztesetek:
- "Normális bevitel, minden kérdésre egy szám és <ENTER>
- "1.adat:" kérdésre több számot is beírunk, szóközzel elválasztva:
1. adat: 1 2 3 <ENTER>
- elejeszám, de szövegre végződik:
1.adat: 500Ft <ENTER>
- szöveg szám helyett:
1.adat: száz <ENTER>
- vegyesen:
1. adat: 1 szaz 5Ft 6 alma <ENTER>
- és minden egyéb lehetséges bemenet ...
Tehát látjuk, hogy milyen hibák fordulhatnak elő! |
1. változat:
//Első megoldás
for(int i=0; i<5; ++i){
bool helytelen;
do{
cout<<i+1<<". adat:";
cin>>a[i];
helytelen=cin.fail();
if (helytelen){
cin.clear();
getline(cin,s);
}
}while(helytelen);
} |
- A rendelkezésre álló cin.fail() függvény segítségével figyeljük a
hibát.
- Helytelen adat esetén cin.clear()-rel töröljük a hiba flageket.
- Mielőtt újra megkíséreljük az olvasást ki kell üríteni a bemenet
puffert, ezt végzi a getline. (Próbáljuk ki először anélkül.)
- Teszteljük az előbbi bemenetekre programunkat.
|
1. változat kicsit másképp:
//Első megoldás
for(int i=0; i<5; ++i){
bool helytelen;
do{
cout<<i+1<<". adat:";
cin>>a[i];
helytelen=cin.fail();
if (helytelen){
cin.clear();
}
getline(cin,s);
helytelen=helytelen || s!="";
if(helytelen)
cerr<<"Hibas szam vagy extra tobblet karakterek!\n";
}while(helytelen);
}
|
- A puffert "kitakarító" getline a helytelen ágból átkerül a belső
do-while ciklus utolsó pontjára, így minden adat beolvasása után lefut.
Ennek az az eredménye, hogy az "egy-soros" bevitelt nem engedjük meg:
minden számot külön sorba, <ENTER>-rel lezárva kell megadni.
- Ellenőrizzük továbbá, hogy az esetlegesen helyes szám után volt-e
még valami "szemét", ha igen, akkor sem fogadjuk el a beírt adatot
(például: "5 db" nem helyes).
- cin.clear() fontos, mert ha cin.fail() igaz, a getline() nem
hajtódik végre!
- Ellenörizhetjük még a bolvasott értéket is, a "vagy"-ot folytatva,
vagy új utasításban, például:
helytelen=helytelen || a[i]<0;
|
2. változat:
//Második megoldás
for(int i=0; i<5; ++i){
int e;
do{
cout<<i+1<<". adat:";
cin>>s; //stringbe olvasunk
e=atoi(s.c_str()); //stringet megpróbáljuk
átkonvertálni
}while(e==0 && s!="0");
a[i]=e;
} |
- atoi - szövegből próbál egész számot csinálni, C függvény, ezért kell
s-et átalakítani (s.c_str()). Ha nem sikerül a konverzió, 0 lesz az
eredmény. Ezért a hibát úgy vehetjük észre, hogy 0 lett az eredmény, de
nem "0" szöveg van s-ben.
- atoi testvére atof, valós számokra használható.
|
3. változat:
//Harmadik megoldás
for(int i=0; i<5; ++i){
int e;
do{
cout<<i+1<<". adat:";
getline(cin,s); //teljes sor beolvasása
e=atoi(s.c_str());
}while(e==0 && s!="0");
a[i]=e;
} |
- a 2-es változatot annyival módosítottuk, hogy cin>>s helyett getline(cin,s)
van, azaz a teljes sort beolvassuk (ENTER-ig mindent), így minden adatot
külön sorba, ENTER-rel lezárva kell megadni.
|
Innen letölthető az egyes változatokat tartalmazó program: main.cpp
21-es kártyajáték
Kezünkben van a magyar kártya néhány lapja. Számítsuk ki, mennyit érnek
lapjaink a 21-es játék szerint.
Megjegyzés: a kártyalapok színe mindegy, így a program csak azt kéri
be, hogy mi lap neve. A lap eleme a következő szövegekből álló halmaznak:
{"VII","VIII","IX","X","Also","Felso","Kiraly","Asz"}

- Az előfeltételben szereplő halmazt tömbbel valósítjuk meg, a
kártyalapoknak megfelelő szövegeket egy 8 hosszú, szöveg típusú tömbben
helyezzük el:
kartya: tömb[0..7:szöveg]={"VII","VIII","IX","X","Also","Felso","Kiraly","Asz"}
a program a beolvasott szöveget ebben a tömbben próbálja megkeresni.
- Az utófeltételben szereplő "ertek" nevű függvényt szintén egy tömb segítségével valósíthatjuk meg:
ertek: tömb[0..7:egész]={7,8,9,10,2,3,4,11}
a tömb rendre a "kartya" tömbben található lapoknak megfelelő értékkel van
feltöltve, így
ha a "kartya" tömbben megtaláltuk a lapot, akkor az "ertek" tömbből
meghatározhatjuk a lap értékét.
Felhasznált programozási tétel: Összegzés (sorozatszámítás speciális esete)



Felhasznált programozási tétel: Eldöntés (pesszimista változat)
Eldöntés tétel másik változata (optimista):
Induláshoz a játék keret programja:
21_indulo.cpp
A program kódja: 21.cpp
Fejlesszük tovább megoldásunkat:
Tudjuk, hogy a magyar kártyában mindegyik lapból 4 szerepel, beolvasásnál
ellenőrizzük, hogy ne lehessen egy adott lapból 4-nél többet megadni. (Ne
adhasson meg a felhasználó mondjuk 5-ször "Király" lapot.) Ellenőrizzük
beolvasásnál, hogy az adott lapból nincs-e már 4, ha igen jelezzük a hibát, és
kérjük újra a lapot! Melyik tételt használjuk, és hogyan?
A program kódja: 21_modositva.cpp
Egy érdekes változat:
Feltesszük, hogy egy pakliból osztjuk a lapokat. Ha a játékos újra játszik, csak azokból választhat,
amelyek még a pakliban maradtak. Az osztás előtt ki is írjuk minden körben, hogy melyik lapból hány
van még a pakliban. Ha a játékos mind a 32 lapot "kihúzta", a játék leáll. Továbbra is lehetősége van
arra, hogy egy kör végén abbahagyja a játékot.
A program kódja: 21_harmadik_valtozat.cpp
Gyakorló feladat, önálló megoldásra:
- A program olvasson be egy hónap nevet, ellenőrizze, hogy helyes-e, majd
írja ki római számmal, továbbá írja ki, hogy melyik évszakba esik az adott
hónap. (Téli hónapok: december, január, február, s.í.t.)
- Készítsünk programot, mely a napi dátumot olvassa be, majd ellenőrzi, hogy
helyes-e. Megadható dátum formák:
2012/2/4 vagy 2012/02/04 (eeee/h/n vagy eeee/hh/nn)
Ellenőrizendő:
- Évszám helyes-e : 1900 és 2100 között lehet
- Hónap helyes-e: 1 és 12 között lehet
- Nap helyes-e: figyelembe véve a hónapokat, van-e megadott nap a
hónapban. Február hónapban vegyük figyelembe a szökőéveket is. Ha az évszám
egy szökőév, akkor
lehessen megadni 29.-ét.
A megoldások.