views:

532

answers:

5

Following code, when compiled and run with g++, prints '1' twice, whereas I expect '1' to be printed only once, since I am dumping a single structure to the file, but while reading back it seems to be reading two structures. Why?

#include <iostream.h>
#include <fstream.h>

int main(){
    struct student
    {
     int rollNo;
    };
    struct student stud1;
    stud1.rollNo = 1;

    ofstream fout;
    fout.open("stu1.dat");
    fout.write((char*)&stud1,sizeof(stud1));
    fout.close();

    ifstream filin("stu1.dat");
    struct student tmpStu;
    while(!filin.eof())
    {
          filin.read((char*)&tmpStu,sizeof(tmpStu));
      cout << tmpStu.rollNo << endl; 
    }
    filin.close();
}
+8  A: 

eof only gets set after a read fails, so the read runs twice, and the second time, it doesn't modify the buffer.

Try this:

while(filin.read((char*)&tmpStu,sizeof(tmpStu)))
{
    cout << tmpStu.rollNo << endl; 
}

Or

while(!filin.read((char*)&tmpStu,sizeof(tmpStu)).eof())
{
    cout << tmpStu.rollNo << endl; 
}

Read returns a reference to filin when called, which will evaluate to true if the stream is still good. When read fails to read any more data, the reference will evaluate to false, which will prevent it from entering the loop.

Eclipse
+4  A: 

Your while loop is executing twice because the EOF condition is not true until the first attempt to read beyond the end of the file. So the cout is executed twice.

Steve Fallows
+1  A: 

I believe it is because you are checking for filin.eof() and that won't be true until the second time you read.

See here. It notes that eofbit is set "...The end of the source of characters is reached before n characters have been read ...". In your case you won't hit EOF until the second read.

borq
+1  A: 

This prints 1 twice because of the exact way eof and read work. If you are at the very end of a file, read will fail, then calls to eof after that return true. If you have not attempted to read past the end of the file, eof will return false because the stream is not in the EOF state, even though there is no more data left to read.

To summarize, your calls look like this:

eof - false (at beginning of file)
read (at beginning of file)
eof - false (now at end of file, but EOF not set)
read (at end of file. fails and sets EOF state internally)
eof - true (EOF state set)

A better strategy would be to check eof right after the read call.

Jay Conrod
A: 
Cool.
Another way (courtesy experts-exchange,I asked the same question there :-))

while(filin.peek() != EOF)
            {
              filin.read((char*)&tmpStu,sizeof(tmpStu));
              cout << tmpStu.rollNo << endl;
            }
dta