Warum verwenden wir:
1) cin.ignore
2) cin.clear
?
Einfach:
1) Ignorieren (Extrahieren und Verwerfen) von Werten, die wir nicht im Stream haben möchten
2) Um den internen Status des Streams zu löschen. Nach Verwendung von cin.clear wird der interne Status wieder auf Goodbit zurückgesetzt, was bedeutet, dass keine "Fehler" vorliegen.
Lange Version:
Wenn etwas auf 'stream' (cin) gestellt wird, muss es von dort genommen werden. Mit "genommen" meinen wir "gebraucht", "entfernt", "extrahiert" aus dem Stream. Stream hat einen Fluss. Die Daten fließen auf cin wie Wasser im Strom. Sie können den Wasserfluss einfach nicht stoppen;)
Schau dir das Beispiel an:
string name; //line 1
cout << "Give me your name and surname:"<<endl;//line 2
cin >> name;//line 3
int age;//line 4
cout << "Give me your age:" <<endl;//line 5
cin >> age;//line 6
Was passiert, wenn der Benutzer antwortet: "Arkadiusz Wlodarczyk" für die erste Frage?
Führen Sie das Programm aus, um sich selbst davon zu überzeugen.
Sie sehen auf der Konsole "Arkadiusz", aber das Programm fragt Sie nicht nach dem Alter. Es wird sofort nach dem Drucken von "Arkadiusz" beendet.
Und "Wlodarczyk" wird nicht gezeigt. Es scheint, als wäre es weg (?) *
Was ist passiert? ;-);
Weil zwischen "Arkadiusz" und "Wlodarczyk" ein Leerzeichen ist.
Das Leerzeichen zwischen Vor- und Nachname ist ein Zeichen für den Computer, dass zwei Variablen darauf warten, im Eingabestream extrahiert zu werden.
Der Computer glaubt, dass Sie mehr als eine Variable an die Eingabe senden möchten. Dieses "Leerzeichen" ist ein Zeichen für ihn, es so zu interpretieren.
Der Computer weist also "Name" (2) "Arkadiusz" zu. Da Sie mehr als eine Zeichenfolge in den Stream (Eingabe) einfügen, versucht der Computer, der Variablen "Alter" (!) Den Wert "Wlodarczyk" zuzuweisen. Der Benutzer hat keine Chance, etwas in Zeile 6 auf das 'cin' zu setzen, da diese Anweisung bereits ausgeführt wurde (!). Warum? Weil noch etwas in Betrieb war. Und wie ich bereits sagte, befindet sich der Stream in einem Fluss, sodass alles so schnell wie möglich entfernt werden muss. Und die Möglichkeit kam, als der Computer den Unterricht sah.
Der Computer weiß nicht, dass Sie eine Variable erstellt haben, in der das Alter einer Person gespeichert ist (Zeile 4). 'Alter' ist nur ein Etikett. Für Computer könnte "Alter" auch als "afsfasgfsagasggas" bezeichnet werden, und es wäre dasselbe. Für ihn ist es nur eine Variable, der er versuchen wird, "Wlodarczyk" zuzuweisen, weil Sie den Computer in Zeile (6) dazu aufgefordert haben.
Es ist falsch, das zu tun, aber hey, du hast es getan! Es ist deine Schuld! Nun, vielleicht Benutzer, aber immer noch ...
Gut gut. Aber wie kann man das beheben?!
Versuchen wir, ein wenig mit diesem Beispiel zu spielen, bevor wir es richtig reparieren, um ein paar weitere interessante Dinge zu lernen :-)
Ich bevorzuge einen Ansatz, bei dem wir die Dinge verstehen. Etwas zu reparieren, ohne zu wissen, wie wir es gemacht haben, gibt keine Befriedigung, meinst du nicht auch? :) :)
string name;
cout << "Give me your name and surname:"<<endl;
cin >> name;
int age;
cout << "Give me your age:" <<endl;
cin >> age;
cout << cin.rdstate(); //new line is here :-)
Nach dem Aufrufen des obigen Codes werden Sie feststellen, dass der Status Ihres Streams (cin) gleich 4 ist (Zeile 7). Das heißt, sein interner Zustand ist nicht mehr gleich Goodbit. Etwas ist durcheinander. Es ist ziemlich offensichtlich, nicht wahr? Sie haben versucht, der int-Typvariablen 'age' den Wert für den Zeichenfolgentyp ("Wlodarczyk") zuzuweisen. Typen stimmen nicht überein. Es ist Zeit zu informieren, dass etwas nicht stimmt. Und der Computer ändert dazu den internen Status des Streams. Es ist wie: "Du verdammter Mann, repariere mich bitte. Ich informiere dich 'freundlich' ;-)"
Sie können 'cin' (Stream) einfach nicht mehr verwenden. Es steckt fest. Als ob Sie große Holzscheite auf den Wasserstrahl gelegt hätten. Sie müssen es reparieren, bevor Sie es verwenden können. Daten (Wasser) können nicht mehr von diesem Stream (cin) abgerufen werden, da Holzprotokoll (interner Zustand) dies nicht zulässt.
Oh, wenn es ein Hindernis gibt (Holzstämme), können wir es einfach mit dafür vorgesehenen Werkzeugen entfernen?
Ja!
Der interne Zustand von cin auf 4 ist wie ein Alarm, der heult und Geräusche macht.
cin.clear löscht den Zustand wieder auf Normal (Goodbit). Es ist, als wären Sie gekommen und hätten den Alarm zum Schweigen gebracht. Du hast es einfach aufgeschoben. Sie wissen, dass etwas passiert ist, also sagen Sie: "Es ist in Ordnung, keinen Lärm mehr zu machen. Ich weiß, dass bereits etwas nicht stimmt. Halt die Klappe (klar)."
Also gut, lass es uns tun! Verwenden wir cin.clear ().
Rufen Sie den folgenden Code mit "Arkadiusz Wlodarczyk" als erste Eingabe auf:
string name;
cout << "Give me your name and surname:"<<endl;
cin >> name;
int age;
cout << "Give me your age:" <<endl;
cin >> age;
cout << cin.rdstate() << endl;
cin.clear(); //new line is here :-)
cout << cin.rdstate()<< endl; //new line is here :-)
Wir können sicher nach der Ausführung des obigen Codes sehen, dass der Zustand gleich Goodbit ist.
Großartig, damit das Problem gelöst ist?
Rufen Sie den folgenden Code mit "Arkadiusz Wlodarczyk" als erste Eingabe auf:
string name;
cout << "Give me your name and surname:"<<endl;
cin >> name;
int age;
cout << "Give me your age:" <<endl;
cin >> age;
cout << cin.rdstate() << endl;;
cin.clear();
cout << cin.rdstate() << endl;
cin >> age;//new line is here :-)
Auch wenn der Status nach Zeile 9 auf Goodbit gesetzt ist, wird der Benutzer nicht nach "Alter" gefragt. Das Programm stoppt.
WARUM?!
Oh Mann ... Sie haben gerade Alarm geschlagen, was ist mit dem Holzklotz in einem Wasser? * Gehen Sie zurück zu dem Text, in dem wir über "Wlodarczyk" gesprochen haben, wie es angeblich weg war.
Sie müssen "Wlodarczyk" dieses Stück Holz aus dem Strom entfernen. Das Ausschalten von Alarmen löst das Problem überhaupt nicht. Sie haben es gerade zum Schweigen gebracht und denken, das Problem ist weg? ;)
Es ist also Zeit für ein anderes Tool:
cin.ignore kann mit einem speziellen LKW mit Seilen verglichen werden, der kommt und die Holzstämme entfernt, durch die der Strom stecken geblieben ist. Es behebt das Problem, das der Benutzer Ihres Programms erstellt hat.
Könnten wir es also noch verwenden, bevor der Alarm ausgelöst wird?
Ja:
string name;
cout << "Give me your name and surname:"<< endl;
cin >> name;
cin.ignore(10000, '\n'); //time to remove "Wlodarczyk" the wood log and make the stream flow
int age;
cout << "Give me your age:" << endl;
cin >> age;
Der "Wlodarczyk" wird entfernt, bevor das Geräusch in Zeile 7 gemacht wird.
Was ist 10000 und '\ n'?
Es heißt, 10000 Zeichen entfernen (nur für den Fall), bis '\ n' erfüllt ist (ENTER). Übrigens kann es mit numeric_limits besser gemacht werden, aber es ist nicht das Thema dieser Antwort.
Die Hauptursache des Problems ist also verschwunden, bevor Lärm gemacht wurde ...
Warum brauchen wir dann "klar"?
Was wäre, wenn jemand in Zeile 6 nach der Frage "Gib mir dein Alter" gefragt hätte, zum Beispiel: "20 Jahre alt", anstatt 20 zu schreiben?
Typen stimmen nicht mehr überein. Der Computer versucht, int eine Zeichenfolge zuzuweisen. Und der Alarm beginnt. Sie haben nicht einmal die Chance, auf eine solche Situation zu reagieren. cin.ignore hilft Ihnen in diesem Fall nicht weiter.
Also müssen wir in solchen Fällen klar verwenden:
string name;
cout << "Give me your name and surname:"<< endl;
cin >> name;
cin.ignore(10000, '\n'); //time to remove "Wlodarczyk" the wood log and make the stream flow
int age;
cout << "Give me your age:" << endl;
cin >> age;
cin.clear();
cin.ignore(10000, '\n'); //time to remove "Wlodarczyk" the wood log and make the stream flow
Aber sollten Sie den Staat "nur für den Fall" löschen?
Natürlich nicht.
Wenn etwas schief geht (cin >> age;), werden Sie durch eine falsche Anweisung darüber informiert.
Wir können also eine bedingte Anweisung verwenden, um zu überprüfen, ob der Benutzer einen falschen Typ in den Stream eingegeben hat
int age;
if (cin >> age) //it's gonna return false if types doesn't match
cout << "You put integer";
else
cout << "You bad boy! it was supposed to be int";
Also gut, damit wir unser anfängliches Problem beheben können, wie zum Beispiel:
string name;
cout << "Give me your name and surname:"<< endl;
cin >> name;
cin.ignore(10000, '\n'); //time to remove "Wlodarczyk" the wood log and make the stream flow
int age;
cout << "Give me your age:" << endl;
if (cin >> age)
cout << "Your age is equal to:" << endl;
else
{
cin.clear();
cin.ignore(10000, '\n'); //time to remove "Wlodarczyk" the wood log and make the stream flow
cout << "Give me your age name as string I dare you";
cin >> age;
}
Dies kann natürlich verbessert werden, indem Sie beispielsweise das, was Sie in Frage gestellt haben, mit loop während ausführen.
BONUS:
Sie fragen sich vielleicht. Was ist, wenn ich vom Benutzer Vor- und Nachnamen in derselben Zeile erhalten möchte? Ist es überhaupt möglich, cin zu verwenden, wenn cin jeden durch "Leerzeichen" getrennten Wert als unterschiedliche Variable interpretiert?
Sicher, Sie können es auf zwei Arten tun:
1)
string name, surname;
cout << "Give me your name and surname:"<< endl;
cin >> name;
cin >> surname;
cout << "Hello, " << name << " " << surname << endl;
2) oder mit der Funktion getline.
getline(cin, nameOfStringVariable);
und so geht's:
string nameAndSurname;
cout << "Give me your name and surname:"<< endl;
getline(cin, nameAndSurname);
cout << "Hello, " << nameAndSurname << endl;
Die zweite Option kann nach hinten losgehen, falls Sie sie verwenden, nachdem Sie 'cin' vor der getline verwendet haben.
Schauen wir uns das an:
ein)
int age;
cout << "Give me your age:" <<endl;
cin >> age;
cout << "Your age is" << age << endl;
string nameAndSurname;
cout << "Give me your name and surname:"<< endl;
getline(cin, nameAndSurname);
cout << "Hello, " << nameAndSurname << endl;
Wenn Sie "20" als Alter angeben, werden Sie nicht nach nameAndSurname gefragt.
Aber wenn Sie es so machen:
b)
string nameAndSurname;
cout << "Give me your name and surname:"<< endl;
getline(cin, nameAndSurname);
cout << "Hello, " << nameAndSurname << endl;
int age;
cout << "Give me your age:" <<endl;
cin >> age;
cout << "Your age is" << age << endll
alles ist gut.
WAS?!
Jedes Mal, wenn Sie etwas in die Eingabe (Stream) einfügen, verlassen Sie am Ende das weiße Zeichen ENTER ('\ n'). Sie müssen irgendwie Werte für die Konsole eingeben. Es muss also passieren, wenn die Daten vom Benutzer stammen.
b) cin-Merkmale sind, dass Leerzeichen ignoriert werden. Wenn Sie also Informationen aus cin einlesen, spielt das Zeilenumbruchzeichen '\ n' keine Rolle. Es wird ignoriert.
a) Die Funktion getline bringt die gesamte Zeile bis zum Zeilenumbruchzeichen ('\ n'), und wenn das Zeilenumbruchzeichen das erste ist, erhält die Funktion getline '\ n', und das ist alles, was zu bekommen ist. Sie extrahieren ein Zeilenumbruchzeichen, das vom Benutzer im Stream belassen wurde, der in Zeile 3 "20" in den Stream eingefügt hat.
Um dies zu beheben, müssen Sie immer cin.ignore () aufrufen. Jedes Mal, wenn Sie cin verwenden, um einen Wert zu erhalten, wenn Sie getline () jemals in Ihrem Programm verwenden möchten.
Der richtige Code wäre also:
int age;
cout << "Give me your age:" <<endl;
cin >> age;
cin.ignore(); // it ignores just enter without arguments being sent. it's same as cin.ignore(1, '\n')
cout << "Your age is" << age << endl;
string nameAndSurname;
cout << "Give me your name and surname:"<< endl;
getline(cin, nameAndSurname);
cout << "Hello, " << nameAndSurname << endl;
Ich hoffe, Streams sind dir klarer.
Hah, bring mich bitte zum Schweigen! :-)
cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
.