Ich habe ein sehr einfaches Programm in C ++ geschrieben, das den Benutzer aufforderte, eine Zahl und dann eine Zeichenfolge einzugeben. Zu meiner Überraschung hörte es beim Ausführen des Programms nie auf, nach der Zeichenfolge zu fragen. Es wurde einfach übersprungen. Nachdem ich etwas über StackOverflow gelesen hatte, stellte ich fest, dass ich eine Zeile hinzufügen musste, in der stand:
cin.ignore(256, '\n');
vor der Zeile, die die Zeichenfolgeneingabe erhält. Das Hinzufügen behebt das Problem und lässt das Programm funktionieren. Meine Frage ist, warum C ++ diese cin.ignore()
Zeile benötigt und wie ich vorhersagen kann, wann ich sie verwenden muss cin.ignore()
.
Hier ist das Programm, das ich geschrieben habe:
#include <iostream>
#include <string>
using namespace std;
int main()
{
double num;
string mystr;
cout << "Please enter a number: " << "\n";
cin >> num;
cout << "Your number is: " << num << "\n";
cin.ignore(256, '\n'); // Why do I need this line?
cout << "Please enter your name: \n";
getline (cin, mystr);
cout << "So your name is " << mystr << "?\n";
cout << "Have a nice day. \n";
}
Antworten:
Ignorieren ist genau das, was der Name impliziert.
Es "wirft" nicht etwas weg, das Sie nicht benötigen, sondern ignoriert die Anzahl der Zeichen, die Sie beim Aufrufen angeben, bis zu dem Zeichen, das Sie als Haltepunkt angeben.
Es funktioniert sowohl mit Eingabe- als auch mit Ausgabepuffern.
Im Wesentlichen
std::cin
ignorieren Sie Anweisungen, die Sie ignorieren, bevor Sie einengetline
Aufruf ausführen, denn wenn ein Benutzer etwas mit eingibtstd::cin
, drückt er die Eingabetaste und ein'\n'
Zeichen gelangt in dencin
Puffer. Wenn Sie dann verwendengetline
, wird anstelle der gewünschten Zeichenfolge das Zeilenumbruchzeichen angezeigt. Sie tun also astd::cin.ignore(1000,'\n')
und das sollte den Puffer bis zu der gewünschten Zeichenfolge löschen. (Die 1000 wird dort abgelegt, um eine bestimmte Anzahl von Zeichen vor dem angegebenen Haltepunkt zu überspringen, in diesem Fall das Zeichen \ n Zeilenumbruch.)quelle
numeric_limits<streamsize>::max()
, um alle Zeichen zu ignorieren, nicht 1000.Du denkst falsch darüber nach. Sie denken jedes Mal in logischen Schritten
cin
odergetline
werden verwendet. Ex. Fragen Sie zuerst nach einer Nummer und dann nach einem Namen. Das ist der falsche Weg, um darüber nachzudenkencin
. Sie geraten also in eine Rennbedingung, weil Sie davon ausgehen, dass der Stream jedes Mal klar ist, wenn Sie nach einer Eingabe fragen.Wenn Sie Ihr Programm nur zur Eingabe schreiben, finden Sie das Problem:
void main(void) { double num; string mystr; cin >> num; getline(cin, mystr); cout << "num=" << num << ",mystr=\'" << mystr << "\'" << endl; }
Oben denken Sie: "Holen Sie sich zuerst eine Nummer." Geben Sie also die
123
Eingabetaste ein und Ihre Ausgabe wird angezeigtnum=123,mystr=''
. Warum ist das so? Dies liegt daran, dass in dem Stream, den Sie haben,123\n
der123
in dienum
Variable analysiert wird, während er\n
sich noch im Stream befindet. Wenn Sie das Dokumentgetline
standardmäßig auf Funktion lesen, wird esistream
bis a angezeigt\n
wird. In diesem Beispiel seit\n
sieht es so aus, als ob es im Stream "übersprungen" wurde, aber es hat ordnungsgemäß funktioniert.Damit das oben genannte funktioniert, müssen Sie eingeben,
123Hello World
welches ordnungsgemäß ausgegeben wirdnum=123,mystr='Hello World'
. Das, oder Sie setzen einecin.ignore
zwischen diecin
undgetline
damit es in logische Schritte zerfällt, die Sie erwarten.Deshalb brauchen Sie die
ignore
Befehl. Weil Sie in logischen Schritten und nicht in Stream-Form darüber nachdenken, geraten Sie in eine Rennbedingung.Nehmen Sie ein anderes Codebeispiel, das in Schulen häufig vorkommt:
void main(void) { int age; string firstName; string lastName; cout << "First name: "; cin >> firstName; cout << "Last name: "; cin >> lastName; cout << "Age: "; cin >> age; cout << "Hello " << firstName << " " << lastName << "! You are " << age << " years old!" << endl; }
Das Obige scheint in logischen Schritten zu sein. Fragen Sie zuerst nach Vorname, Nachname und dann nach Alter. Wenn Sie also
John
eingetreten sind, dannDoe
eingeben, dann19
eingeben, arbeitet die Anwendung jeden logischen Schritt. Wenn Sie in "Streams" daran denken, können Sie einfachJohn Doe 19
die Frage "Vorname:" eingeben , und es würde auch funktionieren und die verbleibenden Fragen überspringen. Damit die oben genannten Schritte in logischen Schritten ausgeführt werden können, müssen Sieignore
für jede logische Unterbrechung der Fragen den verbleibenden Stream verwenden.Denken Sie daran, Ihre Programmeingabe beim Lesen aus einem "Stream" und nicht in logischen Schritten zu betrachten. Jedes Mal, wenn Sie es aufrufen
cin
, wird es aus einem Stream gelesen. Dies erzeugt eine ziemlich fehlerhafte Anwendung, wenn der Benutzer die falsche Eingabe eingibt. Wenn Sie beispielsweise ein Zeichen eingegeben haben, bei dem acin >> double
erwartet wird, erzeugt die Anwendung eine scheinbar bizarre Ausgabe.quelle
Kurze Antwort
Warum? Weil im Eingabestream noch Leerzeichen (Zeilenumbrüche, Tabulatoren, Leerzeichen, Zeilenumbrüche) vorhanden sind.
Wann? Wenn Sie eine Funktion verwenden, die nicht alleine die führenden Leerzeichen ignoriert. Cin ignoriert und entfernt standardmäßig das führende Leerzeichen, aber getline ignoriert das führende Leerzeichen nicht alleine.
Nun eine ausführliche Antwort.
Alles, was Sie in die Konsole eingeben, wird aus dem Standard-Stream stdin gelesen. Wenn Sie etwas eingeben, sagen wir 256 in Ihrem Fall und drücken Sie die Eingabetaste, wird der Inhalt des Streams
256\n
. Jetzt nimmt cin 256 auf und entfernt sie aus dem Stream und\n
bleibt immer noch im Stream. Wenn Sie nun Ihren Namen eingeben, sagen wirRaddicus
, der neue Inhalt des Streams ist\nRaddicus
.Jetzt kommt hier der Haken. Wenn Sie versuchen, eine Zeile mit getline zu lesen, liest getline standardmäßig bis zum Zeilenumbruchzeichen und entfernt das Zeilenumbruchzeichen aus dem Stream, wenn kein Trennzeichen als drittes Argument angegeben ist. Beim Aufrufen einer neuen Leitung liest und verwirft getline
\n
aus dem Stream. dass eine leere Zeichenfolge in mystr gelesen wird, die so aussieht, als würde getline übersprungen (aber nicht), da bereits eine neue Zeile im Stream vorhanden war. Getline fordert Sie nicht zur Eingabe als auf es hat bereits gelesen, was es lesen sollte.Wie hilft cin.ignore hier?
Laut der Ignorierdokumentation Auszug aus cplusplus.com -
Damit,
cin.ignore(256, '\n');
ignoriert ersten 256 Zeichen oder alle Zeichen bis es trifft delimeter (hier \ n in Ihrem Fall), je nachdem , was zuerst eintritt (hier \ n ist das erste Zeichen, so dass es ignoriert , bis \ n angetroffen wird).Nur als Referenz: Wenn Sie nicht genau wissen, wie viele Zeichen übersprungen werden sollen, und Ihr einziger Zweck darin besteht, den Stream zu löschen, um das Lesen einer Zeichenfolge mit getline oder cin vorzubereiten, sollten Sie diese verwenden
cin.ignore(numeric_limits<streamsize>::max(),'\n')
.Kurze Erklärung: Es werden die Zeichen ignoriert, die der maximalen Größe des Streams entsprechen oder bis ein '\ n' auftritt, je nachdem, welcher Fall zuerst eintritt.
quelle
Wenn Sie eine bestimmte Anzahl von Zeichen manuell aus dem Eingabestream entfernen möchten.
Ein sehr häufiger Anwendungsfall ist die Verwendung dieser Option, um Zeilenumbrüche sicher zu ignorieren, da cin manchmal Zeilenumbrüche hinterlässt, die Sie durchgehen müssen, um zur nächsten Eingabezeile zu gelangen.
Kurz gesagt, es gibt Ihnen Flexibilität bei der Verarbeitung von Stream-Eingaben.
quelle
'\n'
in IOStreams als Leerzeichen analysiert wird und IOStreams denstd::ws
Manipulator bereitstellen, der führende Leerzeichen verwirft. Sie müssenstd::getline(std::cin >> ws, mystr)
lediglich alle Leerzeichen und Zeilenumbrüche ignorieren.operator>>
undgetline
auf dem gleichen Stream. Zum Beispiel mitcin
nur verwendengetline
. Wenn Sie Daten ohne Zeichenfolge benötigen, analysieren Sie die Zeichenfolge, die Siegetline
mitistringstream
oderstoi/stod/etc...
Die Ignorierfunktion wird verwendet, um Zeichen im Eingabestream zu überspringen (zu verwerfen / wegzuwerfen). Datei ignorieren ist der Datei istream zugeordnet. Betrachten Sie die folgende Funktion, z. B.: Cin.ignore (120, '/ n'); Die jeweilige Funktion überspringt die nächsten 120 Eingabezeichen oder überspringt die Zeichen, bis ein Zeilenumbruchzeichen gelesen wird.
quelle
Wie von vielen anderen Benutzern richtig angegeben. Dies liegt daran, dass möglicherweise Leerzeichen oder Zeilenumbrüche vorhanden sind.
Betrachten Sie den folgenden Code, der alle doppelten Zeichen aus einer bestimmten Zeichenfolge entfernt.
#include <bits/stdc++.h> using namespace std; int main() { int t; cin>>t; cin.ignore(); //Notice that this cin.ignore() is really crucial for any extra whitespace or newline character while(t--){ vector<int> v(256,0); string s; getline(cin,s); string s2; for(int i=0;i<s.size();i++){ if (v[s[i]]) continue; else{ s2.push_back(s[i]); v[s[i]]++; } } cout<<s2<<endl; } return 0; }
Sie erhalten also den Punkt, dass diese unerwünschten Eingaben ignoriert werden und die Arbeit erledigt wird.
quelle
Es ist besser, scanf ("% [^ \ n]", str) in c ++ als cin.ignore () nach der Anweisung cin >> zu verwenden. Dazu müssen Sie zuerst den Header <cstdio> einfügen.
quelle
scanf
ist ein Teil des<cstdio>
Headers und nicht die idiomatische C ++ - Methode, um Eingaben vom Benutzer zu erhalten.