Bufor strumienia

0

Inspiracja

http://4programmers.net/Forum/C_i_C++/179733-mediana_liczb_z_pliku

Problem - bufor strumieni, jego zawartosc i poruszanie sie po zawartosci bufora.

  1. Weźmy standardowe strumienie cin i cout:
    Jak to jest? Skoro są to funkcje symetryczne, hmm czyli dane wczytane za pomocą cout będą na tym samym stosie co cout? Dalej. flush() czy endl powoduje opróżnienie ich przez - wypisanie ich na ekran?

Weźmy strumienie plików ifstream i ofstream:
Dane płyną z pliku data.txt , powiedzmy że mam dwa wyrazy w pliku i liczbę:
RAZ DWA 3

  1. Wczytam RAZ do slowo[0], DWA do slowo[1], i 3 do int liczba taką instrukcją?
    wejscie >> slowo[0] >> slowo[1] >> liczba;

Jeżeli slowo to tablica stringów to powinienem dopisać takim ściąganiem koniec stringu ?
I czy muszę dodawać do końca pliku eof, żeby to nie był nieskończony plik?

analogicznie do wczytywania:
wyjscie << slowo[0] << ' ' << slowo[1] << ' ' << liczba <<'\0' ;

  1. Czy będę musiał poruszać wskaźnikiem po pliku po wczytaniu każdego elementu, czy klasa strumienia sama zadba o to że jak jest spacja to ją usunie i wczyta kolejne słowo, później znowu usunie spację i przesunie wskaźnik na liczbę, po której jest eof? czy muszę używać seekg() i seekp()?
0

EOF to brak znaku, czyli żadnego EOF nie trzeba zapisywać.
Słowa i liczby mogą być rozdzielone dowolną ilością: spacji, tabulacji, enterów oraz innych białych znaków.
zapis:
strumien>>liczba;
najpierw pomija wszystkie białe znaki potem próbuje wczytać liczbę. Ze słowem jest analogicznie.

0
_13th_Dragon napisał(a)

EOF to brak znaku, czyli żadnego EOF nie trzeba zapisywać.
Słowa i liczby mogą być rozdzielone dowolną ilością: spacji, tabulacji, enterów oraz innych białych znaków.
zapis:
strumien>>liczba;
najpierw pomija wszystkie białe znaki potem próbuje wczytać liczbę. Ze słowem jest analogicznie.

Ale:

data.txt {RAZ DWA 3 [EOF]}

ifstream("data.txt");
while(!wejscie.eof())
wejscie << slowo[0] << slowo[1] << liczba;

czy to mi wczyta do stringa najpierw RAZ później DWA na miejscie RAZ a później 3 na miejsce R(czyli pierwszy element stringa)?
bo - nie przesuwam wskaźnika w pliku:
seekg(+length(slowo[0]), ioscurr);seekg(+length(slowo[1]), ioscurr);seekg(+licznik_cyfr, ioscurr)

4.dopisuje kolejny problem - licznik cyfr jako poruszanie sie po pliku z liczbami.

A tak ładnie zaznaczyłem problemy...

0

TAK!
każdy odczyt zawsze przesuwa wskaźnik odczytu, najefektywniej wczytuje/zapisuje się sekwencje danych, stąd właśnie określenie strumień danych.

0

To co podałeś nawet się nie skompiluje.
Natomiast to:

ifstream wejscie("data.txt");
while(wejscie) wejscie >> slowo[0] >> slowo[1] >> liczba;

Odczyta ci nawet kilka wierszy.

0
ChS napisał(a)

czy to mi wczyta do stringa najpierw RAZ później DWA na miejscie RAZ a później 3 na miejsce R(czyli pierwszy element stringa)?

RAZ wczyta Ci do 1 elementu tablicy(slowo[0]), DWA do drugiego elementu (slowo[1]), a 3 do zmiennej int(liczba).
ifstream czyta dane do bialych znakow, nastepnie te znaki pomija i wczytuje kolejne dane. Tak jak wszyscy wyzej pisali. Nie myl tylko ">>" z "<<". Ten drugi stosujesz do zapisu do pliku.

ChS napisał(a)

data.txt {RAZ DWA 3 [EOF]}

Po danych znajdujących się w pliku, jeżeli dalej nie ma żadnego znaku to oznacza, że jest EOF, dlatego żadnego znaku końca pliku nie dodawaj.

0

Spoko dzięki, już kumam.
A wytłumaczycie mi jak działa cin i cout?
czy one mają ten sam stos czy dwa różne?
bo jak wczytam powiedzmy 4 litery
cin >> a >> b >> c >> d;
i po każdej literze wcisne enter, czyli w buforze klawiatury jest enter?
czyli wczyta mi a i c? bo w b i d będzie enter?
i jak to dokładnie wygląda z trzymaniem na stosie.

0

jakiż znowu stos???? tam nie ma żadnego stosu.

operator >> (domyślnie, da sie to wylaczyc) pomija białe znaki wystepujące PRZED danymi do odczytania. to znaczy, ze jezeli masz:

int x,y,z;
cin >> x;
cin >> y >> z;

i wpiszesz:

12345 4444\n
6666      \n
ggggg  778777    \n

to po odczytaniu w/w kodem wartosci X Y i Z, w buforze wejscia zostanie dokladnie:

      \n
ggggg  778777    \n

dlatego wlasnie cala masa ludzi ma problem, kiedy miesza cin i getline, np:

int x;
string zdanie;
cin >> x;
getline(cin, zdanie);

przy takim czyms, jezeli ktoś wpisze:

55555\n
ala ma kota\n

to dostanie x = 55555 oraz zdanie = "", poniewaz getline nie pomija bialych znakow i odczyta jedynie "\n" bedacy zaraz po 55555.

0

to jak nie stos to musi być jakieś miejsce w pamięci (taki kontener) strumienia gdzie są dane buforowane i dlatego zapytam się dalej:
jak użyje
flush(); to dane znikną(zostaną wyrzucone z bufora)?
cout.flush() to wypisze dane na konsoli?
czy musze
cout << flush(); co jest równoznaczne? z cout << endl;
?

0

btw. tak aby bylo dokladniej:
flush na cout nie jest rownoznaczny z endl
endl to jest ("\n" + flush) albo ("\r" + flush) albo ("\r\n" + flush), zaleznie od OS'a

a odpowiadajac: tak, cout << flush spowoduje, ze wszystko co jest zgromadzone w buforze wyjscia, zostanie natychmiast z niego wypchniete. nagminne nieuzywanie endl albo nierobienie flush powoduje, ze czasem sobei bufor cos zachowikuje i cout wypluwa na out'a z pewnym opoznieniem. czasem, nie zawsze. w ten sposob zachowuja sie wszystkie strumienie wyjsciowe.

z kolei co do cin << flush to juz jest ślisko. o ile w cout generalnie wiesz co masz/mozesz miec w buforze wyjscia i wiesz co flushujesz, o tyle (IIRC) flush na strumieniach wejsciowych co prawda tez 'oproznia bufor' wejscia, czyli robi czystke/pominiecie na wejsciu, ale tak naprawde zastanow sie, co to znaczy? skad wiesz ile OS faktycznie zdazyl podac na STDIN programu? jesli siedzisz np. na linuksie, to domyslnie masz buforowanie interaktywnego stdina per linia. czyli napiszesz polowe zdania "ala ma kota" i zamyslisz sie na chwile, program zrobi w tym czasie cin flush, ale jak teraz Ty nacisniesz enter, to sie okaze ze flush niczego nie sprzatnal bo program jeszcze nic nie dostal.. jezeli z-pipe-ujesz mu stdin'a np. na plik udajacy wejscie, to cin.flush wywali tylko tyle, ile aktualnie bylo zbuforowane, a cala reszta pliku i tak przyleci.. flush na wejsciu ogolnie rzecz biorac nie ma sensu..

jezeli strumien wejsciowy spali z racji zlych znakow i bledu konwersji, tak czy owak musisz zrobic cin.reset, potem flush moze faktyczne troszke sie przydac, ale po nim defacto i tak nie wiesz "gdzie" w strumieniu wejscia jestes nastepny znak odebrany po flush moze byc dokladnie dowolny. zreszta to przydaloby sie IMHO chyba tylko w trybie interaktywnym, podczas 'konwersacji' z uzytkownikiem, po odpowiednim komunikacie bledu ktoryby 'zresetowa' uzytkownikowi mozg... wszedzie indziej zamiast flush na cin, bezpieczniej jest uzywac ignore z numericlimits<int>.max jako iloscia elementow, i z elementem szukanym takim, aby "odznalezc sie" w stumieni - np. \n czy , czy ; -- acz ignore jest tyci wolniejszy

1

Umiesz korzystać z google i MSDN?! Jeśli nie, to najwyższa pora się nauczyć, bo tu nikt nie będzie ciągle dawał Ci odpowiedzi na każde Twoje pytanie. Ciężko poszukać? Taka rada na przyszłość ;)

0

Nie ma tam żadnego stosu.
Jak już powiedziałem wcześniej (niby odpowiedziałeś że kumasz) każdy operator >> zaczyna od wywalenia białych znaków.
Czyli nie wczytasz żadnej: spacji, tabulacji czy entera.

0

Gracias Amigo!

quetzalcoatl napisał(a)

nagminne nieuzywanie endl albo nierobienie flush powoduje, ze czasem sobei bufor cos zachowikuje

To mnie też zaciekawiło:

quetzalcoatl napisał(a)

jesli siedzisz np. na linuksie, to domyslnie masz buforowanie interaktywnego stdina per linia. czyli napiszesz polowe zdania "ala ma kota" i zamyslisz sie na chwile, program zrobi w tym czasie cin flush, ale jak teraz Ty nacisniesz enter, to sie okaze ze flush niczego nie sprzatnal bo program jeszcze nic nie dostal..

Czyli ściąga bufor w czasie rzeczywistym z linii? huh

Znaczy chodzi o te flagi stanu strumienia?
// chodziło mi o cin.reset() :

quetzalcoatl napisał(a)

jezeli strumien wejsciowy spali z racji zlych znakow i bledu konwersji, tak czy owak musisz zrobic cin.reset,

Jak? Założyć pętle :
do(cin.ignore()) while ((char = cin.get()) != _znak)??
//omiń linię wyżej

quetzalcoatl napisał(a)

wszedzie indziej zamiast flush na cin, bezpieczniej jest uzywac ignore z numericlimits<int>.max

muszę o tym poczytać.

btw. google tu jest !
@mbar254 books are better.
a opinia ludzi znających się jest bardzo szanowana przez ludzi się uczących.

@_13th_Dragon
kumam. zastanawialem sie tylko nad praca wskaznika.

a jezeli zapisuje do pliku i wrzuce tam jeden string to czy wskaźnik w pliku przesunie mi się o ilosc znaków w stringu? czy będę to musiał zrobić seekp'iem?

0

Po każdym odczycie/zapisie wskaźnik przesuwa się na koniec odczytanego/zapisanego bloku.
Seek jest potrzebny tylko wtedy kiedy chcemy ponownie odczytać/zapisać lub pominąć jakiś fragment.

0
ChS napisał(a)
quetzalcoatl napisał(a)

nagminne nieuzywanie endl albo nierobienie flush powoduje, ze czasem sobei bufor cos zachowikuje

To mnie też zaciekawiło:
Czyli ściąga bufor w czasie rzeczywistym z linii? huh

nie. nic z "linii" sie nie sciaga do bufora. w tym kawałku tekstu pisałem o COUT/STDOUT i o tym, ze jezeli masz w zwyczaju pisac cout << "mama\n" zamiast cout << "mama" << endl to jezeli takich cout'ów bedziesz mial wiele, to w koncu gdzies zauwazusz, ze są one wypisywane "paczkami" a nie "natychmiast".

ChS napisał(a)
quetzalcoatl napisał(a)

jesli siedzisz np. na linuksie, to domyslnie masz buforowanie interaktywnego stdina per linia. czyli napiszesz polowe zdania "ala ma kota" i zamyslisz sie na chwile, program zrobi w tym czasie cin flush, ale jak teraz Ty nacisniesz enter, to sie okaze ze flush niczego nie sprzatnal bo program jeszcze nic nie dostal..

Znaczy chodzi o te flagi stanu strumienia? :

nie. w tym w kawałku tekstu chciałem Ci przypomnieć, że poza Twoim programem są jeszcze:

  • system operacyjny
  • i konsola
    i że one TEŻ BUFORUJĄ TWOJE DANE WEJSCIOWE. Na linuksie, zwlaszcza konsola lubi buforowac per linia i dawac Twojemu programowi dopiero dane po uskładaniu całej linijki (czyli nacisniecia entera). Jeżeli sam nie zadbasz o to różnymi sposobami, pracując w "terminalu" linuksowym/unixowym/etc, Twoj program prawie nigdy nie zobaczy "kawalka" linijki na STDIN. z tego powodu, CIN >> X >> Y >> .. będzie stało w miejscu az nacisniesz enter, i nie wazne ile razy wcisniejsz 5-spacja-5-spacja, ono i tak bedzie stalo do entera, poniewaz ono nie zobaczy nic nowego, dopoki bufor konsoli nie uzna, ze czas wypchnac dane do Twojego programu. i nie ma to nic wspolnego z flagami Twojego strumienia wyjsciowego. jezeli nie zaobserwowales takiego efektu nigdy, to moze oznaczac ze Twoja konsola/terminal nie buforuje per-linia, "masz szczescie", ale tylko złudne, poniewaz nabiera się przez to zlych przyzwyczajen i zlej wizjii "wejscia-wyjscia" i wystarczy ze przeniesiesz program na komputer/system innego typu i pewnie będzie płacz.
ChS napisał(a)
quetzalcoatl napisał(a)

jezeli strumien wejsciowy spali z racji zlych znakow i bledu konwersji, tak czy owak musisz zrobic cin.reset,

Jak? Założyć pętle :
do(cin.ignore()) while ((char = cin.get()) != _znak)??

że co?
weź przeczytaj jak dziala ignore..
jeżeli chcesz "usunąć" aktualnie czytaną "linijkę" z "wejścia", to "robi się" to tak:

(patrz np. http://4programmers.net/Forum/C_i_C++/137405-C++_wyszukiwanie_numeru_osoby_z_listy_osob_na_strukturach?p=510999#id510999)
`cin.ignore(numeric_limits<streamsize>::max(), '\n');`
a jezeli jestes leniwy w pisaniu:
`cin.ignore(INT_MAX, '\n');`
ale keidys za 15lat moze akurat ta ostatnia linijka przestac dzialac prawidlowo:)


 > ##### ChS napisał(a)
> > ##### quetzalcoatl napisał(a)
> > wszedzie indziej zamiast flush na cin, bezpieczniej jest uzywac ignore z numericlimits<int>.max
> 
> 
> btw. google tu jest !
> second books are better <<
> a opinia ludzi się znających jest bardzo szanowana przez ludzi się uczących.
????


 > ##### ChS napisał(a)
> @_13th_Dragon
> kumam. zastanawialem sie tylko nad praca wskaznika.
> 
> a jezeli zapisuje do pliku i wrzuce tam jeden string to czy wskaźnik w pliku przesunie mi się o ilosc znaków w stringu? czy będę to musiał zrobić seekp'iem?

'wskazniki' strumieni przesuwaja sie automatycznie przy kazdym odczycie i zapisie, dokladnie o tyle, ile zapisano lub odczytano. nigdy nie bedziesz musial recznie ruszac wskaznikiem-p ani wskaznikiem-g (seekp/seekg) dopoki sam nie stwierdzisz ze z jakiegos powodu musisz "nagle przeskoczyc" w strumieniu jakies dane lub "się cofnac" do jakichs danych. btw. odczyta rusza wskaznikiem-g, zapis wskaznikiem-p, nigdy na krzyz. odczyt nie zmieni wskanzika-p.


 > ##### _13th_Dragon napisał(a)
> Po każdym odczycie/zapisie wskaźnik przesuwa się na koniec odczytanego/zapisanego bloku.
> Seek jest potrzebny tylko wtedy kiedy chcemy ponownie odczytać/zapisać lub pominąć jakiś fragment.

seek jest takze potrzebny, jezeli chcemy sie przelaczyc pomiedzy zapisem a odczytem i vice versa, nawet jezeli przy przelaczaniu sie wcale nie mamy zamiaru zmieniac pozycji wskaznikow-p/g. ma to znaczenie tylko dla "pełnych" klas (f)stream, nie dla "połówek" typu i- czy o- steam, a takze ta sama regula tyczy sie ogolnie do strumieni z warstwy C. wykonac w takim przypadku trzeba 'seek-p/g' z przesunieciem 'zero' wzgledem pozycji 'current'.
0

Spoko Quetz, przeniosłem komentarze trochę bo nie tak to przeczytałeś. co do cin.ignore i flush no to mam zadanie domowe. Wskaźniki są już oklepane perfekcyjnie. tylko z tym cin.reset to mi chodzilo o to czy ta funkcja resetuje stan flag formatowania strrumieni. a wiem ze w c# są strumienie co ściągają od razu z buforu klawiatury co za klawisz naciśniesz dlatego się zapytałem czy w c++ jest taki bajer że od razu interfejs moża robić 'bez enterów' a jeżeli nie można to ratują tylko wstawki assemblera? huh rzeźnia...

0

.reset powoduje wyczyszczenie stanu flag błędów strumieni i efektywnie "budzi" lub "odblokowuje" go po bledzie. kompletnie nic ona nie zmienia w kontekscie flag/manipulatorow formatowania

do "sciagania od razu" nie potrzebujesz wstawek asemblerowych. problem tkwi w tym, ze program na warstwie abstrakcji samego jezyka C++ i iostreamow, nie ma zielonego pojecia czy dane dostaje z zewnatrz "interaktywnie" od uzytkownika, czy streamuje wejscie pliku, czy tez z socketa, czy bog wie z czego. żeby się tego dowiedziec, musisz się o to spytać systemu operacyjnego, a tego juz iostreamy nie pokrywaja. tak samo, jeżeli system operacyjny udostepnia Ci inny dostep do klawiaruty niz iostreamy, mozesz sie go bezposrednio pytac o aktualny niebuforowany stan klawiatury, w ten sposob chocby robi kbhit() i getch() chyba, że nazwy przekrecilem. zarowno na Win jak i Linux są wystawione od tego funkcje, jeszcze na "warstwie" języka C, więc w C++ mozesz tez z nich korzystac, acz korzstanie z nich rownolegle wraz z uzywaniem cin moze byc czasem karkolomne.

inna rzecz, ze na systemach *nix i tak bedziesz mial problem z faktem, ze shell/konsola beda lubily buforowac wejscie per linijka. szczesliwie, programy moga w pewnym zakresie sterowac terminalami i ich zachowaniem, patrz np. program passwd - ostatecznie wpisuje sie haslo bez echa? z tego co pamietam, buforowanie linii wejscia tez sie da nakazac terminalowi wylaczyc, calkiem albo chwilowo. cos znalazlem np. tutaj http://4programmers.net/C/FAQ/W%C5%82asna_implementacja_funkcji_getch() ale jesli chcesz robic ninjaGUI na terminalu linuksowym lepiej od razu zapoznaj sie z sekwencjami sterujacymi terminali VC100 i VC400, to taki 'podstawowy zestaw' od ruszania kursorem, kolorkow itede. oczywiscie na Windows to kompletnieniebedziedzialac, albo tez niedokonca, albo tez niepoprawnie. na win lepiej uzywac funkcji w stylu SetConsoleAttribute.

a inna rzecz, ze przy takich problemach, przy wiekszej ilosci wymaganych 'interaktywnosci' w konsoli, lepiej wziac jakaś biblioteke pokroju P/N/Curses czy jak im tam..

0

Odnawiam:
Pozostane przy Devie jednak...

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