Frage

Die folgende C++ Code verwendet a ifstream Objekt zum Lesen von Ganzzahlen aus einer Textdatei (die eine Zahl pro Zeile enthält), bis es trifft EOF.Warum wird die Ganzzahl in der letzten Zeile zweimal gelesen?Wie kann man das beheben?

Code:

#include <iostream>
#include <fstream>
using namespace std;

int main()
{
    ifstream iFile("input.txt");    // input.txt has integers, one per line

    while (!iFile.eof())
    {
        int x;
        iFile >> x;
        cerr << x << endl;
    }

    return 0;
}

input.txt:

10  
20  
30

Ausgabe:

10  
20  
30  
30

Notiz:Ich habe den gesamten Fehlerprüfcode übersprungen, um den Codeausschnitt klein zu halten.Das obige Verhalten tritt unter Windows (Visual C++), Cygwin (gcc) und Linux (gcc) auf.

War es hilfreich?

Lösung

Verfolgen Sie einfach genau die Kette der Ereignisse.

  • Schnapp dir 10
  • Schnapp dir 20
  • Schnapp dir 30
  • Schnappen Sie sich EOF

Schauen Sie sich die vorletzte Iteration an.Sie haben sich 30 geschnappt und dann weiter nach EOF gesucht.Sie haben EOF noch nicht erreicht, weil die EOF-Markierung noch nicht gelesen wurde („binarisch gesehen liegt ihre konzeptionelle Position direkt nach der 30er-Zeile).Daher fahren Sie mit der nächsten Iteration fort.x ist immer noch 30 aus der vorherigen Iteration.Jetzt lesen Sie aus dem Stream und erhalten EOF.x bleibt 30 und das ios::eofbit wird erhöht.Sie geben die Ausgabe in stderr x aus (was 30 ist, genau wie in der vorherigen Iteration).Als Nächstes prüfen Sie, ob die Schleifenbedingung EOF aufweist, und dieses Mal befinden Sie sich außerhalb der Schleife.

Versuche dies:

while (true) {
    int x;
    iFile >> x;
    if( iFile.eof() ) break;
    cerr << x << endl;
}

Übrigens gibt es noch einen weiteren Fehler in Ihrem Code.Haben Sie jemals versucht, es mit einer leeren Datei auszuführen?Das Verhalten, das Sie erhalten, hat genau den gleichen Grund.

Andere Tipps

Mir gefällt dieses Beispiel, das vorerst die Prüfung weglässt, die Sie innerhalb des while-Blocks hinzufügen könnten:

ifstream iFile("input.txt");        // input.txt has integers, one per line
int x;

while (iFile >> x) 
{
    cerr << x << endl;
}

Ich bin mir nicht sicher, wie sicher es ist ...

Hierfür gibt es einen alternativen Ansatz:

#include <iterator>
#include <algorithm>

// ...

    copy(istream_iterator<int>(iFile), istream_iterator<int>(),
         ostream_iterator<int>(cerr, "\n"));

Das EOF-Muster benötigt einen ersten Lesevorgang, um den EOF-Prüfprozess zu starten.Bedenken Sie, dass der EOF der leeren Datei zunächst erst beim ersten Lesen festgelegt wird.Der primäre Lesevorgang fängt in diesem Fall den EOF ab und überspringt die Schleife ordnungsgemäß vollständig.

Hier müssen Sie bedenken, dass Sie den EOF erst beim ersten Leseversuch über die verfügbaren Daten der Datei hinaus erhalten.Das Auslesen der genauen Datenmenge führt nicht zur Kennzeichnung des EOF.

Ich möchte darauf hinweisen, dass Ihr angegebener Code gedruckt worden wäre, wenn die Datei leer gewesen wäre, da der EOF verhindert hätte, dass beim Eintritt in die Schleife ein Wert auf x gesetzt wurde.

  • 0

Fügen Sie also einen ersten Lesevorgang hinzu und verschieben Sie den Lesevorgang der Schleife an das Ende:

int x;

iFile >> x; // prime read here
while (!iFile.eof()) {
    cerr << x << endl;
    iFile >> x;
}

Ohne große Änderungen am Originalcode könnte daraus Folgendes werden:

while (!iFile.eof())
{  
    int x;
    iFile >> x;
    if (!iFile.eof()) break;
    cerr << x << endl;
}

aber ich bevorzuge im Allgemeinen die beiden anderen oben genannten Lösungen.

int x;
ifile >> x

while (!iFile.eof())
{  
    cerr << x << endl;        
    iFile >> x;      
}

Am Ende der letzten Zeile steht ein Zeilenumbruchzeichen, das vom Operator >> nicht gelesen wird und kein Dateiende darstellt.Bitte machen Sie ein Experiment und löschen Sie die neue Zeile (das letzte Zeichen in der Datei) – Sie erhalten keine Duplikate.Um einen flexiblen Code zu haben und unerwünschte Effekte zu vermeiden, wenden Sie einfach eine beliebige Lösung anderer Benutzer an.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top