Warum ist iostream::eof innerhalb einer Schleife ist die Bedingung (D. H. " beim (!stream.eof())`) als falsch?
Ich habe gerade einen Kommentar in diese Antwort sagen, dass mit iostream::eof
in einer Schleife, Bedingung ist "nahezu sicher falsch". Ich verwende in der Regel so etwas wie while(cin>>n)
- ich glaube, das implizit prüft EOF.
Warum ist die überprüfung für eof explizit mit while (!cin.eof())
falsch?
Wie unterscheidet es sich von mit scanf("...",...)!=EOF
in C (was ich oft verwenden, ohne Probleme)?
scanf(...) != EOF
funktioniert nicht in C, weil scanf
gibt die Anzahl der Felder erfolgreich analysiert und zugeordnet. Die korrekte Bedingung ist scanf(...) < n
wo n
ist die Anzahl der Felder in der format-string.Voigt, es gibt eine negative Zahl ist (EOF ist normalerweise definiert als solche) im Fall von EOF erreicht ist
Tatsächlich, wird es wieder
EOF
wenn das Ende der Datei angetroffen wird, bevor das erste Feld Konvertierung (erfolgreich oder nicht). Wenn das Ende der Datei erreicht ist zwischen den Feldern, es wird wieder die Anzahl der Felder succcessfully umgewandelt und gespeichert. Das macht den Vergleich zu EOF
falsch.Nein, nicht wirklich. Er Irrt, wenn er sagt, dass "die Vergangenheit die Schleife gibt es keine (einfache) Weise zu unterscheiden, dass eine richtige Eingabe aus einer missbräuchlichen one". In der Tat ist es so einfach wie die überprüfung
.eof()
nachdem die Schleife beendet.Ja, für diesen Fall (Lesen eines einfachen int). Aber man kann leicht kommen mit einem Szenario, in dem
while(fail)
Schleife beendet mit einem tatsächlichen Ausfall und ein eof. Denke, über, wenn Sie 3 ints pro iteration (sagen Sie, dass Sie Lesen eine x-y-z-Punkt oder so), aber es ist, fälschlicherweise, nur zwei ints in den Bach.InformationsquelleAutor MAK | 2011-04-09
Du musst angemeldet sein, um einen Kommentar abzugeben.
Weil
iostream::eof
nur zurücktrue
nach Lesen das Ende des Streams. Es tut nicht darauf hinzuweisen, dass die nächste lese-wird das Ende des Streams.Betrachten Sie diese (und übernehmen dann weiter Lesen, werden am Ende des Streams):
Gegen diese:
Und auf Ihre zweite Frage: Da
ist das gleiche wie
und nicht das gleiche wie
Ich denke, es ist erwähnenswert, dass, diese Antwort ist etwas irreführend. Bei der Extraktion
int
s oderstd::string
s oder ähnlich, ist das EOF-bit ist gesetzt, wenn Sie extrahieren die man kurz vor dem Ende, und die Extraktion trifft das Ende. Sie brauchen nicht noch einmal zu Lesen. Der Grund, warum es nicht gesetzt, wenn das Lesen aus Dateien ist, weil es eine zusätzliche\n
am Ende. Ich habe bedeckt dieses in eine weitere Antwort. Lesenchar
s ist eine andere Rolle, weil es nur extrahiert und nicht weiter Treffer zum Ende.Das Hauptproblem ist, dass nur, weil wir noch nicht erreicht, EOF, bedeutet nicht, dass der nächste gelesen wird erfolgreich.
alles wahr, aber nicht sehr nützlich... auch wenn es keine abschließenden '\n' es ist vernünftig, zu wollen, dass andere nachfolgende Leerzeichen behandelt werden konsequent mit anderen whitespace in der Datei (d.h. übersprungen). Weitere, subtile Konsequenz ", wenn Sie extrahieren die man direkt vor" ist, dass
while (!eof())
nicht "arbeiten" aufint
s oderstd::string
s, wenn die Eingabe vollständig leer sein, also auch zu wissen, es gibt keine nachgestellten\n
Pflege ist nötig.Völlig einverstanden. Der Grund, warum ich sage, es ist, weil ich denke, dass die meisten Menschen, wenn Sie Lesen diese und ähnliche Antworten werden denken, dass wenn der stream enthält
"Hello"
(keine Leerzeichen oder\n
) und einestd::string
extrahiert wird, wird es extrahieren Sie die Buchstaben ausH
zuo
stoppen extrahieren, und dann nicht setzt das EOF-bit. In der Tat, es würde das EOF-bit, denn es war der EOF, der beendet wurde die Extraktion. Nur in der Hoffnung, klar, dass Sie sich für die Menschen.InformationsquelleAutor Xeo
Bottom-line-top: Mit der richtigen Handhabung von white-space, das folgende ist, wie
eof
verwendet werden können (und sogar zuverlässiger alsfail()
für die Fehlerprüfung):(Dank Tony D für die Anregung zu markieren die Antwort. Siehe sein Kommentar unten für ein Beispiel, warum das so ist robuster.)
Das wichtigste argument gegen die Verwendung von
eof()
scheint zu sein, fehlt eine wichtige Feinheit, über die Rolle der weißen Raum. Mein Vorschlag ist, dass die überprüfungeof()
explizit ist nicht nur nicht "immer falsch" - das scheint zu einem überwiegenden Meinung in diesen und ähnlichen SO threads --, aber mit der richtigen Handhabung von white-space, sorgt es für eine saubere und zuverlässige Fehlerbehandlung, und ist die immer richtig Lösung (obwohl, nicht unbedingt die tersest).Zusammenfassen, was wird vorgeschlagen, die als die "richtige" Kündigung und lese-Reihenfolge ist folgende:
Den Ausfall aufgrund von lese-Versuch über eof als Abbruchbedingung. Dies bedeutet, dass es keine einfache Möglichkeit, zu unterscheiden zwischen einem erfolgreichen stream-und eine, die wirklich scheitert aus anderen Gründen als der eof. Nehmen Sie die folgenden Ströme:
1 2 3 4 5<eof>
1 2 a 3 4 5<eof>
a<eof>
while(in>>data)
endet mit einem Satzfailbit
für alle drei ein. In der ersten und Dritten,eofbit
ist auch gesetzt. Also vorbei an den loop braucht man sehr hässlich zusätzliche Logik zu unterscheiden, dem richtigen input (1.) durch unsachgemäße (2. und 3.).In der Erwägung, dass die folgenden:
Hier
in.fail()
überprüft, wie lange, wie es ist, etwas zu Lesen, es ist die richtige. Es ist Ziel ist nicht eine bloße while-loop-terminator.So weit so gut, aber was passiert, wenn es Leerzeichen im stream -- was sich anhört wie die großen Bedenken gegen
eof()
als terminator?Brauchen wir nicht zu kapitulieren unsere Fehler-handling; einfach nur Essen, bis die white-space:
std::ws
überspringt alle Potenzial (null oder mehr) Leerzeichen in den Strom während der Einstellung dereofbit
, und nicht diefailbit
. Alsoin.fail()
wie erwartet funktioniert, solange es mindestens einen Daten zu Lesen. Wenn alle-leer-streams sind auch in Ordnung, dann die richtige form ist:Zusammenfassung: Eine richtig konstruierte
while(!eof)
ist nicht nur möglich und nicht falsch, sondern es erlaubt, Daten lokalisiert werden, die in Umfang, und liefert eine sauberere Trennung der Fehlerprüfung von business as usual. Dass gesagt wird, diewhile(!fail)
ist unbestritten ein häufiger und knappe Sprache, und kann bevorzugt in einfacher (single-Daten-per-Lesen-Typ-Szenarien).eofbit
undfailbit
festgelegt sind, in der anderen nurfailbit
eingestellt ist. Sie brauchen nur zu prüfen, dass einmal, nachdem die Schleife beendet wurde, wird nicht bei jeder iteration; es wird nur verlassen Sie die Schleife einmal, so müssen Sie nur überprüfen, warum verließ er die Schleife einmal.while (in >> data)
funktioniert gut für alle leeren streams.Das, was Sie sagen (und einen Punkt zuvor) ist, dass einem schlecht formatierten Datenstrom identifiziert werden können, wie
!eof & fail
letzten Schleife. Es gibt Fälle, in denen kann man sich darauf nicht verlassen. Siehe oben Kommentar (goo.gl/9mXYX). Eitherway, ich plädiere nicht dafüreof
-überprüfen Sie, wie der-immer-besser alternative. Ich bin lediglich zu sagen, es wird eine mögliche und (in einigen Fällen mehr entsprechenden) Art und Weise, dies zu tun, eher als "sicherlich falsch!" wie es dazu neigt, in Anspruch genommen werden, um hier in SO."Als ein Beispiel, betrachten, wie würden Sie auf Fehler überprüfen, wo die Daten eine Struktur mit überladenen operator>> Lesen Sie mehrere Felder auf einmal" - einem viel einfacheren Fall auf die Unterstützung Ihrer Punkt ist
stream >> my_int
wo der stream enthält, z.B. "-":eofbit
undfailbit
gesetzt sind. Das ist schlimmer, als dieoperator>>
Szenario, in dem die vom Benutzer bereitgestellten überlastung hat zumindest die option, clearingeofbit
vor der Rückkehr zu unterstützenwhile (s >> x)
die Nutzung. Mehr in der Regel, diese Antwort könnte ein clean-up - nur der Letztewhile( !(in>>ws).eof() )
ist in der Regel robust, und er ist begraben am Ende... in der Tat. Danke. Ich aktualisierte die Antwort.
InformationsquelleAutor sly
Weil wenn die Programmierer nicht schreiben
while(stream >> n)
, Sie könnten schreiben:Hier das problem ist, man kann nicht
some work on n
ohne zuvor zu prüfen, wenn der stream Lesen erfolgreich war, denn wenn es nicht erfolgreich war, Ihresome work on n
würde unerwünschte Ergebnis.Der springende Punkt ist, dass
eofbit
,badbit
oderfailbit
gesetzt sind nach dem Versuch zum Lesen aus dem stream. Also, wennstream >> n
ausfällt, danneofbit
,badbit
oderfailbit
ist umgehend, so dass Ihr weitere Redewendungen, wenn Sie schreibenwhile (stream >> n)
werden, weil das zurückgegebene Objektstream
konvertiertfalse
wenn es einige Fehler in der Lesung aus dem stream und somit die Schleife beendet. Und es wandelt auftrue
wenn das Lesen erfolgreich war und die Schleife fortgesetzt.n
mag das Programm auch fallen in ein Endlosschleife, wenn Sie den fehlerhaften stream-Betrieb verbraucht nicht jede Eingabe.InformationsquelleAutor Nawaz
Die anderen Antworten haben erklärt, warum die Logik ist falsch in
while (!stream.eof())
und wie es zu lösen ist. Ich möchte den Fokus auf etwas anderes:Im Allgemeinen, die überprüfung für die
eof
nur ist falsch, weil Strom-Extraktion (>>
) ausfallen kann, ohne auf das Ende der Datei. Wenn Sie z.B.int n; cin >> n;
und der stream enthälthello
, dannh
ist keine gültige Ziffer, also die Extraktion wird fehlschlagen, ohne erreichen des Endes der Eingabe.Dieses Problem, in Kombination mit der Allgemeinen Logik-Fehler überprüfen Sie den stream-Zustand vor dem Lesen, was bedeutet, dass für die N Eingabe Elemente, die Schleife wird ausgeführt N+1-mal, führt zu der folgenden Symptome:
Wenn der stream leer ist, wird die Schleife einmal ausgeführt.
>>
fehl (es ist kein Eingang zu Lesen) und alle Variablen, die angeblich eingestellt werden (durchstream >> x
) sind tatsächlich nicht initialisiert. Dies führt zu Datenmüll verarbeitet werden, welche sich dann als unsinnige Ergebnisse (oft riesige zahlen).Wenn der stream nicht leer ist, wird die Schleife erneut ausgeführt, nachdem die Letzte gültige Eingabe. Da in der letzten iteration alle
>>
Operationen fehlschlagen Variablen sind wahrscheinlich zu halten, die Ihren Wert aus der vorherigen iteration. Dies kann sich als "die Letzte Zeile ist zweimal gedruckt" oder "die Letzte input-Datensatz ist doppelt verarbeitet".Wenn der stream enthält fehlerhafte Daten, aber Sie prüfen nur für
.eof
Sie am Ende mit einem unendlichen loop.>>
wird scheitern, um zu extrahieren alle Daten aus dem stream, so dass die Schleife dreht sich in Ort, ohne jemals das Ende.Zur Erinnerung: Die Lösung ist zum testen der Erfolg der
>>
operation selbst, nicht mit einem separaten.eof()
Methode:while (stream >> n >> m) { ... }
, genau wie in C-testen Sie den Erfolg derscanf
nennen sich selbst:while (scanf("%d%d", &n, &m) == 2) { ... }
.InformationsquelleAutor melpomene