c++ while - Reading from text file until EOF repeats last line




to how (7)

The EOF pattern needs a prime read to 'bootstrap' the EOF checking process. Consider the empty file will not initially have its EOF set until the first read. The prime read will catch the EOF in this instance and properly skip the loop completely.

What you need to remember here is that you don't get the EOF until the first attempt to read past the available data of the file. Reading the exact amount of data will not flag the EOF.

I should point out if the file was empty your given code would have printed since the EOF will have prevented a value from being set to x on entry into the loop.

  • 0

So add a prime read and move the loop's read to the end:

int x;

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

This question already has an answer here:

The following C++ code uses a ifstream object to read integers from a text file (which has one number per line) until it hits EOF. Why does it read the integer on the last line twice? How to fix this?

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

Output:

10  
20  
30  
30

Note: I've skipped all error checking code to keep the code snippet small. The above behaviour is seen on Windows (Visual C++), cygwin (gcc) and Linux (gcc).


At the end of the last line, you have a new line character, which is not read by >> operator and it is not an end of file. Please, make an experiment and delete the new line (thelast character in file) - you will not get the duplication. To have a flexible code and avoid unwanted effects just apply any solution given by other users.


Just follow closely the chain of events.

  • Grab 10
  • Grab 20
  • Grab 30
  • Grab EOF

Look at the second-to-last iteration. You grabbed 30, then carried on to check for EOF. You haven't reached EOF because the EOF mark hasn't been read yet ("binarically" speaking, its conceptual location is just after the 30 line). Therefore you carry on to the next iteration. x is still 30 from previous iteration. Now you read from the stream and you get EOF. x remains 30 and the ios::eofbit is raised. You output to stderr x (which is 30, just like in the previous iteration). Next you check for EOF in the loop condition, and this time you're out of the loop.

Try this:

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

By the way, there is another bug in your code. Did you ever try to run it on an empty file? The behaviour you get is for the exact same reason.


I like this example, which for now, leaves out the check which you could add inside the while block:

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

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

Not sure how safe it is...


int x;
ifile >> x

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

There's an alternative approach to this:

#include <iterator>
#include <algorithm>

// ...

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

This is a header that declares a bunch of "intrinsics" -- functions that are built into the compiler so it can emit inline code for them. If you're using VC++ as the compiler, it should be in the same directory with its other standard headers. If you're using a different compiler, you'll need to change the intrinsics to suit the compiler you are using. gcc, for example, has a lot of similar intrinsic functions, but with slightly different names.

Edit: Given that you're using MinGW (I.e., gcc), you're pretty much stuck with porting the code (or using VC++). If you're dealing with a fairly small amount of code, one way to do that is to comment out the line that includes that header, and try to compile it. The compiler will point out errors where the intrinsic functions were used that gcc doesn't have. You can then look those up (e.g., on MSDN) and try to find something that gcc does provide that does (close enough to) the same thing. Depending on what it uses (and how much) that may be quick and easy, or it may be easier to start over producing new code to do the same things.

The *intrinsic headers you've found will (probably) contain declarations of (at least some of) gcc's counterparts to Microsoft's that you need to replace. You'll probably end up using them in the process of porting the code, so don't forget about them. At the same time, just including those headers instead of Microsoft's almost certainly isn't going to make the code work either.





c++ iostream fstream