Das C ++ - Tutorial der Google Code University enthielt diesen Code:
// Description: Illustrate the use of cin to get input
// and how to recover from errors.
#include <iostream>
using namespace std;
int main()
{
int input_var = 0;
// Enter the do while loop and stay there until either
// a non-numeric is entered, or -1 is entered. Note that
// cin will accept any integer, 4, 40, 400, etc.
do {
cout << "Enter a number (-1 = quit): ";
// The following line accepts input from the keyboard into
// variable input_var.
// cin returns false if an input operation fails, that is, if
// something other than an int (the type of input_var) is entered.
if (!(cin >> input_var)) {
cout << "Please enter numbers only." << endl;
cin.clear();
cin.ignore(10000,'\n');
}
if (input_var != -1) {
cout << "You entered " << input_var << endl;
}
}
while (input_var != -1);
cout << "All done." << endl;
return 0;
}
Welche Bedeutung hat cin.clear()
und cin.ignore()
? Warum sind die 10000
und \n
Parameter notwendig?
cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
.std::numeric_limits
, stellen Sie sicher, dass#include <limits>
.std::numeric_limits<std::streamsize>::max()
?Sie geben die
Anweisung, wenn beim Übernehmen der Eingabe von cin ein Fehler auftritt. Wenn ein Fehler auftritt, wird ein Fehlerflag gesetzt und zukünftige Versuche, Eingaben zu erhalten, schlagen fehl. Deshalb brauchst du
um das Fehlerflag loszuwerden. Außerdem befindet sich die fehlgeschlagene Eingabe in einer Art Puffer. Wenn Sie versuchen, erneut eine Eingabe zu erhalten, liest es dieselbe Eingabe im Puffer und schlägt erneut fehl. Deshalb brauchst du
Es nimmt 10000 Zeichen aus dem Puffer heraus, stoppt jedoch, wenn es auf eine neue Zeile (\ n) stößt. Der 10000 ist nur ein allgemeiner großer Wert.
quelle
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:
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? :) :)
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:
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:
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:
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:
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
Also gut, damit wir unser anfängliches Problem beheben können, wie zum Beispiel:
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)
2) oder mit der Funktion getline.
und so geht's:
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)
Wenn Sie "20" als Alter angeben, werden Sie nicht nach nameAndSurname gefragt.
Aber wenn Sie es so machen:
b)
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:
Ich hoffe, Streams sind dir klarer.
Hah, bring mich bitte zum Schweigen! :-)
quelle
Verwenden Sie
cin.ignore(1000,'\n')
diese Option, um alle Zeichen des vorherigen Zeichenscin.get()
im Puffer zu löschen, und es wird angehalten, wenn es '\ n' oder das1000 chars
erste Mal erfüllt .quelle