Jak zignorować niechcianą odpowiedź za pomocą cin.ignore()? 13885 4

O temacie

Autor Draquer

Zaczęty 7.04.2019 roku

Wyświetleń 13885

Odpowiedzi 4

Draquer

Draquer

Użytkownicy
Problematyk :F
posty360
Propsy23
ProfesjaNierób
  • Użytkownicy
  • Problematyk :F
Zabrałem się za zadanie z końca tego tematu:
http://cpp0x.pl/kursy/Kurs-C++/Poziom-1/Obsluga-strumienia-wejsciowego/12

Potrzebuję żeby ktoś wytłumaczył mi dokładnie jak działa komenda "cin.ignore()", ponieważ nie rozumiem tego jak zostało to wytłumaczone w linku powyżej.
Dokładnie chodzi mi o to, aby program nie kończył się np. kiedy przy podawaniu 1 liczby rzeczywistej, gdy użytkownik poda słowo, tylko żeby zostało to pominięte i była możliwość wpisania 2 i 3 liczby.

Kod który do tej pory napisałem:
Spoiler
#include<iostream>
#include<cstdio>
#include<limits>

using namespace std;

int main()
{
    float a;
    float b;
    float c;

    cout << "Wprowadz pierwsza liczbe rzeczywista: ";
    cin >> a;
    cout << "Blad? " << cin.fail() << endl;
    bool Blad = cin.fail();
    cin.ignore( 1000, '\n');
    cin.clear();

    cout << "Wprowadz druga liczbe rzeczywista: ";
    cin >> b;
    cout << "Blad? " << cin.fail() << endl;
    bool Blad2 = cin.fail();
    cin.clear();

    cout << "Wprowadz trzecia liczbe rzeczywista: ";
    cin >> c;
    cout << "Blad? " << cin.fail() << endl;
    bool Blad3 = cin.fail();
    cin.clear();

    cout << "Liczba pierwsza to: " << a <<endl;
    cout << "Liczba druga to : " << b <<endl;
    cout << "Liczba trzecia to: " << c <<endl;
    return 0;
}

Przykładowo napisałem komendę "cin.ignore()" tak jak ja to rozumiem, change my mind xD
Poza tematem mam jeszcze jedno pytanie: czy linijka "return 0;" jest potrzebna? Kiedyś jej nie napisałem i kompilator nie zareagował.
 
Spoiler
#include<iostream>
using namespace std;

int main()
{
      cout << "Hello theModders" <<endl;
      return 0;
}

Cruc

Cruc

Użytkownicy
posty666
Propsy232
Profesjabrak
  • Użytkownicy
Kiepski ze mnie specjalista, ale nikt się nie kwapi, żeby odpowiedzieć :F
Ale trudno, postaram się wyjaśnić jak tylko potrafię, choć nie do końca wiem w czym problem xd

1. Ogólnie

C++ w wejściu i wyjściu posługuje się strumieniami, czyli pewnymi (pewnymi, bo ich długość nie jest określona) ciągami bajtów (wydaje się to dość logiczne, spójrz na nazwę pierwszej biblioteki, którą dodałeś - input output stream).

cin.ignore służy do tego na co wskazuje jej nazwa - do odrzucania kolejnych znaków w strumieniu. Jeśli np. zechcesz sobie pobrać dane:

int number;
string myStr;

cin >> number;
getline(cin,myStr);

cout << number << " + " << myStr << endl;

i wpiszesz sobie 123 > enter > cokolwiek > enter, wówczas otrzymasz wynik

123 +

Stanie się tak dlatego, że naciskając enter do strumienia dostaje się znak nowej linii - \n. W strumieniu znajduje się więc 123\n. 123 zostanie sparsowane na liczbę i przypisane zmiennej number, natomiast znak nowej linii zostanie w tym strumieniu. Getline natomiast działa tak, że wczytuje ze strumienia wszystko, aż do napotkania znaku nowej linii. Skoro więc napotka go na samym początku, zatem sparsuje wielkie nic i przypisze to do myStr.

To był jedynie przykład, ale głównie z jego powodu należy strumień wejściowy oczyścić przed wczytywaniem kolejnych danych. Celem jest uniknięcie niezamierzonego parsowania tego co z jakiegoś powodu znalazło się w strumieniu, albo zwyczajne usunięcie wadliwych danych.

2. cin.ignore

Załóżmy strumień 234324_2354_123 Powiedzmy, że znaki podłogi dostają się tam z pewnej specyfikacji programu, jednakże przy odczycie nam przeszkadzają. Należy więc po każdym sparsowaniu cyfr na liczbę oczyścić z nich bufor. Gdy odczytamy pierwszą liczbę pozostanie nam _2354_123. Wówczas korzystając z cin.ignore(1000,'_') strumień zostanie oczyszczony i będzie wyglądał tak 2354_123, ponieważ będzie on odrzucał kolejne znaki pod dwoma warunkami. Dopóki nie odrzuci 1000 znaków, albo nie znajdzie znaku podłogi. Dalej działamy analogicznie.

3. Podsumowanko

Musisz więc zwyczajnie czyścić bufor przy każdym kolejnym odczycie danych. Czyli już po tym kiedy pobierzesz informację o tym czy wystąpił jakiś błąd czy nie.
Btw. chyba dobrze zrozumiałeś na czym polega wykorzystanie cin.ignore, jednakże użyłeś go tylko raz, a więc tylko przy pierwszym pobraniu danych bufor zostanie oczyszczony z śmieci. Co więc kiedy coś nieodpowiedniego dostanie się przy drugim wprowadzeniu? :P

4. return

Jest potrzebny i nie. Zależy od języka, w którym piszesz. Np. w takim C++ funkcja obędzie się bez returna, nawet jeśli jej typ sugeruje, że powinna go mieć. Warto jednak wiedzieć do czego on jest. Dosłownie zwraca pewną wartość. Ponieważ jednak funkcje to wyższy szczebel w programowaniu, a nie chcę Ci niczego mieszać, skoro i tak zdążysz do tego dojść, to powiem Ci tylko tyle, że return 0 w tym przypadku informuje programistę, że program wykonał się bez błędu (jakiś runtime'ów czy innego badziewia).

Ale się rozpisałem xd
Jeśli jednak nie zrozumiałeś mojego bełkotu to zajrzyj tutaj odnośnie cin.ignore:
 
while (!success) try{...}

Najlepszy modder od gothic multiplayer - polecam pytać go o wszystko!

Draquer

Draquer

Użytkownicy
Problematyk :F
posty360
Propsy23
ProfesjaNierób
  • Użytkownicy
  • Problematyk :F
Dzięki za odpowiedź :D
Trochę mnię naprowadziłeś, jednak czegoś dalej nie rozumiem.
Dodałem już cin.ignore wszędzie tam, gdzie powinno być. Skoro dobrze użyłem cin.ignore(), to dlaczego program nie działa tak jak powinien? Dla wyjaśnienia:

Podaję wyraz "a" jako liczbę, np. 5,
Wszystko gra, w cmd wygląda to tak jak powinno, czyli: Wprowadz pierwsza liczbe rzeczywista : 5 Blad? 0

Ale kiedy podam wyraz "a" jako coś co nie jest liczbą np. pies, to w cmd wygląda to tak:
Spoiler
Wprowadz pierwsza liczbe rzeczywista: pies
Blad? 1
Wprowadz druga liczbe rzeczywista: Blad? 1
Wprowadz trzecia liczbe rzeczywista: Blad? 1
Liczba pierwsza to: 0
Liczba druga to : 0
Liczba trzecia to: 0

Process returned 0 (0x0)   execution time : 2.578 s
Press any key to continue.

Nie mam możliwości wprowadzenia kolejno wyrazów b i c.
 
Spoiler
#include<iostream>
using namespace std;

int main()
{
      cout << "Hello theModders" <<endl;
      return 0;
}

Cruc

Cruc

Użytkownicy
posty666
Propsy232
Profesjabrak
  • Użytkownicy
cin.clear powinno być przed cin.ignore.

Zapomniałem o tym, że gdy natrafiamy na błąd, strumień jest zablokowany, zatem cin.ignore nic nie da i przed tym trzeba usunąć flagę błędu przy użyciu cin.clear.

Sorry za tak późny odzew :F

Przerobiłem na szybko Twój program. Żadnych wielkich zmian tam nie robiłem, ale powinno działać - przynajmniej u mnie działa :F
Spoiler
#include<iostream>
#include<cstdio>
#include<limits>

using namespace std;

int main()
{
float a;
float b;
float c;

cout << "Wprowadz pierwsza liczbe rzeczywista: ";
cin >> a;
bool Blad = cin.fail();
cout << "Blad? " << Blad << endl;

cin.clear();
cin.ignore(1000, '\n');

cout << "Wprowadz druga liczbe rzeczywista: ";
cin >> b;
bool Blad2 = cin.fail();
cout << "Blad? " << Blad2 << endl;

cin.clear();
cin.ignore(1000, '\n');

cout << "Wprowadz trzecia liczbe rzeczywista: ";
cin >> c;
bool Blad3 = cin.fail();
cout << "Blad? " << Blad3 << endl;

cout << "Liczba pierwsza to: " << a << endl;
cout << "Liczba druga to : " << b << endl;
cout << "Liczba trzecia to: " << c << endl;
return 0;
}
 
while (!success) try{...}

Najlepszy modder od gothic multiplayer - polecam pytać go o wszystko!

Draquer

Draquer

Użytkownicy
Problematyk :F
posty360
Propsy23
ProfesjaNierób
  • Użytkownicy
  • Problematyk :F
Teraz już rozumiem na czym polega cin.ignore(), dziękuję za pomoc :)
Temat do zamknięcia.
 
Spoiler
#include<iostream>
using namespace std;

int main()
{
      cout << "Hello theModders" <<endl;
      return 0;
}


0 użytkowników i 1 Gość przegląda ten wątek.
0 użytkowników
Do góry