Wenn ein Anfänger anfängt, ifstreams zu lesen, besteht sein Instinkt darin, die Datei mit einer Schleife zu lesen, die normalerweise so aussieht:
while (!ifstream.eof()
{
...
}
Als ich diesen Code verwendete, bemerkte ich jedoch, dass er nicht aufhörte, bis er die letzte Zeile der Datei zweimal gelesen hatte. C ++ - Programmierer bemerken, dass man eine Datei nicht so lesen sollte. Stattdessen empfehlen sie normalerweise, dass jeder, der eine Datei lesen muss, stattdessen eine Schleife wie diese verwendet:
while (ifstream >> someVar)
{
...
}
Warum funktioniert der erste Code immer nicht richtig?
Antworten:
Die
while (!ifstream.eof())
Schleife funktioniert nicht, da Streams / Dateien in C und C ++ nicht vorhersagen, wann Sie das Ende der Datei erreicht haben, sondern eher angeben, ob Sie versucht haben, über das Ende der Datei hinaus zu lesen .Wenn die letzte Zeile der Datei mit einem newline (
\n
) -Zeichen endet , werden die meisten Leseaktionen nicht mehr gelesen, wenn sie auf dieses Zeichen gestoßen sind und nicht erkennen, dass es sich um das letzte Zeichen in der Datei handelt. Bei der nächsten Leseaktion kann es sogar sein, dass mehr Zeichen angehängt wurden und der Lesevorgang diese erfolgreich extrahieren kann.Die Schleife, die den Stream-Extraktionsoperator (
while (ifstream >> someVar)
) verwendet, funktioniert, weil das Ergebnis des Stream-Extraktionsoperators als falsch ausgewertet wird, wenn ein Element des richtigen Typs nicht extrahiert werden konnte. Dies geschieht auch, wenn keine Zeichen mehr zu lesen sind.quelle
Das ist nicht was passiert. Das
eofbit
spielt bei der Konvertierung in einen Booleschen Wert (stream::operator bool
(oderoperator void*
in älterem c ++)) keine Rolle . Nur diebadbit
undfailbit
sind beteiligt.Angenommen, Sie lesen eine Datei mit durch Leerzeichen getrennten Zahlen. Eine Schleife, die auf basiert,
cin.eof()
ist unweigerlich entweder falsch oder vollerif
Tests. Sie lesen erst EOF. Sie lesen Zahlen. Lassen Sie Ihren Code diese Logik ausdrücken:Dies funktioniert unabhängig davon, ob die letzte Zeile der Datei mit
0 42\n
oder nur endet0 42
(keine neue Zeile am Ende der letzten Zeile in der Datei). Wenn die Datei mit endet0 42\n
, ruft der letzte gute Lesevorgang den Wert 42 ab und liest den letzten Zeilenende-Marker. Beachten Sie, dass der EOF-Marker noch nicht gelesen wurde. Die Funktionprocess_value
wird mit aufgerufen42
. Der nächste Aufruf zum Stream-Operator >> liest den EOF, und da nichts extrahiert wurde, sowohl daseofbit
undfailbit
wird eingestellt.Angenommen, die Datei endet mit
0 42
(keine neue Zeile am Ende der letzten Zeile). Der letzte gute Lesevorgang ruft den Wert 42 ab, der auf dem EOF-Marker endet. Vermutlich möchten Sie diese 42 verarbeiten. Aus diesem Grundeofbit
spielt das im booleschen Konvertierungsoperator des Eingabestreams keine Rolle. Beim nächsten Aufruf an den Stream-Extraktionsoperator >> erkennt die zugrunde liegende Maschine schnell, dass dereofbit
bereits eingestellt ist. Dies führt schnell zum Einstellen derfailbit
.Weil Sie nicht nach EOF als Schleifenbedingung suchen sollten. Die Schleifenbedingung sollte ausdrücken, was Sie versuchen, z. B. Zahlen aus einem Stream zu extrahieren.
quelle