IT rekvalifikácia. Seniorní programátori zarábajú až 6 000 €/mesiac a rekvalifikácia je prvým krokom. Zisti, ako na to!

Ošetrenie užívateľských vstupov

Dnes to bude v C ++ tutoriálu také oddychové, dokončíme si totiž našu kalkulačku, ďalej už ju nebudeme potrebovať a bolo by pekné ju dotiahnuť do konca. Asi tušíte, že u nej chýba zabezpečenia vstupov od užívateľa, tým sa bude zaoberať dnešný lekcie.

Pripomeňme si kód našej kalkulačky:

cout << "Vitejte v kalkulacce" << endl;
string pokracovat = "ano";
while (pokracovat == "ano")
{
    cout << "Zadejte prvni cislo:" << endl;
    float a;
    cin >> a;
    cout << "Zadejte druhe cislo:" << endl;
    float b;
    cin >> b;
    cout << "Zvolte si operaci:" << endl;
    cout << "1 - scitani" << endl;
    cout << "2 - odcitani" << endl;
    cout << "3 - nasobeni" << endl;
    cout << "4 - deleni" << endl;
    int volba;
    cin >> volba;
    float vysledek = 0.0f;
    switch(volba)
    {
        case 1:
            vysledek = a + b;
            break;
        case 2:
            vysledek = a - b;
            break;
        case 3:
            vysledek = a * b;
            break;
        case 4:
            vysledek = a / b;
            break;
    }
    if ((volba > 0) && (volba < 5))
        cout << "Vysledek: " << vysledek << endl;
    else
        cout << "Neplatna volba" << endl;
    cout << "Prejete si zadat dalsi priklad? [ano/ne]" << endl;
    cin >> pokracovat;
}
cout << "Dekuji za pouziti kalkulacky, aplikaci ukoncite libovolnou klavesou." << endl;
cin.get(); cin.get();

Vstupy od užívateľa by sme mali vždy ošetrovať. Poviem vám tajomstvo úspešných a obľúbených aplikácií, je veľmi jednoduché: Počítajú s tým, že je používateľ úplný hlupák :) . Čím hlúpejšieho užívateľa budete predpokladať, tým väčší úspech budú vaše aplikácie mať. Pokiaľ tu používateľ zadá miesto "áno" napr. "Áno." (Áno bodka) alebo "Áno" (s veľkým písmenom), program rovnako skončí. To ešte nemusí byť kvôli hlúposti, ale preto, že sa preklepli. Môže nám však zadať aj niečo úplne nezmyselného, napr. "Možno".

To však nie je najväčší problém nášho programu, keď používateľ nezadá číslo, ale nejaký nezmysel, celý program sa zastaví a spadne s chybou. Poďme teraz tieto dva problémy opraviť.

Na overenie správnosti vstupu použijeme funkciu stoi (). Tú nájdeme v knižnici string. Postup bude nasledujúci:

  1. požiadame užívateľa o zadanie hodnoty
  2. miesto do číselnej premennej načítame vstup do stringu
  3. pokúsime sa text previesť na číslo
  4. v prípade neúspechu sa vrátime k bodu 1

Jediná ťažkosť je v tom, ako spoznať neúspech. K tomu slúži výnimky. Podrobne sa nimi budeme zaoberať až u objektov. Zatiaľ bude musieť stačiť to, že výnimka je spôsob, ako vyslať správu o chybe. Ak túto správu nikde nezachytíme, ukončí program. K jej zachytenie slúži blok try-catch. Ten vyzerá takto:

try {
    // příkazy, které mohou výjimku způsobit
} catch (prvniTypVyjimky v1) {
    // ošetření chyby typu prvniTypVyjimky
} catch (druhyTypVyjimky v2) {
    // ošetření výjimky typu druhyTypVyjimky
}

Časťou catch môže byť ľubovoľný počet. Ak namiesto premennej u catch napíšeme tri bodky (...) zachytíme tu ľubovoľnú výnimku (ak je časťou catch viac, bodky smie byť len u tej poslednej). Ako výnimku vyvolať si vysvetlíme neskôr, bude nám je teraz stačiť vedieť zachytávať.

Funkcia stoi () vyvoláva 2 typy výnimiek:

  • invalid_argument ak nedokáže zo stringu prečítať číslo
  • out_of_range ak sa prečítané číslo nezmestí do typu int

Náš kód môže teda vyzerať napríklad takto:

int i;
string s;
while (true)
{
    try
    {
        cin >> s;
        i = stoi(s);
        break;
    }
    catch (invalid_argument& exception)
    {
        cout << "Nebylo zadano cislo" << endl;
    }
    catch (out_of_range& exception)
    {
        cout << "Cislo je prilis velke (nebo prilis male)" << endl;
    }
}

Ak sa prevod nepodarí, skočí sa rovno na príslušného catch bloku a príkaz break sa tým pádom preskočí. Akonáhle sa prevod povedie, vyskočíme z cyklu a pokračujeme za ním.

Funkcie pre ďalšie dátové typy

Ako vás už asi napadlo, typ int nie je jediným typom, ktorý sa dá zo stringu čítať (tzv. Parsovať). Konkrétne funkcie pre načítanie ďalších typov máte nižšie v tabuľke:

dátový typ funkcia počet parametrov
float stof () 1 - 2
double Stod () 1 - 2
long double stold () 1 - 2
int stoi () 1 - 3
long stor () 1 - 3
long long Stoll () 1 - 3
unsigned long stoul () 1 - 3
unsigned long long stoull () 1 - 3
Okrem stringu na prevedenie môžeme týmto funkciám odovzdať ešte ukazovateľ na typ size_t (číselný typ). Po prevedení sa nám do tohto ukazovateľa uloží pozície, kde prevod skončil. To je užitočné potrebné pre čítanie niekoľkých čísel oddelených napr. Medzerami. Ak namiesto neho uvedieme nullptr, bude ignorovaný.

U funkcií pre celočíselné typy môžeme uviesť ešte číselnú sústavu, ktorá sa má použiť. Napr. čítanie čísla zapísaného v šestnástkovej sústave do typu unsigned long by teda mohlo vyzerať takto:

unsigned long cislo = stoul(str, nullptr, 16);

Ideme teda konečne upraviť našu kalkulačku:

cout << "Vitejte v kalkulacce" << endl;
string pokracovat = "ano";
string s;
while (pokracovat == "ano")
{
    cout << "Zadejte prvni cislo:" << endl;
    float a;
    while (true)
    {
        try
        {
            cin >> s;
            a = stoi(s);
            break;
        }
        catch (invalid_argument& exception)
        {
            cout << "Nebylo zadano cislo" << endl;
        }
        catch (out_of_range& exception)
        {
            cout << "Cislo je prilis velke (nebo prilis male)" << endl;
        }
    }
    cout << "Zadejte druhé číslo:" << endl;
    float b;
    while (true)
    {
        try
        {
            cin >> s;
            b = stoi(s);
            break;
        }
        catch (invalid_argument& exception)
        {
            cout << "Nebylo zadano cislo" << endl;
        }
        catch (out_of_range& exception)
        {
            cout << "Cislo je prilis velke (nebo prilis male)" << endl;
        }
    }

    // ...
    // zbytek programu
    // ...

}
cout << "Dekuji za pouziti kalkulacky, aplikaci ukoncite libovolnou klavesou." << endl;
cin.get(); cin.get();

Teraz sa ešte pozrieme na výber operácie a pokračovanie. Obe voľby teraz načítame ako string. To ale nie je nutné, pre výber z menu nám stačí iba jeden znak. Jeden znak prečítame už známu konštrukcií cin.get (). Ak bola zadaná zlá hodnota, odchytíme to v samotnom switch i. Problémom je, že cin.get () prečíta aj enter z minulého zadania. Musíme teda vstup opäť prečítať viackrát.

char volba;
do
{
    volba = cin.get();
} while (volba == '\n');
switch (volba) {
case '1':
    cout << "Vysledek: " << (a + b) << endl;
    break;
case '2':
    cout << "Vysledek: " << (a - b) << endl;
    break;
case '3':
    cout << "Vysledek: " << (a * b) << endl;
    break;
case '4':
    if (b != 0)
        cout << "Vysledek: " << (a / b) << endl;
    else
        cout << "Nulou nelze delit!" << endl;
    break;
default:
    cout << "Neplatna volba" << endl;
    break;
}

Do premennej voľba si uložíme stlačený znak ako char. Pretože sa rozsah znakov nedá už tak jednoducho otestovať podmienkou, urobíme kontrolu iným spôsobom, ako keď sme načítali voľbu ako int. Pripravíme si premennú platnaVolba typu bool, ktorú nastavíme na true (budeme predpokladať, že je voľba správna). Switch zostane podobný, len čísla dáme teraz do apostrofov, pretože sa jedná o jednotlivé znaky. Pridáme možnosť default, ktorá v prípade iné hodnoty než menovaných nastaví nami pripravenú premennú platnaVolba na false. Potom nie je nič jednoduchšie, než premennú otestovať. Vyskúšajte si to, program sa používa teraz pohodlnejšie.

K tomu ešte upravíme počítanie výsledku a ošetríme delenie nulou.

Nakoniec upravíme aj výzvu na pokračovanie, zadávať budeme opäť char A / N, budeme tolerovať rôznu veľkosť písmen a reagovať na zlé zadanie. Opäť použijeme switch, našu premennú pokracovat zmeníme na typ bool. Kód je asi zbytočné viac popisovať, za zmienku stojí len funkcie tolower(), ktorá prevádza veľké písmená na malé.

cout << "Vitejte v kalkulacce" << endl;
bool pokracovat = true;
while (pokracovat)
{
    // nacteni cisel
    string s;
    cout << "Zadejte prvni cislo:" << endl;
    float a;
    while (true)
    {
        try
        {
            cin >> s;
            a = stoi(s);
            break;
        }
        catch (invalid_argument& exception)
        {
            cout << "Nebylo zadano cislo" << endl;
        }
        catch (out_of_range& exception)
        {
            cout << "Cislo je prilis velke (nebo prilis male)" << endl;
        }
    }
    cout << "Zadejte druhe cislo:" << endl;
    float b;
    while (true)
    {
        try
        {
            cin >> s;
            b = stoi(s);
            break;
        }
        catch (invalid_argument& exception)
        {
            cout << "Nebylo zadano cislo" << endl;
        }
        catch (out_of_range& exception)
        {
            cout << "Cislo je prilis velke (nebo prilis male)" << endl;
        }
    }

    // volba operace a výpočet
    cout << "Zvolte si operaci:" << endl;
    cout << "1 - scitani" << endl;
    cout << "2 - odcitani" << endl;
    cout << "3 - nasobeni" << endl;
    cout << "4 - deleni" << endl;
    char volba;
    do
    {
        volba = cin.get();
    } while (volba == '\n');
    switch (volba)
    {
        case '1':
            cout << "Vysledek: " << (a + b) << endl;
            break;
        case '2':
            cout << "Vysledek: " << (a - b) << endl;
            break;
        case '3':
            cout << "Vysledek: " << (a * b) << endl;
            break;
        case '4':
            if (b != 0)
                cout << "Vysledek: " << (a / b) << endl;
            else
                cout << "Nulou nelze delit!" << endl;
            break;
        default:
            cout << "Neplatna volba" << endl;
            break;
    }

    // dotaz na pokračování
    cout << "Prejete si zadat dalsi priklad? [a/n]" << endl;
    bool platnaVolba = false;
    while (!platnaVolba)
    {
        char volba;
        do
        {
            volba = cin.get();
        } while (volba == '\n');
        switch (volba) {
        case 'a':
            pokracovat = true;
            platnaVolba = true;
            break;
        case 'n':
            pokracovat = false;
            platnaVolba = true;
            break;
        case 224:
            _getch();
        default:
            cout << "Neplatna volba, zadejte prosim a/n" << endl;
            break;
        }
    }
}
cout << "Dekuji za pouziti kalkulacky, aplikaci ukoncite libovolnou klavesou." << endl;
cin.get(); cin.get();
return 0;
Jednoduchá konzolová kalkulačka v C ++ s ošetrením vstupov - Zdrojákoviště C ++ - Základná konštrukcia

Gratulujem, práve ste vytvorili svoj prvý blbovzdorný program :) Kód sa nám trochu skomplikoval, snáď ste to všetko pochytia. Niekedy v budúcnosti to napravíme a rozdelíme ho do prehľadných funkcií.


 

Stiahnuť

Stiahnutím nasledujúceho súboru súhlasíš s licenčnými podmienkami

Stiahnuté 204x (8.83 kB)
Aplikácia je vrátane zdrojových kódov v jazyku C++

 

Všetky články v sekcii
Zdrojákoviště C ++ - Základná konštrukcia
Článok pre vás napísal Zdeněk Pavlátka
Avatar
Užívateľské hodnotenie:
Ešte nikto nehodnotil, buď prvý!
Autor se věnuje spoustě zajímavých věcí ze světa informatiky a grafiky
Aktivity