0

When I run the following code, and I write for example "Peter" then the result is that I get "PeterPeter" in the file.

Why?

#include "stdafx.h"
#include "iostream"
#include "iomanip"
#include "cstdlib"
#include "fstream"
#include "string"

using namespace std;

int _tmain(int argc, _TCHAR* argv[])
{
    ofstream File2;
    File2.open("File2.dat",ios::out);

    string name;
    cout<<"Name?"<<endl;
    while(!cin.eof())
    {
        cin>>name;
        File2<<name;
    }
    return 0;
}

When I change the while loop to

while(cin>>name)
{
    File2<<name;
}

it works. But I don't understand why the first approach does not.

I can't answer my own question (as I don't have enough reputation). Hence I write my Answer here:

Ahhhh!!! Ok Thanks. Now I got it ^^

I have been testing with

    while(!cin.eof())
{
    cin>>name;
    File2<<name;
    cout<<j++<<"cin.eof() "<<cin.eof()<<endl;
}

What happens is that when I tip crtl+z he is still in the while loop. The variable name stays unchanged and is added to "File2" in the next line of code.

The following is working:

while(!cin.eof())
{
    cin>>name;
    if(!cin.eof()){File2<<name;}
    cout<<j++<<"cin.eof() "<<cin.eof()<<endl;
}
newandlost
  • 935
  • 2
  • 10
  • 21
  • What is your **cin** is it of **ifstream** type? if so, you must be having "Peter", written twice in you input file. please provide more information. – Zeeshan Sep 21 '13 at 08:40

2 Answers2

4

Ho hum, the millionth time this has been asked. This is wrong

while(!cin.eof())
{
    cin>>name;
    File2<<name;
}

eof() doesn't do what you think it does. You think it tells you whether you're at the end of file, right?

What eof() actually does is tell you why the last read you did failed. So it's something you call after you have done a read to see why it failed, not something you do before a read to see if it will fail. The return value of eof() when the last read has not failed is more complex. It depends on what you have been reading and how you've been reading it. You are trying to use eof() in a situation where there has been no failure and so the results can vary.

The short answer is don't to it like that, do it like this

while(cin >> name)
{
    File2<<name;
}

BTW, sorry for the flippant tone, I am seriously interested to know why you wrote the code wrong in the first place. We see this mistake all the time, it seems almost every newbie makes the same mistake, so I am interested to understand where this mistake comes from. Did you see that code somewhere else, did someone teach you to write that, did it just seem right to you, etc. etc. If you could explain in your case I'd appreciate it.

john
  • 85,011
  • 4
  • 57
  • 81
  • Exactly as you said. I thought cin.eof() would by default be equal to zero. When I press ctr+z I thought it would switch to 1. So... why isn't it working? :) – newandlost Sep 21 '13 at 08:43
  • @john i believe, this mistake comes from the habit of reading entire input file, which we (as newbie) most probably do at start of learning fstream :P – Zeeshan Sep 21 '13 at 08:44
  • 1
    What eof actually does it tell you **why the last read you did failed**. So it's something you call after you have done a read to see why it failed, not something you do before a read to see if it will fail. – john Sep 21 '13 at 08:44
  • Actually even the explanation above is a simplification because in some circumstances eof will tell you that you are at end of file, but it depends on what you are reading and how you are reading it. The take home message is that eof is not a particularly useful function, and that you should test the return value of the read itself to see if you should carry on reading. – john Sep 21 '13 at 08:48
  • OK Thank you very much! And I am amazed about how quickly you responded to my question. How is the echo at the end really produced? cin.eof() is recording and puts it's value at the end of "cin< – newandlost Sep 21 '13 at 08:49
  • 1
    The echo is produced because you go round the loop twice, even though you only have entered one value. The second time round the read fails (because of end of file) and `name` is left unaltered so you see it echoed. – john Sep 21 '13 at 08:51
  • @john Your first comment is excellent as far as it goes (and you really should work it into your answer). The second point (more subtle) is that if the input hasn't failed, the results of `eof()` may vary, so you cannot reliably use it for anything in such cases. – James Kanze Sep 21 '13 at 10:32
1

The basic problem of the using std::cin.eof() in the loop condition is that it tests the stream state before it is attempted to read anything from the stream. At this point, the stream has no idea what will be attempted to be read and it can't make any prediction of what will by tried. The fundamental insight is: You always have to verify that reading data was successful after reading it!

A secondary problem is that eof() only tests one of multiple error conditions. Reading a std::string can only go wrong if there is no further data but for most other data types there are also format failure. For example, reading an int can go wrong because there was a format mismatch. In that case the std::ios_base::failbit will be set and fail() would return true while eof() keeps returning false.

Testing the stream itself is equivalent to testing fail() which detects that something is wrong with the stream (it actually also tests if the stream is bad()). Thus, the canonical approach for reading a file typically has one of the following forms:

while (input) {
     // multiple read operations go here
     if (input) {
         // processing of the read data goes here
     }
}

or

while (/* reading everything goes here */) {
    // processing of the read data goes here
}

Obviously, you can use a for-loop instead of a while-loop. Another interesting approach to reading data uses std::istream_iterator<T> and assumes that there is an input operator for the type T. For example:

for (std::istream_iterator<std::string> it(std::cin), end; it != end; ++it) {
    std::cout << "string='" << *it << "'\n";
}

In none of these approaches eof() is used in the main reading loop. However, it is reasonable to use eof() after the loops to detect if the loop stopped because the end of the file was reached or because there was some formatting error.

Dietmar Kühl
  • 150,225
  • 13
  • 225
  • 380
  • Thank You very much Dietmar! I will need a while for fully understanding it and to go through your examples. Schöne Grüße, newandlost. – newandlost Sep 21 '13 at 09:44