istream public function eof() works not as expected!

Write your question here.
why did the the string "lichao!" be showed twice?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
  1 #include<fstream>
  2 #include<iostream>
  3 #include<string.h>
  4 #include<stdio.h>
  5 #include<sys/stat.h>
  6 #include<fcntl.h>
  7 using namespace std;
  8 
  9 
 10 istream &iostream_input(istream &is){
 11         string str;
 12         while(!is.eof()){
 13                 is>>str;
 14                 cout<<str<<endl;
 13
 16         }
 17        
 18         is.clear();
 19         if(!is.rdstate())
 20                 cout<<"istream accessable"<<endl;
 21         else
 22                 cout<<"istream forbiden"<<endl;
 23 }
 24 
 25 int main(){
 26         ifstream str;
 27         str.open("./zhouting.txt",ifstream::in);
 28         iostream_input(str);
 29 
 30 
 31         return 0;
 32 }



the content of the file "zhouting.txt" is "zhouting like lichao!"
This is wrong:
1
2
3
4
5
while( !is.eof() ) { 

         is >> str; // this attempted input may fail; but we are not checking for failure
         cout << str << endl; // print out str even if input failed
}


This is the canonically correct construct:
1
2
3
4
while( is >> str ) {
        
         std::cout << str << '\n' ;
}
the content of the file "zhouting.txt" is "zhouting like lichao!"

I tested the program with exactly that file content. This was the output:
zhouting
like
lichao!
istream accessable


but ... if I press enter at the end of the line, the file content becomes
"zhouting like lichao!\n"
and the output is now:
zhouting
like
lichao!
lichao!
istream accessable


That is only part of the problem. The behaviour is inconsistent depending on presence of whitespace. When the last item is read, because there is whitespace afterwards, end of file is not reached. But on the next iteration, the read will fail, so it just prints out the existing contents of the variable str.

The other part of the problem is we don't even know whether the file is being read at all.

Let's change the code to this, but keep the same input file:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
#include <fstream>
#include <iostream>

using namespace std;
   
istream &iostream_input(istream &is)
{
//    string str;
    int str = 0;  // use an integer instead of a string
    
    while (!is.eof())
    {
         is >> str;
         cout << str << endl;
    }
         
    is.clear();
    if (!is.rdstate())
        cout<<"istream accessable"<<endl;
    else
        cout<<"istream forbiden"<<endl;
        
    return is;        
 }
  
 int main()
 {
     ifstream str("./zhouting.txt");
     iostream_input(str);
 }


The output is now
0
0
0
0
0
0
0
0
0
0
0
0
... repeat to infinity 


The solution to both problems is the same.

Check that the file was actually read before trying to proceed. eof() at the start of the loop tells you about what happened in the past. It does not predict whether or not the next read attempt will be successful. In addition not all conditions will even set eof() at all. If there is an error, eof will never be true and it will loop forever.


The easiest way to do that is to put the input operation inside the loop condition (and forget you ever heard of eof()* ... at least for now).

Change this:
 
    while(!is.eof()){
to this:
 
    while ( is >> str )


*There are valid uses for eof() but they may be considered advanced /specialised applications.
Last edited on
thank you for your help,at first!
and i think that the public function eof() of istream may have a problem in analyzing if the file comes to an end with EOF;and the code i write also has a problem that can't repeat the contents of the file wanted as it looks like!And then i rewrite the code as follow ,i think it works better!

1 #include<fstream>
2 #include<iostream>
3 #include<string.h>
4 #include<stdio.h>
5 #include<sys/stat.h>
6 #include<fcntl.h>
7 using namespace std;
8
9
10 istream &iostream_input(istream &is){
11 char c;
12 //to have the character in the istream
13 while(is.get(c)){
14 if(c==EOF)
15 break;
16 cout<<c;
17 }
18
19 is.clear();
20 if(!is.rdstate())
21 cout<<"istream accessable"<<endl;
22 else
23 cout<<"istream forbiden"<<endl;
24 }
25
26 int main(){
27 ifstream str;
28 str.open("./zhouting.txt",ifstream::in);
29 iostream_input(str);
30 str.close();
31
32 return 0;
33 }
~
Click the <> button on the right, then copy and paste your file between the [code] and [/code] tags.
> the public function eof() of istream may have a problem in analyzing if the file comes to an end with EOF;

No, it does not have any problem.

This function only reports the stream state as set by the most recent I/O operation; it does not examine the associated data source. For example, if the most recent I/O was a get(), which returned the last byte of a file, eof() returns false. The next get() fails to read anything and sets the eofbit. Only then eof() returns true.
http://en.cppreference.com/w/cpp/io/basic_ios/eof


Repeat: this is the canonical way to read everything up to the end of stream
1
2
3
4
while( is >> str ) { // 
        
         std::cout << str << '\n' ;
}


To non-destructively check if the input stream is in a readable state, either use peek()
or use get(char) followed by unget() if the get was successful.
Topic archived. No new replies allowed.