开发者

file handling in c++

I wrote the following code to input numbers from a file however the last number gets printe开发者_Go百科d twice which I find perplexing. What could be the possible answer. Thanks in advance.

code:

#include<iostream>
#include<fstream>
using namespace std;
int main()
{
    int x;
    ifstream f;
    f.open("note");
    while(!f.eof()){
            f>>x;
            cout<<x<<endl;
    }
    return 0;
}

gives output:

1
2
3
4
5
5

the contents of file note are:

1
2
3
4
5 


Let me try to be a bit more illuminating than the previous answers here. f>>x reads an integer so it scans the input for digits. It sees '5' and then '\n', which is not a digit, so it stops after the '5' and sets x to 5. It has not yet encountered eof, your loop executes again, then f>>x reads the '\n' and then fails when it hits eof, leaving x unchanged, and you then print 5 again. So, you need to test after reading and before printing. The simplest (and preferred) way to do that is

while(f>>x)
    cout<<x<<endl;

You should not do something like

do{
    f>>x;
    cout<<x<<endl;
}while(!f.eof());

(which does not test after reading and before printing) because that results in undefined behavior if the input file does not contain any numbers -- x is unitialized and you'll print garbage (or possibly blow up the world, but probably not).


This is because EOF flag is only set when you have tried to read past the EOF. (It's an error flag)

So you better test f.eof() at the end of your loop.


Every solution so far presented has a good explanation of why the OP code is wrong. But most have the incorrect solution to the problem.

As stated many times before the EOF flag is not set until you try and read past the end of file. The last successful read may read up-to (inclusive) the last character. So in your case the last read will read the 5 from the file and then print it. We then renter enter the loop (which will work because the last read did not read past the end of file and thus EOF is false). Your attempt to read the next character will fail at f >> x and the variable 'x' will be left untouched (in your code this means it has the last value read a 5) and is then printed.

The solution is to test the condition of the stream after you have done the read to make sure it works. Note: You should not exclusively test for EOF there are other bad states. If one of the other bad states is entered the current code will enter an infinite loop. To check for all bad bits call fail() on the object. So the easiest solution is to put the read into the while test ( see below )

#include<iostream>
#include<fstream>
using namespace std;
int main()
{
    int x;
    ifstream f;
    f.open("note");
    while(f>>x)
    {
            cout<<x<<endl;
    }
    return 0;
}

This works because the >> operator returns a stream. When a stream object is used in a boolean context it is converted into a type than can represent true/false (for technical reasons this is not bool but you can think of it as a bool). The value returned depends on the state of the stream. If the stream is in a good state then it will (in a boolean context) evaluate to true thus allowing the loop to be entered, if the stream object is in an invalid state (ie EOF (or other failed state) is true) then it will evaluate to false and the loop is not entered.

Note: The conversion actually calls fail() on the stream to test the state.

If your code is complex and you can not test the state as part of the read. Then after each read you MUST test the state of the object to verify it worked.

#include<iostream>
#include<fstream>
using namespace std;
int main()
{
    int x;
    ifstream f;
    f.open("note");
    while(f)
    {
            f>>x;
            if (f) // dont' use f.eof() there are other bad states.
            {      // This will actuall call f.fail() which test for all bad states.
                   // Thus it only prints if the read worked.

                  cout<<x<<endl;
            }
            // Alternatively you can put the read into the if
            if ( f >> x)
            {
                  // STUFF
            }
    }
    return 0;
}

In response to Jim's comments.
Once a number has been read from the stream with the >> operator. No other characters are read. TO show this is true try the following code:

#include <iostream>
#include <fstream>
#include <string>

int main()
{
    std::ifstream  file("txt");
    std::string    line;
    int            x;

    while(f >> x)
    {
        std::getline(f, line);   // If the '\n' was read then
                                 // this code would remove the next line.
                                 // As it works correctly it simply removes then
                                 // characters upto the newline character after the number.
        std::cout << x << "\n";
    }
}
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜