4. gyakorlat

Feladatok:

 


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

Felhasznált programozási tétel: Összegzés (sorozatszámítás speciális esete)

sorozatszamitas elso specifikacio sorozatszamitas osszegzesre
sorozatszamitas vegleges specifikacio sorozatszamitas algoritmusai

Felhasznált programozási tétel: Eldöntés (pesszimista változat)

Eldontes (pesszimista) Eldontes (pesszimista) algoritmusa

Eldöntés tétel másik változata (optimista):

Eldontes (optimista) specifikacio Eldontes (optimista) algoritmus

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:

  1. 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.)
  2. 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ő:

A megoldások.