Wie C++ mit der Konsole spricht
C++ erledigt Konsolen-E/A über Streams aus dem Header <iostream>. Du schreibst mit cout (Zeichenausgabe) nach außen und liest mit cin (Zeicheneingabe) vom Benutzer. Sie verwenden zwei Operatoren, die du schon als Bit-Verschiebungen gesehen hast, hier mit neuem Zweck:
<<ist der Einfüge-Operator: Er schickt Daten incouthinein.>>ist der Extraktions-Operator: Er zieht Daten auscinin eine Variable.
Ein praktischer Merksatz für die Richtung: Die Pfeile zeigen in die Richtung, in die die Daten fließen. Jetzt, da du Text in Strings halten kannst, bewegen wir diesen Text in dein Programm hinein und wieder heraus.
Ausgeben mit cout
cout schickt alles, was du einfügst, an die Standardausgabe. Du kannst mehrere << in einer Anweisung verketten und dabei Text, Zahlen und Variablen frei mischen.
Jedes << hängt an dieselbe Zeile an, bis du einen Zeilenumbruch einfügst. Dafür gibt es zwei Wege: '\n' fügt ein Zeilenumbruch-Zeichen ein, während endl einen Zeilenumbruch einfügt und den Puffer auf den Bildschirm leert. Das Leeren hat echte Kosten, also bevorzuge in einer Schleife, die Tausende Zeilen ausgibt, '\n' – der Stream leert sich bei Bedarf von selbst (und immer beim Programmende).
// In Ordnung für eine einmalige Meldung:
cout << "Done" << endl;
// In einer heißen Schleife lieber so - kein erzwungenes Leeren pro Iteration:
for (int i = 0; i < 1000000; ++i)
cout << i << '\n';
Einlesen mit cin und >>
cin >> variable liest ein durch Leerzeichen getrenntes Token und wandelt es in den Typ der Variablen um. Es überspringt führende Leerzeichen oder Zeilenumbrüche und stoppt dann beim nächsten Leerzeichen.
Weil >> beim Leerzeichen stoppt, eignet es sich hervorragend für einzelne Zahlen und einzelne Wörter, aber gar nicht für einen ganzen Satz: cin >> word bei der Eingabe hello world liest nur hello und lässt world für die nächste Leseoperation im Puffer.
Eine ganze Zeile mit getline einlesen
Um eine ganze Zeile – samt Leerzeichen – zu erfassen, nutze getline(cin, line), das alles bis zur Enter-Taste in einen std::string einliest.
Das ist das richtige Werkzeug, wann immer die Eingabe Leerzeichen enthalten kann – Namen, Adressen, Sätze. Es gibt nur eine Falle, die in dem Moment auf dich wartet, in dem du getline mit >> mischst.
Die Zeilenumbruch-Falle bei cin + getline
Das ist der mit Abstand häufigste E/A-Bug in C++. Wenn du cin >> n machst, liest die Extraktion die Zahl, lässt aber den Zeilenumbruch (die Enter-Taste, die du gedrückt hast) im Eingabepuffer liegen. Das nächste getline sieht diesen übrig gebliebenen Zeilenumbruch sofort, behandelt die Zeile als bereits abgeschlossen und gibt dir einen leeren String – ohne jemals auf Eingabe zu warten.
int age;
string city;
cin >> age; // du tippst 30 und drückst Enter; '\n' bleibt im Puffer
getline(cin, city); // liest den übrigen '\n' -> city ist "" (leer!)
Die Lösung besteht darin, diesen übrig gebliebenen Zeilenumbruch mit cin.ignore nach dem >> und vor dem getline zu verwerfen:
cin.ignore(numeric_limits<streamsize>::max(), '\n') überspringt Zeichen, bis es einen Zeilenumbruch verschluckt hat (oder das Eingabeende erreicht). Das ist die robuste Variante – das kürzere cin.ignore() verwirft nur ein einziges Zeichen, was kaputtgeht, wenn der Benutzer nach der Zahl zusätzliche Leerzeichen getippt hat. Greife aus Gewohnheit zur vollständigen Form.
Wenn die Eingabe fehlschlägt
Wenn der Benutzer Buchstaben tippt, wo du eine Zahl erwartet hast, schlägt die Extraktion fehl: cin geht in einen Fehlerzustand über und die Zielvariable bleibt unverändert (seit C++11 auf 0 gesetzt). Schlimmer noch: Sobald cin im Fehlerzustand ist, wird auch jede spätere Leseoperation stillschweigend übersprungen, sodass du in einer Endlosschleife landen kannst.
Die Erholung hat immer zwei Schritte: cin.clear() setzt die Fehler-Flags zurück, sodass der Stream wieder nutzbar ist, und cin.ignore(...) wirft die störenden Zeichen weg, die noch im Puffer feststecken. Lässt du das ignore weg, bleibt die fehlerhafte Eingabe liegen, also schlägt das nächste >> erneut fehl – die klassische Endlosschleife. cin >> n direkt in der Bedingung zu prüfen funktioniert, weil sich der Stream im Fehlerzustand in false umwandelt.
Häufige Fehler, die du vermeiden solltest
cin >> sfür einen Satz verwenden. Es stoppt beim ersten Leerzeichen. Nutzegetlinefür alles mit Leerzeichen.cin.ignorezwischen>>undgetlinevergessen. Der übrig gebliebene Zeilenumbruch gibt dir eine leere Zeile. Leere zuerst den Puffer.- Überall zu
endlgreifen. Jedes davon erzwingt ein Leeren. Nimm standardmäßig'\n'und spare direndlfür Fälle auf, in denen die Ausgabe wirklich jetzt erscheinen muss. - Ein fehlgeschlagenes
cinignorieren. Buchstaben in einer numerischen Leseoperation machencinkaputt; mach immerclear()und dannignore(), bevor du erneut liest.
Weiter: String-Streams
Konsolen-E/A und String-Verarbeitung treffen sich in String-Streams. Ein stringstream gibt dir dieselben Operatoren << und >>, aber auf einen String im Speicher statt auf die Konsole gerichtet – perfekt, um eine Zeile in Zahlen zu zerlegen, formatierten Text aufzubauen und zwischen Strings und anderen Typen umzuwandeln, ohne jemals die Tastatur zu berühren.
Häufig gestellte Fragen
Warum überspringt getline die Eingabe direkt nach der Verwendung von cin in C++?
cin >> x liest die Zahl, lässt aber den Zeilenumbruch, den du gedrückt hast, im Puffer liegen. Das nächste getline liest bis zu diesem übrig gebliebenen Zeilenumbruch und gibt sofort einen leeren String zurück. Räume ihn zuerst mit cin.ignore(numeric_limits<streamsize>::max(), '\n'); nach dem >> und vor dem getline weg.
Was ist der Unterschied zwischen endl und \n in C++?
Beide beenden die Zeile, aber endl leert zusätzlich (flush) den Ausgabepuffer auf den Bildschirm, während '\n' nur einen Zeilenumbruch einfügt. Das Leeren hat einen Preis: In einer engen Schleife bevorzuge '\n' und lass den Stream von selbst leeren. Nutze endl nur, wenn du wirklich willst, dass die Ausgabe genau jetzt erscheint.
Wie lese ich in C++ eine ganze Textzeile einschließlich Leerzeichen ein?
Nutze getline(cin, line), nicht cin >> line. Der Operator >> stoppt beim ersten Leerzeichen, schnappt sich also nur ein Wort. getline liest alles bis zur Enter-Taste in einen std::string ein, Leerzeichen inklusive.