Verwenden von getline(cin, s) nach cin [duplicate]
Lesezeit: 7 Minuten
pauliwago
Ich benötige das folgende Programm, um die gesamte Zeile der Benutzereingabe zu übernehmen und in Zeichenfolgennamen einzufügen:
cout << "Enter the number: ";
int number;
cin >> number;
cout << "Enter names: ";
string names;
getline(cin, names);
Mit dem cin >> number Befehl vor dem getline() Befehl jedoch (was meiner Meinung nach das Problem ist), erlaubt es mir nicht, Namen einzugeben. Warum?
Ich habe etwas über a gehört cin.clear() Befehl, aber ich habe keine Ahnung, wie das funktioniert oder warum das überhaupt notwendig ist.
Angenommen, Sie haben Folgendes eingegeben: 5<enter>John<enter>. Dann cin >> number liest GERADE 5. Belassen des Zeilenumbruchzeichens (Enter) im Stream. Also, wenn Sie versuchen, den Namen mit zu lesen getline(cin,name) es liest bis zum Ende der Zeile. ABER ACHTUNG dort ist ein New-Line-Zeichen, das gelesen werden kann (daher sind Namen leer (weil Sie das New-Line-Zeichen nach der 5 nicht abgelesen haben). Wenn Sie zwischen >> und getline() wechseln wollen, brauchen Sie Seien Sie vorsichtig mit dem nachgestellten Zeilenende bei Ihrer Eingabe.
– Martin York
21. April 2011 um 8:41 Uhr
@LokiAstari: Das ist besser Antworten als alle unten geposteten. Könntest du es so posten?
– Leichtigkeitsrennen im Orbit
29. Mai 2015 um 18:39 Uhr
cout << "Enter the number: ";
int number;
cin >> number;
cin.ignore(256, '\n'); // remaining input characters up to the next newline character
// are ignored
cout << "Enter names: ";
string names;
getline(cin, names);
Eine andere Möglichkeit, dies zu tun, besteht darin, a zu setzen
nach ihrem cin>>number; um den Eingabepuffer vollständig zu leeren (alle zusätzlichen Zeichen abzulehnen, bis ein Zeilenumbruch gefunden wird). Du musst #include <limits> um das zu bekommen max() Methode.
@jonsca: “Alle zusätzlichen Zeichen abzulehnen” ist in den meisten Produktionssystemen zweifelhaft … es ist gut, Leerzeichen zu essen, aber das Verwerfen unbekannter Daten kann leicht und stillschweigend zu falschen Ergebnissen führen.
– Toni Delroy
21. April 2011 um 6:03 Uhr
@cnicutar es variiert von Implementierung zu Implementierung
– Jonska
21. April 2011 um 6:08 Uhr
@Tony Wie wäre es, wenn Sie anstelle einer getline eine Schleife haben, die Zeichen nach der cin-Anweisung aufnimmt? Sicherlich werden die zusätzlichen Charaktere einen Schraubenschlüssel hineinwerfen. Reden Sie eher von Sicherheitslücken?
– Jonska
21. April 2011 um 6:10 Uhr
“Schleife, die Zeichen einnimmt” … wenn Sie meinen while (isspace(cin.peek())) cin.ignore()… Sieht gut für mich aus. Bezüglich oben dachte ich eher an einen Benutzer, der die Anforderungen an das Eingabeformat missverstanden hat, oder an ein Skript, das die Eingabeunterbrechungen generiert, aber die fehlerhafte Eingabe scheint erfolgreich verarbeitet zu werden, weil sie ignoriert wird – sie können am Ende fehlerhaften Ergebnissen vertrauen. Wenn die Eingabe nicht den Spezifikationen entspricht, ist es besser, Ihr Programm einen Fehler generieren zu lassen.
– Toni Delroy
21. April 2011 um 6:26 Uhr
@Tony Ah, okay, ich habe falsch interpretiert, was du sagen wolltest. Guter Punkt zur Validierung.
– Jonska
21. April 2011 um 6:39 Uhr
Toni Delroy
cout << "Enter the number: ";
int number;
if (cin >> number)
{
// throw away the rest of the line
char c;
while (cin.get(c) && c != '\n')
if (!std::isspace(c))
{
std::cerr << "ERROR unexpected character '" << c << "' found\n";
exit(EXIT_FAILURE);
}
cout << "Enter names: ";
string name;
// keep getting lines until EOF (or "bad" e.g. error reading redirected file)...
while (getline(cin, name))
...use name...
}
else
{
std::cerr << "ERROR reading number\n";
exit(EXIT_FAILURE);
}
Im obigen Code ist dieses Bit …
char c;
while (cin.get(c) && c != '\n')
if (!std::isspace(c))
{
std::cerr << "ERROR unexpected character '" << c << "' found\n";
exit(EXIT_FAILURE);
}
…überprüft den Rest der Eingabezeile, nachdem die Zahl nur Leerzeichen enthält.
Warum nicht einfach ignorieren?
Das ist ziemlich ausführlich, also mit ignore im Stream danach >> x ist ein oft empfohlener alternativer Weg, um Inhalte bis zum nächsten Zeilenumbruch zu verwerfen, aber es besteht die Gefahr, dass Nicht-Leerzeichen-Inhalte weggeworfen werden und dabei beschädigte Daten in der Datei übersehen werden. Es kann Ihnen egal sein, ob der Inhalt der Datei vertrauenswürdig ist, wie wichtig es ist, die Verarbeitung beschädigter Daten zu vermeiden usw.
Wann würden Sie also clear verwenden und ignorieren?
Damit, std::cin.clear() (und std::cin.ignore()) ist dafür nicht erforderlich, aber nützlich, um den Fehlerstatus zu entfernen. Zum Beispiel, wenn Sie dem Benutzer viele Chancen geben möchten, eine gültige Nummer einzugeben.
int x;
while (std::cout << "Enter a number: " &&
!(std::cin >> x))
{
if (std::cin.eof())
{
std::cerr << "ERROR unexpected EOF\n";
exit(EXIT_FAILURE);
}
std::cin.clear(); // clear bad/fail/eof flags
// have to ignore non-numeric character that caused cin >> x to
// fail or there's no chance of it working next time; for "cin" it's
// common to remove the entire suspect line and re-prompt the user for
// input.
std::cin.ignore(std::numeric_limits<std::streamsize>::max());
}
Geht es nicht einfacher mit skipws oder ähnlichem?
Eine weitere einfache, aber halbgare Alternative zu ignore für Ihre ursprüngliche Anforderung verwendet std::skipws um eine beliebige Menge an Leerzeichen zu überspringen, bevor Zeilen gelesen werden …
if (std::cin >> number >> std::skipws)
{
while (getline(std::cin, name))
...
…aber wenn es eine Eingabe wie “1E6” bekommt (z. B. ein Wissenschaftler versucht, 1.000.000 einzugeben, aber C++ unterstützt diese Notation nur für Gleitkommazahlen), wird das nicht akzeptiert, würden Sie damit enden number einstellen 1und E6 gelesen als erster Wert von name. Unabhängig davon, wenn Sie eine gültige Nummer gefolgt von einer oder mehreren Leerzeilen hätten, würden diese Zeilen stillschweigend ignoriert.
Ähm, das beantwortet weder die Frage noch behebt das Problem. -1
– Leichtigkeitsrennen im Orbit
11. September 2015 um 0:19 Uhr
@LightnessRacesinOrbit: Wie wird das Problem “nicht behoben”? Der erste Anruf bei getline verbraucht den Zeilenumbruch nach der Zahl und Schleifen, bis es eine nicht leere Zeile findet … scheint mir behoben zu sein. Die Frage des OP lautete nicht “warum?” Das Problem ist aufgetreten, hat aber kommentiert, dass er nicht sicher war, warum clear könnte notwendig sein – jemand anderes hat die 5 Jahre alte Frage vor 2 Tagen bearbeitet, um dies hinzuzufügen und den Kern wesentlich zu ändern.
– Toni Delroy
13. September 2015 um 14:01 Uhr
Jetzt haben Sie bearbeitet [someone else’s] antworte es ist besser
– Leichtigkeitsrennen im Orbit
13. September 2015 um 15:33 Uhr
@LightnessRacesinOrbit: Ich habe den Kern meines Kommentars zu Jonscas Antwort von 2011 bearbeitet – nichts Neues.
– Toni Delroy
14. September 2015 um 0:24 Uhr
Versuchen:
int number;
cin >> number;
char firstCharacterOfNames;
cin >> firstCharacterOfNames; // This will discard all leading white space.
// including new-line if there happen to be any.
cin.unget(); // Put back the first character of the name.
std::string names;
std::getline(cin, names); // Read the names;
Alternative. Wenn Sie wissen, dass Nummer und Namen immer in verschiedenen Zeilen stehen.
Angenommen, Sie haben Folgendes eingegeben:
5<enter>John<enter>
. Danncin >> number
liest GERADE 5. Belassen des Zeilenumbruchzeichens (Enter) im Stream. Also, wenn Sie versuchen, den Namen mit zu lesengetline(cin,name)
es liest bis zum Ende der Zeile. ABER ACHTUNG dort ist ein New-Line-Zeichen, das gelesen werden kann (daher sind Namen leer (weil Sie das New-Line-Zeichen nach der 5 nicht abgelesen haben). Wenn Sie zwischen >> und getline() wechseln wollen, brauchen Sie Seien Sie vorsichtig mit dem nachgestellten Zeilenende bei Ihrer Eingabe.– Martin York
21. April 2011 um 8:41 Uhr
@LokiAstari: Das ist besser Antworten als alle unten geposteten. Könntest du es so posten?
– Leichtigkeitsrennen im Orbit
29. Mai 2015 um 18:39 Uhr