Panel użytkownika
Nazwa użytkownika:
Hasło:
Nie masz jeszcze konta?

[Rozdział 34] Zadanie domowe 2 [ trudne ]

Ostatnio zmodyfikowano 2016-05-12 13:43
Autor Wiadomość
Aran_swiezak
Temat założony przez niniejszego użytkownika
[Rozdział 34] Zadanie domowe 2 [ trudne ]
» 2016-03-21 20:51:05
Napisz program, który dla każdego wiersza w pliku:
- wczyta liczby i wypisze ich sumę w przypadku, gdy wszystkie liczby uda się wczytać;
- wypisze komunikat o błędnych danych, jeżeli wystąpi błąd podczas wczytywania liczb (komunikat ma wyświetlać numer wiersza, w którym wystąpił błąd).

Program się kompiluje i działa prawidłowo do momentu wczytania ostatnich znaków w pliku, wtedy zamiast wykryć koniec pliku i zakończyć pętlę while nadal wczytuje dane(krzaki). Mimo wielu prób nie mogę znaleźć błędu więc proszę o pomoc. Być może warunek lub działanie metody eof klasy fstream nie jest przezemnie dobrze rozumiane.

Oto moja funkcja odpowiedzialna za wczytywanie danych z pliku:

C/C++
bool wczytajPlik( string nazwaPliku )
{
    ifstream plik;
    plik.open( nazwaPliku.c_str() );
    if( !plik.good() )
         return false;
   
    if( plik.good() )
    {
        string wiersz;
        cout << "Dane z pliku: " << endl;
        while( getline( plik, wiersz ) )
             cout << wiersz << endl;
       
        cout << endl;
        plik.close();
    }
    plik.open( nazwaPliku.c_str() );
    int a; //wczytywana liczba
    char x; //wczytywany znak
    int b = 0; //suma liczb w wierszu
    int c = 1; //numer wiersza
    bool czyBylyBledy = false; //rejestracja blednego wczytania danych ( warunek )
    while( !plik.eof() )
    {
        plik >> a;
        if( plik.good() )
             b += a;
       
        if( !plik.good() )
        {
            cout << "Bledne dane w wierszu nr " << c << "!" << endl;
            czyBylyBledy = true;
            plik.clear();
            plik >> x;
            if( !plik.good() )
            {
                cout << "Blad wczytywania danych! " << endl;
                return 0;
            }
        }
       
        if( czyNapotkanoZnakNowegoWiersza( plik ) )
        {
            if( czyBylyBledy == false )
                 cout << b << endl;
           
            if( czyBylyBledy == true )
                 czyBylyBledy = false;
           
            b = 0;
            c++;
        }
    }
    return true;
}
P-146381
carlosmay
» 2016-03-22 06:01:00
Doczytanie do końca pliku nie ustawia EOF, dopiero próba odczytania czegoś,
gdy wskaźnik odczytu jest na końcu pliku.

Oprogramuj wczytywanie liczb w podobny sposób jak getlin() wcześniej.

plik >> a >> x >> b
P-146403
Aran_swiezak
Temat założony przez niniejszego użytkownika
» 2016-03-22 13:39:27
Tak jak napisałeś doczytanie do końca pliku - wczytanie ostatniego znaku w pliku zakończone powodzeniem nie ustawia EOF jednak kolejną akcją jest próba wczytania kolejnego znaku (którego nie ma) i najwyraźniej wczytuje(tworzy?) krzaki.
Jeśli chodzi o wczytywanie zasugerowane przez Ciebie to w przypadku gdy mam losową i różną ilość danych w każdym wierszu (mieszanka cyfr, liter i znaków) tego typu wczytywanie chyba mi nie pomoże - przykładowo gdy w wierszu będą 2 cyfry to trzecią pobierze z wiersza następnego.
Poza tym wczytywanie pojedynczo znaków też musi zadziałać jeśli program wykryje w jakiś sposób koniec pliku a najwyraźniej próba wczytania znaku po końcu pliku go o tym nie uświadamia...
P-146413
carlosmay
» 2016-03-22 18:19:03
Jeśli chodzi o wczytywanie zasugerowane przez Ciebie to w przypadku gdy mam losową i różną ilość danych w każdym wierszu (mieszanka cyfr, liter i znaków) tego typu wczytywanie chyba mi nie pomoże
Tak. Jest podobne zadanie i pomyliłem się.

C/C++
{
    std::ifstream plik( "test.txt" );
    if( plik.is_open() ) {
        int wiersz = 1;
        int suma = 0;
        char znak;
        bool flag;
       
        do {
            flag = true;
            suma = 0;
            while( !czyNapotkanoZnakNowegoWiersza( plik ) && !plik.eof() ) {
                if(( plik >> znak ) && isdigit( znak ) ) {
                    suma += znak - '0';
                }
                else {
                    flag = false;
                    while( plik.get() != '\n' )
                         continue;
                   
                    break;
                }
            }
           
            if( plik.eof() ) {
                break;
            }
            else if( flag ) {
                std::cout << suma << std::endl;
            }
            else {
                std::cout << "Bledne dane w wierszu " << wiersz << '!' << std::endl;
            }
            ++wiersz;
        } while( !plik.eof() );
       
    }
P-146420
KrulTibianus
» 2016-05-12 13:43:15
Pozwolę sobie (chyba nikt się nie obrazi:) odświeżyć temat i wrzucić tu swoje rozwiązanie. Po przeglądnięciu około 10 tematów z tym zadaniem, wreszcie udało mi się dojść do ostatecznego rozwiązania. Kluczowa była metoda ignore, która po wykryciu błędnej danej, pozwala na przejście do kolejnego wiersza.

Minusem mojego rozwiązania jest brak rozbicia kodu na funkcje.
W przeglądanych przeze mnie tematach kody były nieskończone, lub nie działały do końca jak powinny. To rozwiązanie może się komuś przydać.

C/C++
#include <iostream>
#include <string>
#include <fstream>
#include <limits>

/* Napisz program, który dla każdego wiersza w pliku:
-wczyta liczby i wypisze ich sumę w przypadku, gdy wszystkie liczby uda się wczytać;
-wypisze komunikat o błędnych danych, jeżeli wystąpi błąd podczas wczytywania liczb
(komunikat ma wyświetlać numer wiersza, w którym wystąpił błąd).*/

bool czyNapotkanoZnakNowegoWiersza( std::ifstream & plik )
{
    char cZnak;
    for(;; ) //nieskończona pętla
    {
        plik.clear();
        cZnak = plik.peek(); //sprawdzamy jaki kolejny znak zostanie zwrócony przez operację odczytu
        if( plik.fail() || plik.bad() )
             return false; //wystąpił błąd odczytu danych
       
        if( !isspace( cZnak ) )
             return false; //pobrany znak nie jest białym znakiem
       
        plik.get( cZnak ); //odczytujemy biały znak z pliku
        if( plik.fail() || plik.bad() )
             return false; //wystąpił błąd odczytu danych
       
        if( cZnak == '\n' )
             return true;
       
    } //for
}

int main()
{
    std::ifstream plik;
    int wiersz = 1;
    int wynik = 0;
   
    plik.open( "tekst.txt" );
   
    if( !plik.fail() )
         std::cout << "Udalo sie otworzyc plik.\n" << std::endl;
    else
    {
        std::cout << "Nie udalo sie otworzyc pliku.";
        return 0;
    }
   
    while( !plik.eof() )
    {
        plik.clear();
        int liczba;
       
        plik >> liczba;
       
        if( plik.bad() )
        {
            std::cout << "Wystapil blad sprzetowy przy wczytywaniu liczby!" << std::endl;
            plik.close();
            return 0;
        }
       
        if( plik.fail() )
        {
            plik.clear();
            std::cout << "Bledne dane w wierszu " << wiersz << std::endl;
            wiersz++;
            plik.ignore( std::numeric_limits < std::streamsize >::max(), '\n' );
            wynik = 0;
            continue;
        } else
        {
            //std::cout << "Dodaje " << liczba << " do " << wynik << std::endl;
            wynik += liczba;
        }
       
        if( czyNapotkanoZnakNowegoWiersza( plik ) || plik.eof() )
        {
            std::cout << "Wynik w wierszu " << wiersz << " = " << wynik << std::endl;
            wiersz++;
            wynik = 0;
        }
    }
    plik.close();
    return 0;
}
P-148143
« 1 »
  Strona 1 z 1