Eine ganze Zeile einlesen
cin >> text liest ein einzelnes Wort: Es stoppt beim ersten Leerzeichen. Um alles einzulesen, was der Benutzer bis zur Enter-Taste getippt hat, Leerzeichen inklusive, nimm std::getline aus dem Header <string>:
#include <iostream>
#include <string>
int main() {
std::string name;
std::cout << "Full name: ";
std::getline(std::cin, name);
std::cout << "Hello, " << name << "!\n";
}
Die Eingabe Ada Lovelace gibt Hello, Ada Lovelace! aus. Mit std::cin >> name käme Hello, Ada! heraus, und Lovelace würde in der Eingabe warten.
Die Signatur lautet:
std::istream& std::getline(std::istream& input, std::string& text);
std::istream& std::getline(std::istream& input, std::string& text, char delim);
inputist ein beliebiger Eingabestream:std::cin, eine mitstd::ifstreamgeöffnete Datei oder ein aus einem String gebauterstd::istringstream.textwird durch die gelesenen Zeichen ersetzt (nicht ergänzt).delimist das Zeichen, das das Lesen beendet. Standardmäßig ist es'\n'. Das Trennzeichen wird aus dem Stream entfernt und nicht intextgespeichert.- Der Rückgabewert ist der Stream selbst. Deshalb kannst du ihn in einer Bedingung prüfen.
Weil getline bei jedem Eingabestream gleich funktioniert, lesen die ausführbaren Beispiele auf dieser Seite aus einem std::istringstream mit festem Text. So ist die Ausgabe vorhersehbar, ohne dass du etwas tippen musst. Um stattdessen von der Tastatur zu lesen, ersetz die Stream-Variable durch std::cin.
Ausgabe:
[Ada Lovelace]
[Alan Turing]
Die eckigen Klammern zeigen, dass der Zeilenumbruch zu keinem der beiden Strings gehört.
getline nach cin >> liefert einen leeren String
Das ist das häufigste Problem mit getline. Du liest eine Zahl mit >>, danach eine Zeile mit getline, und das getline scheint übersprungen zu werden:
Ausgabe:
age: 30
city: []
input >> age liest die Zeichen 30 und stoppt beim ersten Zeichen, das nicht zu einer Zahl gehören kann, dem Zeilenumbruch. Dieser Zeilenumbruch bleibt im Stream. getline liest dann bis zum nächsten Zeilenumbruch, findet sofort einen und liefert einen leeren String. Mit std::cin wartet das Programm deshalb nie auf die zweite Antwort.
Es gibt zwei übliche Lösungen. Beide gehören zwischen das >> und das getline.
Lösung 1: den Rest der Zeile mit ignore verwerfen.
Ausgabe:
age: 30
city: [Paris]
ignore(n, '\n') wirft Zeichen weg, bis es einen Zeilenumbruch oder n Zeichen entfernt hat, je nachdem, was zuerst eintritt. Den größtmöglichen std::streamsize-Wert zu übergeben heißt „bis zum Zeilenumbruch, egal wie weit weg“. Dabei verschwindet auch alles, was der Benutzer in derselben Zeile nach der Zahl getippt hat, etwa Leerzeichen am Ende. Für die Tastatur lautet die Zeile std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');, und sie braucht #include <limits>.
Ein bloßes std::cin.ignore() verwirft genau ein Zeichen. Das klappt, wenn der Zeilenumbruch direkt auf die Zahl folgt, und scheitert, sobald ein Leerzeichen davor steht.
Lösung 2: führende Leerzeichen mit std::ws überspringen.
Ausgabe:
age: 30
city: [Paris]
std::ws ist ein Manipulator, der an der aktuellen Position alle Leerraumzeichen (Leerzeichen, Tabs, Zeilenumbrüche) verbraucht. input >> std::ws gibt den Stream zurück und kann deshalb direkt in getline stehen. Es überspringt auch Leerzeilen und führende Leerzeichen. Für Namen und Städte ist das praktisch, aber falsch, wenn führende Leerzeichen oder eine leere Zeile eine bedeutsame Eingabe sind. Nimm in diesem Fall ignore.
Bis zum Ende der Eingabe lesen
getline gibt den Stream zurück, und ein Stream wird zu false, sobald ein Lesevorgang fehlschlägt. Wenn keine Zeilen mehr da sind, schlägt getline fehl. Eine while-Schleife darum liest also jede Zeile und hört am Ende auf:
Ausgabe:
1: [apples 3]
2: [bread 1]
3: []
4: [milk 2]
read 4 lines
Zwei Details aus dieser Ausgabe:
- Eine leere Zeile ist trotzdem ein erfolgreicher Lesevorgang. Sie ergibt einen leeren String, und die Schleife läuft weiter. Nur das Ende der Eingabe stoppt sie.
- Die letzte Zeile braucht keinen abschließenden Zeilenumbruch. Endete der Text mit
milk 2ohne\n, würdegetlinesie trotzdem liefern, und erst der nächste Aufruf schlüge fehl.
Mit std::cin liest dieselbe Schleife, bis die Eingabe endet. Das passiert, wenn die Eingabe aus einer Datei umgeleitet wird (./program < data.txt) oder wenn der Benutzer unter macOS und Linux Strg+D drückt, unter Windows Strg+Z und dann Enter.
Vermeide das Muster while (!input.eof()) { std::getline(input, line); ... }. eof() wird erst wahr, nachdem ein Lesevorgang bereits auf das Ende gestoßen ist. Der Rumpf läuft deshalb einmal zu oft, mit einem fehlgeschlagenen Lesevorgang und einem veralteten line. Setz den Aufruf von getline stattdessen in die Bedingung.
Eine Datei Zeile für Zeile lesen
Dateien verwenden dieselbe Schleife. Öffne die Datei mit std::ifstream aus <fstream>, prüf, ob sie geöffnet wurde, und lies:
Ausgabe:
1. Ada 92
2. Grace 88
3. Alan 95
if (!file) fängt eine fehlende Datei oder einen falschen Pfad vor der Schleife ab. Ohne diese Prüfung liest die Schleife einfach null Zeilen, was nach einer leeren Datei aussieht statt nach einem Fehler. Die Datei wird automatisch geschlossen, wenn file am Ende von main den Gültigkeitsbereich verlässt.
Unter Windows gespeicherte Dateien beenden jede Zeile mit \r\n. Liest man eine solche Datei unter Linux oder macOS, entfernt getline das \n, behält aber das \r. Jede Zeile endet dann mit einem unsichtbaren Wagenrücklauf, der Vergleiche wie line == "done" kaputt macht. Entferne ihn nach dem Lesen:
if (!line.empty() && line.back() == '\r') {
line.pop_back();
}
Ein eigenes Trennzeichen verwenden
Das dritte Argument ändert das Zeichen, das jeden Lesevorgang beendet. Ein häufiger Einsatz ist, eine Zeile an Kommas aufzuteilen. Lies zuerst die Zeile und teile sie dann über einen std::istringstream auf:
Ausgabe:
fields: 3
[Ada Lovelace]
[36]
[London]
Das Komma wird aus dem Stream entfernt und nicht gespeichert, genauso wie der Zeilenumbruch in der Standardform. Beachte, dass ein Zeilenumbruch mit einem eigenen Trennzeichen ein gewöhnliches Zeichen ist. Rufst du std::getline(file, field, ',') direkt auf einer mehrzeiligen Datei auf, kommen das letzte Feld einer Zeile und das erste Feld der nächsten zusammengeklebt zurück, etwa als "London\nGrace Hopper". Wer eine Zeile nach der anderen liest und jede Zeile einzeln aufteilt, vermeidet das. Die Seite zu String-Streams behandelt std::istringstream ausführlicher, auch die Umwandlung von Feldern wie "36" in Zahlen.
std::getline vs. cin.getline
Es gibt auch eine Memberfunktion mit ähnlichem Namen:
char buffer[20];
std::cin.getline(buffer, 20); // Memberfunktion, char-Array fester Größe
std::string text;
std::getline(std::cin, text); // freie Funktion, std::string
cin.getline schreibt in ein char-Array und speichert höchstens size - 1 Zeichen plus das abschließende '\0'. Eine längere Zeile versetzt den Stream in einen Fehlerzustand, und jeder spätere Lesevorgang wird übersprungen, bis du std::cin.clear() aufrufst. Bei std::getline mit einem std::string musst du dich um keine Längengrenze kümmern. Nimm es, außer du arbeitest mit einer API, die ein char-Array verlangt.
Häufige Fehler
>>undgetlinemischen, ohne den Zeilenumbruch zu entfernen. Setzignore(...)oderstd::wsdazwischen. Die Seite zu Ein- und Ausgabe zeigt dasselbe Problem mitstd::cinund wie du dich erholst, wenn das Einlesen einer Zahl fehlschlägt.getline(std::cin, number)mit einemintaufrufen.getlineliest nur in einenstd::string. Lies die Zeile und wandle sie dann mitstd::stoioder einemstd::istringstreamum.- Eine Schleife über
eof(). Prüf den Aufruf vongetlineselbst:while (std::getline(input, line)). #include <string>vergessen.std::getlinefür Strings ist in<string>deklariert. Manche Compiler lassen es über<iostream>durchgehen, und der Code scheitert dann auf einem anderen Compiler.- Nicht prüfen, ob eine Datei geöffnet wurde. Ein falscher Pfad lässt
std::ifstreamstillschweigend fehlschlagen, und die Leseschleife läuft null Mal.
Häufig gestellte Fragen
Was macht getline in C++?
std::getline(stream, text) liest Zeichen aus stream in den std::string text, bis es einen Zeilenumbruch erreicht, und entfernt diesen Zeilenumbruch dann aus dem Stream, ohne ihn zu speichern. Anders als cin >> text behält es Leerzeichen und liest so eine ganze Zeile wie einen vollständigen Namen oder einen Satz.
Warum wird getline nach cin >> in C++ übersprungen?
cin >> number hört beim Zeilenumbruch auf, den du nach der Zahl eingegeben hast, und lässt diesen Zeilenumbruch im Eingabepuffer liegen. Das nächste getline findet ihn sofort und liefert einen leeren String. Verwirf ihn zuerst mit std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n'); oder ruf std::getline(std::cin >> std::ws, text) auf, um führende Leerzeichen zu überspringen.
Wie verwende ich getline mit einem anderen Trennzeichen als dem Zeilenumbruch?
Übergib das Trennzeichen als drittes Argument: std::getline(stream, field, ','). Es liest bis zum nächsten Komma, speichert den Text davor und verwirft das Komma. Zeilenumbrüche gelten dann als gewöhnliche Zeichen, deshalb kombiniert man das meist mit einem std::stringstream, der aus einer einzelnen Zeile gebaut wird.
Wie lese ich in C++ eine Datei Zeile für Zeile?
Öffne sie mit std::ifstream file("data.txt"); und schreib eine Schleife while (std::getline(file, line)) { ... }. getline gibt den Stream zurück, der zu false wird, sobald keine Zeilen mehr da sind, also endet die Schleife am Dateiende.
Was ist der Unterschied zwischen cin.getline und getline?
std::getline(std::cin, text) ist eine freie Funktion, die in einen std::string liest, der für jede Zeile mitwächst. std::cin.getline(buffer, size) ist eine Memberfunktion, die in ein char-Array fester Größe liest und fehlschlägt, wenn die Zeile länger als size - 1 Zeichen ist. Nimm std::getline mit std::string, außer du hast einen Grund für rohe Arrays.