Unterm Strich oben: Bei ordnungsgemäßer Handhabung des Leerzeichens sieht das folgendermaßen aus eof
verwendet werden können (und sogar zuverlässiger sind als fail()
zur Fehlerprüfung):
while( !(in>>std::ws).eof() ) {
int data;
in >> data;
if ( in.fail() ) /* handle with break or throw */;
// now use data
}
( Danke Tony D für den Vorschlag, die Antwort hervorzuheben. In seinem Kommentar unten finden Sie ein Beispiel dafür, warum dies robuster ist. )
Das Hauptargument gegen die Verwendung eof()
scheint eine wichtige Feinabstimmung über die Rolle des Weißraums zu fehlen. Mein Vorschlag ist, dass bei der Überprüfung eof()
ist nicht nur ausdrücklich nicht " immer falsch " -- was eine vorherrschende Meinung in diesem und ähnlichen SO-Threads zu sein scheint --, aber mit der richtigen Behandlung von Leerzeichen sorgt es für eine sauberere und zuverlässigere Fehlerbehandlung und ist die immer richtig Lösung (auch wenn sie nicht unbedingt die kürzeste ist).
Zusammenfassend kann man sagen, dass die "richtige" Reihenfolge der Beendigung und des Lesens wie folgt aussieht:
int data;
while(in >> data) { /* ... */ }
// which is equivalent to
while( !(in >> data).fail() ) { /* ... */ }
Das Scheitern eines Leseversuchs nach eof wird als Abbruchbedingung angesehen. Dies bedeutet, dass es keine einfache Möglichkeit gibt, zwischen einem erfolgreichen Stream und einem Stream zu unterscheiden, der aus anderen Gründen als eof fehlschlägt. Nehmen Sie die folgenden Streams:
1 2 3 4 5<eof>
1 2 a 3 4 5<eof>
a<eof>
while(in>>data)
endet mit einem Satz failbit
para todo drei Eingaben. In der ersten und dritten, eofbit
ist ebenfalls festgelegt. Hinter der Schleife braucht man also eine sehr hässliche zusätzliche Logik, um eine richtige Eingabe (1.) von einer falschen (2. und 3.) zu unterscheiden.
Nehmen Sie dagegen Folgendes an:
while( !in.eof() )
{
int data;
in >> data;
if ( in.fail() ) /* handle with break or throw */;
// now use data
}
Hier, in.fail()
bestätigt, dass, solange es etwas zu lesen gibt, es auch das Richtige ist. Er dient nicht nur als Begrenzer der while-Schleife.
So weit, so gut, aber was passiert, wenn im Datenstrom Leerzeichen vorhanden sind - das klingt nach dem Hauptproblem gegen eof()
als Terminator?
Wir müssen unsere Fehlerbehandlung nicht aufgeben, sondern nur den Leerraum aufbrauchen:
while( !in.eof() )
{
int data;
in >> data >> ws; // eat whitespace with std::ws
if ( in.fail() ) /* handle with break or throw */;
// now use data
}
std::ws
überspringt jedes potenzielle (null oder mehr) Leerzeichen am Ende des Datenstroms, während es den eofbit
y nicht die failbit
. Also, in.fail()
funktioniert wie erwartet, solange es mindestens eine Datei zu lesen gibt. Wenn auch "All-Blank"-Streams akzeptabel sind, dann ist die korrekte Form:
while( !(in>>ws).eof() )
{
int data;
in >> data;
if ( in.fail() ) /* handle with break or throw */;
/* this will never fire if the eof is reached cleanly */
// now use data
}
Zusammenfassung: Eine richtig konstruierte while(!eof)
ist nicht nur möglich und nicht falsch, sondern ermöglicht auch die Lokalisierung von Daten innerhalb des Geltungsbereichs und bietet eine saubere Trennung der Fehlerprüfung von der normalen Geschäftstätigkeit. Davon abgesehen, while(!fail)
ist zweifellos eine gebräuchlichere und prägnantere Redewendung, die in einfachen Szenarien (einzelne Daten pro Lesevorgang) bevorzugt werden kann.
27 Stimmen
scanf(...) != EOF
wird auch in C nicht funktionieren, weilscanf
gibt die Anzahl der erfolgreich geparsten und zugewiesenen Felder zurück. Die korrekte Bedingung istscanf(...) < n
donden
ist die Anzahl der Felder in der Formatzeichenkette.8 Stimmen
@Ben Voigt, es wird eine negative Zahl zurückgegeben (die EOF normalerweise als solche definiert ist), wenn EOF erreicht wird
23 Stimmen
@SebastianGodelet: Tatsächlich wird es zurückkehren
EOF
wenn das Ende der Datei vor der ersten Feldumwandlung erreicht wird (erfolgreich oder nicht). Wird das Ende der Datei zwischen den Feldern erreicht, wird die Anzahl der erfolgreich umgewandelten und gespeicherten Felder zurückgegeben. Das macht den Vergleich mitEOF
falsch.2 Stimmen
@SebastianGodelet: Nein, nicht wirklich. Er irrt, wenn er sagt, dass es "hinter der Schleife keine (einfache) Möglichkeit gibt, eine korrekte Eingabe von einer unpassenden zu unterscheiden". In der Tat ist es so einfach wie die Überprüfung
.eof()
nach Beendigung der Schleife.4 Stimmen
@Ben Ja, für diesen Fall (Lesen eines einfachen int). Aber man kann sich leicht ein Szenario ausdenken, in dem
while(fail)
Schleife endet sowohl mit einem tatsächlichen Fehler als auch mit einem eof. Stellen Sie sich vor, Sie benötigen 3 Ints pro Iteration (sagen wir, Sie lesen einen x-y-z-Punkt oder so etwas), aber es sind fälschlicherweise nur zwei Ints im Stream.1 Stimmen
Die Antwort auf diese Frage ist dieselbe wie bei der Frage C: Warum
while(!feof(file))
immer falsch ist? . Da das Kennzeichen nur gesetzt ist nach die auf das EOF treffen.0 Stimmen
Hier ist die Meinung von C++ FAQ zur gleichen Frage.
0 Stimmen
@sly: Wird das "3-Ints"-Szenario nicht korrekt von
while (in >> x) { if (in >> y >> z) use(x, y, z); else FATAL("got an int not followed by 2 more!"); } if (!eof()) FATAL("didn't get integer where expected");
? Wenn nicht, für welche Stream-Inhalte würde das no gut funktionieren?1 Stimmen
Diese Frage wurde ohne Quellenangabe auf Quora gestellt: quora.com/unanswered/ (der Titel der Quora-Frage entspricht genau dem Titel, den diese Frage hatte, bevor sie gestern bearbeitet wurde).