views:

110

answers:

3

Hi,

I'm running myself through a C++ text book that I have as a refresher to C++ programming. One of the practice problems (without going into too much detail) wants me to define a function that can be passed ifstream or cin (e.g. istream) as an argument. From there, I have to read through the stream. Trouble is, I can't figure out a way to have this one function use cin and ifstream to effectively find the end of the stream. Namely,

while(input_stream.peek() != EOF)

isn't going to work for cin. I could rework the function to look for a certain phrase (Like "#End of Stream#" or something) but I think this is inefficient (what if the file stream I pass has this exact phrase?).

I have thought to use function overloading, but so far the book has mentioned when it wants me to do this. I'm probably putting too much effort into this one practice problem, but I enjoy the creative process and am curious if there's such a way to do this without overloading.

Thanks.

+1  A: 

Why won't std::cin.eof() work? cin will signal EOF when stdin closes, which will happen when the user signals it with Ctrl+d (*nix) or Ctrl+z (Windows), or (in the case of a piped input stream) when the piped file ends

Michael Mrozek
In Windows it is `Ctrl+Z`, `Ctrl+D` is for UNIX-based systems.
Archie
@Archie Oh, good point; added that in
Michael Mrozek
Ah, that does indeed work (well Ctrl + Z for windows anyway). Sorry, if there's a little confusion as I originally had while(!input_stream.eof()) in the post before and edited it to while(input_stream.peek() != EOF). At any rate, 1 concern I have about using while(!input_stream.eof()) is that when the function does read the EOF character the fail bit is set for input_stream. Is this supposed to happen?
+2  A: 

eof() does work for cin. You are doing something wrong; please post your code. One common stumbling block is that eof flag gets set after you try to read behind the end of stream.

Here is a demonstration:

#include <iostream>
#include <string>

int main( int, char*[] )
{
    std::string s;
    for ( unsigned n = 0; n < 5; ++n )
    {
        bool b = std::cin.eof();
        std::cin >> s;
        bool a = std::cin.eof();
        std::cout << int(b) << " " << int(a) << "  " << s << std::endl;
    }

    return 0;
}

and its output:

D:>t
aaaaa
0 0  aaaaa
bbbbb
0 0  bbbbb
^Z
0 1  bbbbb
1 1  bbbbb
1 1  bbbbb

(EOF can be generated with Ctrl-Z on Windows and Ctrl-D on many other OSes)

atzz
Sorry for the confusion, I initially had while(!input_stream.eof()) but then realized I had written while(input_stream.peek != EOF) instead. Regardless, both methods work with control+z (ironically enough I was just reading about the eof character in wikipedia). Thanks for the help atzz, and everyone!
A: 

If you use a stream in a boolean context then it will convert itself into a value that is equivalent to true if it has not reached the EOF and false if an attempt has been made to read past the EOF (not it is also false if there was a previous error reading from the stream).

Since most IO operations on streams return the stream (so they can be chained). You can do your read operation and use the result in the test (as above).

So a program to read a stream of numbers from a stream:

int main()
{
   int x;

   // Here we try and read a number from the stream.
   // If this fails (because of EOF or other error) an internal flag is set.
   // The stream is returned as the result of operator>>
   // So the stream is then being used in the boolean context of the while()
   // So it will be converted to true if operator>>  worked correctly.
   //                         or false if operator>> failed because of EOF
   while(std::cin >> x)
   {
       // The loop is only entered if operator>> worked correctly.
       std::cout << "Value: " << x << "\n";
   }

   // Exit when EOF (or other error).
}
Martin York