problem ze zliczaniem linii, słów i znaków w pliku

0

Mam taki kod do zliczania linii, slow i znakow podanego jako parametr pliku:

main(int argc,char* argv[])
{
        int licznik_linii=0,licznik_slow=0,licznik_znakow=0;
        char bufor[1024],ch;
        ifstream plik;
        plik.open(argv[1]);
        if(plik.fail())
        {
                cout<<"blad przy otwarciu pliku";
                exit(1);
        }
        do
        {
                plik.getline(bufor,1024);
                licznik_linii++;
        }
        while(!plik.eof());
        plik.close();
        plik.open(argv[1]);
        do
        {
                plik>>bufor;
                licznik_slow++;
        }
        while(!plik.eof());
        plik.close();
        plik.open(argv[1]);
        while(ch)
        {
                plik.get(ch);
                licznik_znakow++;
        }
        plik.close();
        cout<<"Plik: "<<argv[1];
        cout<<"\nliczba linii: "<<licznik_linii<<"\nliczba slow: "<<licznik_slow<<"\nliczba znakow: "<<licznik_znakow;
        getch();
}

Problem jest taki że zliczane są tylko linie, a wyniki ilosci slow i znakow wynosza 0, nie mam pojęcia dlaczego, przeciez pliki sa zamykane i otwierane porzy kazdej z 3 operacji. Prosze o pomoc.

0

czy naprawdę nikt nie potrafi tutaj pomóc ?

1

heya
nie znam wcale tego ifstream, ale moze cie naprowadze
a) dziwne ze ilosc slow ZAWSZE jest 0, wg kodu nawet w wypadku skrajnym (czyli np pustym pliku) ilosc slow powinna byc 1...

    plik.open(argv[1]);
    do
    {
        plik>>bufor;
        licznik_slow++;
    }
    while(!plik.eof());

ta petla bedzie przynajmniej raz na pewno wykonana...
poza tym pewien jestes ze plik>>bufor wrzuci do bufora tylko jeden wyraz ?

b) ze ci nie liczy liter to nie ma co sie dziwic...

    while(ch)
    {
        plik.get(ch);
        licznik_znakow++;
    }
    plik.close();

przemysl jak ta petla sie zachowa jesli ch przez przypadek jest rowny 0 na poczatku, przed odczytem czegokolwiek z pliku... hm? petle ani razu nie bedzie wykonana ? bingo ;>... poza tym na moje okono \0 to tez jest znak ;p wiec dziiiiiiiiwny warunek dales... lepiej daj to cale !plik.eof( ) ;p chociaz glowy nie dam czy nie bedzie tego samego co z feof, czyli to zaskoczy dopiero PO procie odczytu po koncu pliku, czyli wynik bedzie o 1 przeklamany...

pozdrawiam

0

ad a) Mój błąd masz racje, pętla z warunkiem na końcu wykonuje sie przynajmniej raz. Natomiast jeżeli chodzi o to czy jestem pewien tego "plik>>bufor" to tak, bo operator ekstrakcji jezeli po lewej stronie jest obiekt typu ifstream a po prawej tablica znakowa wypisuje do niej slowo po slowie (ciagi znakow od spacji do spacji) więc dalej nie wiem gdzie jest błąd :-(

ad b) tutaj masz racje, no ale jak są na poczatku śmieci w zmiennej automatycznej to nie powinny one byc rowne 0, no a zamysł jest taki że bedzie czytał znak po znaku az napotka NULL. Jednak próbowałem z tym warunkiem plik.eof() i też to samo (czyli jezeli pętla z warunkiem na pocżatku to 0 a jezeli warunek na koncu to 1) czyli dalej nic :-(

0

Problem jest taki: strumienie plikowe dzialaja tak ze jak sie je otworzy i wczytuje z nich az do konca pliku to gdy to sie stanie ustawia sie failbit . To ze zamykasz plik nie pomoze - musisz recznie wyczyscic failbit.
Robi sie to (chyba - nie pamietam a pisze z glowy):
file.setf(file.rdstate() && ~ios::failbit);
Moze to powyzej jest zle ale powinno Cie naprowadzic.

Moj poprzednik ma racje - petle wykonaja sie przynajmniej raz, nawet dla pustego pliku wszystkie liczniki zwroca na koniec 1. Zmien do...while() na while():
while(file>>bufor) {
++licznik;
}
Dziala to tak ze operator >> zwraca referencje do file, czyli strumienia na rzecz ktorego zostal wywolany, a jedna z funkcji klas strumieni jest konwersja na bool, i to wlasnie dzieje sie w tym while.

0

Sprawdzilem ta funkcje resetujaca failbit, powinno byc tak:

file.clear(file.rdstate() & ~ios::failbit);

Sorki za blad.

0

niestety zresetowanie flagi nic nie dało, kod który podałeś umieściłem między pętlami i próbowałem na dwa sposoby: bez zamykania plików + to resetowanie i z zamykaniem + resetowanie, dalej nic :-( dziwna sprawa

0

Napisalem takie cos:

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

main(int argc,char* argv[])
{
    if(argc<2) {
    	cout<<"brak nazwy pliku";
    	return 1;
    }
	unsigned linie=0,slowa=0,znaki=0;
    string bufor;
    ifstream plik(argv[1]);
    if(!plik) {
        cout<<"blad przy otwarciu pliku";
        return -1;
	}
	while(getline(plik,bufor)) {
		++linie;
		znaki+=bufor.length();
	}
	plik.clear(plik.rdstate() & ~ios::eofbit & ~ios::failbit);
	plik.seekg(0);
	while(plik>>bufor) ++slowa;
	cout<<"Plik: "<<argv[1];
    cout<<"\nliczba linii: "<<linie<<"\nliczba slow: "<<slowa<<"\nliczba znakow: "<<znaki;
}
//nie trzeba uzywac plik.close() bo destruktor ~ifstream::ifstream() zapewnia zamkniecie

Kompilator Borland C++ Builder kompiluje bez bledow ani warningow wiec powinno dzialac. Pozdrawiam.

0

no dzięki twoja wersja działa, ale powiedzcie mi dlaczego mój kod (pierwszy post) nie liczy tego, dodałem teraz czyszczenie tego failbit tak jak Ali G między kolejnymi zliczaniami i nic, po wstawieniu tego czyszczenia nie ma praktycznej różnicy między moją wersją a werjsą Ali G! Gdzie jest błąd ??

0

W kodzie jest kilka bledow - poza tym ze petle zawsze zlicza o jeden znajk/slowo/linie za duzo:
po skonczeniu petli liczacej linie i zamknieciu pliku otworz go i wywolaj funkcje:

plik.clear(); - ustawia ona stan pliku na ios::goodbit

To samo po drugiej petli.
3 petla jest zla (jak to ktos zauwazyl wczesniej) poniewaz uzywasz jako warunku zmiennej ch ktora moze miec watrosc 0, a do tego pierwszy przebieg petli opiera sie na niezainicjalizowanej zmiennej (u mnie w ogóle byl to blad kompilacji), zamien to na:

while(plik.get(c)) ++licznik_znakow;

Jesli skonczy sie plik strumien ustawi failbit i zakonczy to petle.
Zauwaz tez ze taka petla liczy tez tzw. biale znaki, ale moze o to Ci wlasnie chodzi.

0

dzięki, jeszcze tylko jedna mała rzecz o której zapomniałem w poprzednim poście, do czego służy i jak działa plik.seekg(0);

0

Ta funkcja ustawia przesuniecie "kursora" czytania z pliku na podana bezwzgledna wartosc (seekg od seek get), mozliwa jest jeszcze inna przeciazona wersja:
seek(liczba,wzgledem) - wzgledem moze miec wartosci: ios::beg - ustawia wzgledem poczatku (ujemna wartosc jest bez sensu); ios::end - wzgledem konca (dodatnia wartosc bez sensu) oraz ios::cur (albo curr - nie pamietam) wzgledem aktualnego polozenia kursora.
funkcja tellg() zwraca aktualne przesuniecie kursora

Obie te funkcje sa dostepne dla strumieni ifstream oraz fstream

Dla ofstream sa dostepne odpowiednie wersje tellp() (od tell put) i seekp()

Zatem plik.seekg(0) ustawia kursor czytania na poczatku pliku.

Ale o tym jest w kazdym kursie, ksiazce czy chociazby w helpie!!

1 użytkowników online, w tym zalogowanych: 0, gości: 1