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

Dublowanie znaku przy odczycie z pliku

Ostatnio zmodyfikowano 2016-04-09 11:11
Autor Wiadomość
jaśkoo
Temat założony przez niniejszego użytkownika
Dublowanie znaku przy odczycie z pliku
» 2016-04-07 08:22:32
Witajcie, mam zadanie napisać program, który zlicza ilość wystąpień "*" w pliku. Pisząc program pojawiło się dla mnie kilka niejasności.
1. Dlaczego ostatni znak jest dublowany, czy to przy wyświetlaniu czy przy zliczaniu jeśli w tym przypadku jest to "*"? Dla zawartości pliku- "Ala * ma * kota *" Program wyświetla:
"A
l
a
*
m
a
*
k
o
t
a
*
*
4"
nie dość, że dubluje to jeszcze wlicza także tą zdublowaną "*".

2. Czy istnieje możliwość wczytywania z pliku znak po znaku bez pomijania znaków białych?

3. Czy wg Was taki układ zadeklarowanych zmiennych jest ok czy bardziej popieracie zmienne w jednym miejscu? Napisałem to w ten sposób mając na uwadze optymalizację kodu, żeby nie były tworzone zbędne na danym etapie zmienne jeśli np pliku nie odnaleziono.

4. plik.close(); umieścilibyście w ifie czy już za ifami i elsami?

5. Czy is.open() i .good() działają dokładnie tak samo?

C/C++
#include <iostream>
#include <fstream>
#include <cstdlib>

using namespace std;

void zliczanie()
{
    fstream plik;
    plik.open( "dokument.txt", ios::in );
    if( plik.good() )
    {
        char znak;
        int licznik = 0;
        while( !plik.eof() )
        {
            plik >> znak;
            cout << znak << endl;
            if( znak == '*' )
                 licznik++;
           
        }
        cout << licznik;
    }
    else
    {
        cout << "Nie odnaleziono pliku!";
        exit( 0 );
    }
    plik.close();
}

int main()
{
    zliczanie();
    return 0;
}
P-147036
mateczek
» 2016-04-07 09:05:52
C/C++
while( plik >> znak )
{
   
    cout << znak << endl;
    if( znak == '*' )
         licznik++;
   
}

// plik eof dopiero gdy odczyta znak z poza pliku. Więc masz jedno nadmiarowe wykonanie pętli.
//pobranie znaku się nie powiedzie więc zmienna "znak" ma poprzednią wartość którą zliczasz jeśli już to:

while( true ) {
    plik >> znak;
    if( plik.eof() ) break;
   
    cout << znak << endl;
    if( znak == '*' )
         licznik++;
   
}
P-147037
mokrowski
» 2016-04-07 10:52:57
C/C++
#include <iostream>
#include <fstream>
#include <cstdlib>

using namespace std;

void zliczanie( const char * plik_nazwa, const char znak_badany )
{
    size_t licznik = 0;
   
    // XXX: Dodatkowo otworzył bym binarnie .. choć to raczej "pieczołowitość" :-)
    fstream plik( plik_nazwa, ios::in | ios::binary );
   
    // XXX: fstream ma przeciążony operator!() i jest to to samo co fail()
    if( !plik )
    {
        // XXX: Tu na cerr bym wyprowadził błąd. Po to jest.
        cerr << "Nie odnaleziono pliku " << plik_nazwa << "!\n";
        exit( EXIT_FAILURE );
    }
   
    // XXX: A ja bym to for'em zrobił :-)
    for( char znak; plik >> znak; )
    {
        if( znak_badany == znak )
        {
            licznik++;
        }
        cout << znak << endl;
    }
   
    // XXX: Ja bym tu dał nową linię jeszcze.
    cout << licznik << endl;
   
    // XXX: Destruktor fstream wykonuje close() bo obiekt jest tworzony na stosie
}

int main()
{
    cout << zliczanie( "dokument.txt", '*' );
}
Tak naprawdę to Twoje zadanie to wykorzystanie algorytmu count_if z biblioteki standardowej. Oczywiście zakładając że nie potrzebujesz drukowania znaków. Bo jak potrzebujesz to... for_each także z bib. std.  :-)
Następna sprawa to pomieszanie 2 zadań w 1 funkcji. Tu masz: sprawdzenie czy plik się otworzył, zliczanie. Ja bym (jeśli można) wydzielił do 2 funkcji.
P-147039
jaśkoo
Temat założony przez niniejszego użytkownika
» 2016-04-07 13:10:55
@mateczek dlaczego eof dopiero po odczytaniu znaku? Do tej pory niejednokrotnie robiłem tak jak tu i działało, np tutaj:
C/C++
/*  Dany jest plik fizyczny liczby.dat zawieraj¹cy liczby rzeczywiste.
Napisz program, który liczby zapisane w tym pliku zapisze w pliku
kolmny.txt w trzech kolumnach */
#include <iostream>
#include <fstream>
#include <cstdlib>

using namespace std;

void kolumny()
{
    fstream plik;
    fstream plik2;
    int pomocnicza;
    int licznik = 0;
   
    plik.open( "liczby.dat", ios::in );
    if( plik.good() == false )
    {
        cout << "Nie odnaleziono pliku!";
        exit( 0 );
    }
    else
    {
        plik2.open( "kolumny.txt", ios::out );
        while( !plik.eof() )
        {
            plik >> pomocnicza;
            plik2 << pomocnicza << "   ";
            licznik++;
            if( licznik % 3 == 0 )
            {
                plik2 << endl;
            }
        }
        plik.close();
        plik2.close();
    }
}

int main()
{
    kolumny();
    cout << "DONE!";
    return 0;
}

@mokrowski do tego co napisałeś nawet się nie odniosę, bo nie mam pojęcia o czym tam piszesz, to jeszcze nie mój poziom, ale dzięki za zainteresowanie :)
P-147041
Monika90
» 2016-04-07 14:08:42
while (!plik.eof()) działało bo miałeś szczęście, np. plik nie kończył się białym znakiem, tylko cyfrą. Typowe pliki tekstowe kończą się znakiem '\n', w takiej sytuacji twoja błędna pętla odczyta ostatnią liczbę dwa razy (przed C++11) lub odczyta dodatkowe zero (C++11 i późniejsze).

Jeszcze gorsze rzeczy mogą się stać gdy w pliku trafi się jakaś litera, wtedy twoja pętla będzie nieskończona, dlatego nigdy nie używaj while (!plik.eof()) { }



2. Czy istnieje możliwość wczytywania z pliku znak po znaku bez pomijania znaków białych?

Istnieje, można użyć funkcji get
C/C++
char znak;
while( plik.get( znak ) )
{
    std::cout << + znak << '\n'; //wyświetl kod znaku
}
P-147042
jaśkoo
Temat założony przez niniejszego użytkownika
» 2016-04-07 15:36:06
Skoro eof się nie sprawdza czym proponujecie go zastąpić? Poza "while( plik >> znak )" znacie też coś analogicznego?
P-147044
carlosmay
» 2016-04-07 16:00:55
Skoro eof się nie sprawdza czym proponujecie go zastąpić? Poza "while( plik >> znak )" znacie też coś analogicznego?
Sprawdzaj ifem po odczytaniu znaku, ale przed rozpoczęciem nowej pętli.

Rozwiązanie takie zaproponował @mateczek.
@Monika90 podała też inne rowiązanie.
Twoja propozycja też jest dobra. Dlaczego nie chcesz jej używać? (pomija spacje).
P-147045
jaśkoo
Temat założony przez niniejszego użytkownika
» 2016-04-07 17:44:54
Do tej pory jej używałem, ale jeśli tak łatwo o jej niewłaściwe działanie, to chyba powinienem to zmienić. Jeśli chodzi o pętlę- "while( plik.get( znak ))" to zapewne zwraca true dopóki plik się nie skończył, a jakby ktoś jeszcze mógł wyjaśnić jak działa sama funkcja .get() i w odniesieniu do plików.
P-147047
« 1 » 2
  Strona 1 z 2 Następna strona