11. cvičení

Procvičování

Na tomto cvičení jsme procvičovali práci se soubory pomocí tříd dostupných ve standardní knihovně. Také jsme procvičili vytváření vlastních struktur/tříd s konstruktory, destruktorem a vlastními metodami.

Příklad na počítání slov jsem vložil do textu k předchozímu cvičení, naopak příklad na použití třídy std::stringstream uvádím zde.

Příklad: čtení souřadnic ze souboru

Chceme napsat program, který bude číst souřadnice \((x, y, z)\) ze souboru v následujícím formátu:

1.1  1.2  1.3
2.1  2.2  2.3
3.1  4.2  5.3
6.1  2.2  0.3

(Na každém řádku jsou postupně souřadnice \(x, y, z\) oddělené mezerami, počet řádků dopředu neznáme.)

S využitím operátoru >> bychom to mohli naprogramovat např. takto:

#include <iostream>
#include <fstream>
#include <string>
using namespace std;

int main()
{
    ifstream vstup("souradnice.txt");
    if (!vstup.good()) {
        cout << "soubor neslo otevrit" << endl;
        return 1;
    }

    int pocet = 0;
    while (!vstup.eof()) {
        double x = 0;
        double y = 0;
        double z = 0;
        vstup >> x >> y >> z;

        if (vstup.fail() || vstup.bad()) {
            break;
        }
        pocet++;
    }

    // kontrola, jak to dopadlo
    if (!vstup.eof()) {
        cout << "chyba, nedosli jsme az na konec souboru" << endl;
        return 1;
    }

    cout << "pocet bodu je " << pocet << endl;

    return 0;
}

Tento program funguje, pokud vstupní soubor obsahuje data přesně podle zadaného formátu. Pokud však na nějakém řádku chybí nebo přebývá nějaké číslo, program to nezpracuje správně – nedokáže rozpoznat, kdy se přejde na další řádek.

Abychom tento problém vyřešili, musíme změnit způsob načítání – místo operátoru >> použijeme funkci getline, což nám umožní rozpoznat data na jednotlivých řádcích. Další problém ale bude, jak přečíst čísla ze stringu, kde je uložený daný řádek, protože pro string nemůžeme použít operátor >>. Problém můžeme elegantně vyřešit pomocí třídy stringstream z hlavičkového souboru sstream, která reprezentuje „virtuální“ stream, do kterého můžeme zapisovat data pomocí operátoru << i z něho číst data pomocí operátoru >>:

#include <iostream>
#include <fstream>
#include <sstream>
#include <string>
using namespace std;

int main()
{
    ifstream vstup("souradnice.txt");
    if (!vstup.good()) {
        cout << "soubor neslo otevrit" << endl;
        return 1;
    }

    // 2. zpusob: cteni po radcich
    while (!vstup.eof()) {
        double x = 0;
        double y = 0;
        double z = 0;

        string radek;
        getline(vstup, radek);

        if (vstup.fail() || vstup.bad()) {
            break;
        }

        stringstream s;
        // zapsat radek do streamu
        s << radek;
        // precist cisla ze streamu do x, y, z
        s >> x >> y >> z;

        // kontrola, jestli se to povedlo
        if (s.fail() || s.bad()) {
            break;
        }

        pocet++;
    }

    // kontrola, jak to dopadlo
    if (!vstup.eof()) {
        cout << "chyba, nedosli jsme az na konec souboru" << endl;
        return 1;
    }

    cout << "pocet bodu je " << pocet << endl;

    return 0;
}