Find the end of stream for cin & ifstream? - c++

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 a bad idea 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.

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 before = std::cin.eof();
std::cin >> s;
bool after = std::cin.eof();
std::cout << int(before) << " " << int(after) << " " << 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)

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

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).
}

Related

How would one generalise `clearerr()` under C++?…

TL;DR
I am aware that if a program listens for EOF (e.g. ^D) as a sign to stop taking input, e.g. by relying on a conditional like while (std::cin) {...}, one needs to call cin.clear() before standard input can be read from again (readers who'd like to know more, see this table).
I recently learned that this is insufficient, and that the underlying C file descriptors, including stdin, need clearerr() to be run to forget EOF states.
Since clearerr() needs a C-style file descriptor, and C++ operates mainly with std::basic_streambufs and the like (e.g. cin), I want to generalise some code (see below) to run clearerr() on any streambuf's associated C-style file-descriptor, even if that may not be stdin.
EDITS (1&2):
I wonder if stdin is the only ever file-descriptor that behaves like this (needing clearerr() to run) ...?
If it isn't, then the following code should end the question of generalisation (idea pointed out by zkoza in their answer)
As zkoza pointed out in their comment below, stdin is the only file-descriptor that would, logically, ever need such treatment (i.e. clearerr()). Checking whether a given C++ stream is actually really attached to *std::cin.rdbuf() is all that is needed:
std::istream theStream /* some stream with some underlying streambuf */
if (theStream.rdbuf() == std::cin.rdbuf())
clearerr(stdin);
Background
I'm writing a tool in C++ where I need to get multiple lines of user input, twice.
I know there are multiple ways of getting multiline input (e.g. waiting for double-newlines), but I want to use EOF as the user's signal that they're done — not unlike when you gpg -s or -e.
After much consultation (here, here, and on cppreference.com), I decided to use... (and I quote the third):
[the] idiomatic C++ input loops such as [...]
while(std::getline(stream, string)){...}
Since these rely on std::basic_ios::operator bool to do their job, I ensured that cin.rdstate() was cleared between the first and second user-input instructions (using cin.clear()).
The gist of my code is as follows:
std::istream& getlines (std::basic_istream<char> &theStream,
std::vector<std::string> &stack) {
std::ios::iostate current_mask (theStream.exceptions());
theStream.exceptions(std::ios::badbit);
std::string &_temp (*new std::string);
while (theStream) {
if (std::getline(theStream, _temp))
stack.push_back(_temp); // I'd really like the input broken...
// ... into a stack of `\n`-terminated...
// ... strings each time
}
// If `eofbit` is set, clear it
// ... since std::basic_istream::operator bool needs `goodbit`
if (theStream.eof())
theStream.clear(theStream.rdstate()
& (std::ios::failbit | std::ios::badbit));
// Here the logical AND with
// ... (failbit OR badbit) unsets eofbit
// std::getline sets failbit if nothing was extracted
if (theStream.fail() && !stack.size()) {
throw std::ios::failure("No input recieved!");
}
else if (theStream.fail() && stack.size()) {
theStream.clear(theStream.rdstate() & std::ios::badbit);
clearerr(stdin); // 👈 the part which I want to generalise
}
delete &_temp;
theStream.exceptions(current_mask);
return theStream;
}
This does what you need:
#include <iostream>
int main()
{
std::cin.sync_with_stdio(true);
char c = '1', d = '1';
std::cout << "Enter a char: \n";
std::cin >> c;
std::cout << (int)c << "\n";
std::cout << std::cin.eof() << "\n";
std::cin.clear();
clearerr(stdin);
std::cout << std::cin.eof() << "\n";
std::cout << "Enter another char: \n";
std::cin >> d;
std::cout << (int)d << "\n";
std::cout << std::cin.eof() << "\n";
}
It works because C++'s std::cin is tied, by default, with C's stdin (so, the first line is actually not needed). You have to modify your code to check if the stream is std::cin and if so, perform clearerr(stdin);
EDIT:
Actually, sync_with_stdio ensures only synchronization between the C and C++ interfaces, but internally they work on the same file descriptors and this may be why clearerr(stdin); works whether or not the interfaces are tied by sync_with_stdio
EDIT2: Does these answer your problem? Getting a FILE* from a std::fstream
https://www.ginac.de/~kreckel/fileno/ ?

What happens when c++ expects one data type and gets another?

I am new to c++ and was making a program in c++11 that sorts a list of integers using the bubble sort algorithm. While I was doing this I noticed something weird. This is my code:
#include <iostream>
void bubbleSort(int x) {
bool done;
int list[x] {0};
std::cout << "List:\n";
for (int i=0;i<x;i++) {
std::cout<<i<<':';
std::cin>>list[i];
}
do {
done = true;
for (int i=0;i<x-1;i++) {
if (list[i]>list[i+1]) {
list[i] = list[i]+list[i+1];
list[i+1] = list[i]-list[i+1];
list[i] = list[i]-list[i+1];
done = false;
}
}
} while (not done);
for (int i:list) {
std::cout<<i<<' ';
}
std::cout<<std::endl;
}
int main() {
int n;
std::cout<<"Length of list: ";
std::cin>>n;
bubbleSort(n);
}
If I input a char instead of an int the program outputs numbers leading up to the length of the list then a string of zeros equal to length of the list.
ex: if I input 5 then type 'k' at the input:
1:2:3:4:0 0 0 0 0
My question is, why is it producing this specific output? I would expect an error if it gets the wrong data type. Sorry if my question is confusing. Thanks in advance.
If you enter k when the input is expecting a number. Then the stream will go into an error state.
The problem is that you did not check the state:
std::cin>>n;
// There could be an error in the line above.
// But you did not check for the error.
Also here:
std::cin>>list[i];
// There could be an error in the line above.
// But you did not check for the error.
Try this:
if (std::cin >> n) {
std::cout << "It worked I got the number: " << n << "\n";
}
else
{
std::cout << "Failed to read a number.\n";
}
How does the above work.
Well the result of the operator>> is a reference to a stream. So it reads a value from the stream into n but returns a reference to the stream. This allows you to things like this:
std::cin >> n >> x >> y;
After each operator>> you get a reference to the stream to apply to the next operator>> so you can chain reads together.
When you use a stream in a boolean context (a test like an if or while) it will convert itself to boolean value depending on its internal state. If the internal state is good std::cin.good() then it will return true otherwise it returns false.
So after it completes the operator>> in then converts itself to bool for the if statement. If it is in a good state you know the read worked. If the read failed it would set an internal fail state and good() returns false.
So what happened in your code.
Well the read failed and the state of the stream was set to failed. When a read fails the preferred behavior is that object being read into remain unchanged (this is what happens for POD (standard) types, user defined types this can be a bit more haphazard).
So the value of n remains unchanged.
When you declared n
int n;
You did not define an initial value so it has an indeterminate value. Which means trying to read that value is UB. UB is bad. it means the code can do anything (which it has done). In practical terms (for most systems) it means the variable has an unknowable value and is whatever was left at that memory location from the last variable that used it.
For your specific case:
So you have typed 5 first then k.
So your first read std::cin >> n; worked.
The next read std::cin>>list[i]; failed.
This set the state of the stream to bad. Any subsequent reads do nothing (until you reset the stream state to good). So you are supposed to detect and fix the stream state.
Each subsequent time around the loop the std::cin >> list[i] will do nothing as the stream is in an error state. Which means it will keep its original value (which for this case is defined as zero 0).
Again the correct action here is to read and check the state of the stream. If it fails take corrective action:
if (std::cin >> list[i]) {
// Worked
}
else {
std::cerr << "Bad input. Try again\n";
// reset the state of the stream
// before trying to read again.
std::cin.clear();
if (std::cin >> list[i]) {
std::cerr << "You got it correct this time\n";
}
else {
std::cerr << "User not bright enough to use the app aborting\n";
throw std::runtime_error("Failed Bad User");
}
}
Additional Note
This behavior of streams is good for reading user input. As it allows a natural flow for detecting and writing code for the user to fix the issue. This design is practically the same for all modern languages that have the same pattern.
But this is not a good flow when you have machine input (ie. there are not expected to be any errors in the input and if there was an error there is no way to correct it).
For reading machine input you can set the stream to throw on an error. This allows you to write nice clean easy to read code that when things go wrong (when they should not) then an exception is throw causing the application to correctly terminate (or the exception could be caught).
std::cin.exceptions(std::ios::badbit); // Fail and Bad

does the this stl operator >> function make magic happens?

I have a weird problem when I test C++ STL features.
If I uncomment the line if(eee), my while loop never exits.
I'm using vs2015 under 64-bit Windows.
int i = 0;
istream& mystream = data.getline(mycharstr,128);
size_t mycount = data.gcount();
string str(mycharstr,mycharstr+mycount);
istringstream myinput(str);
WORD myfunclist[9] = {0};
for_each(myfunclist,myfunclist+9, [](WORD& i){ i = UINT_MAX;});
CALLEESET callee_set;
callee_set.clear();
bool failbit = myinput.fail();
bool eof = myinput.eof();
while (!failbit && !eof)
{
int eee = myinput.peek();
if (EOF == eee) break;
//if (eee) // if i uncomment this line ,the failbit and eof will always be false,so the loop will never exit.
{
myinput >> myfunclist[i++];
}
//else break;
failbit = myinput.fail();
eof = myinput.eof();
cout << myinput.rdstate() << endl;
}
I think that
int eee = myinput.peek();
at some point returns zero.
Then due to
if (eee)
you stop reading from the stream and never reach EOF.
Try to do
if (eee >= 0)
instead
As an alternative you could do:
if (eee < 0)
{
break;
}
// No need for further check of eee - just do the read
myinput >> myfunclist[i++];
The root cause of your problem is a misunderstanding about the way streams set their flags: fail() and eof() are only set once a reading operation fails or tried to read after the last byte was reached.
In other words, with C++ streams you may perfectly have read the last byte of your input and be at the end of file, yet eof() will stay false until you try to read more. You will find on StackOverflow many questions and answers about why you should not loop on eof in a C++ stream.
Consequences:
You will always enter into the loop, even if there is no character to read in myinput.
You therefore have to check for the special case of peek() returning EOF.
If you're still in the loop after the peek, then there are still characters to read. Keep in mind that peek() does not consume the characters. If you do not read it in a proper way, you stay at the same position in the stream. So if for any reason you do no reach myinput >> myfunclist[i++];, you're stuck in an endless loop, constantly peeking the same character over and over again. This is the 0 case that is well described in 4386427's answer : it's still there and you do not progress in the stream.
Other comments:
since your input can be 128 bytes long, and you read integers in text encoding, you could have evil input with 64 different words, causing your loop to go out ov bounds and cause for example memory corruption.
It is not clear why at all you try to peek.
I'd suggest to forget about the flags, use the usual stream reading idiom and simplify the code to:
...
callee_set.clear(); // until there, no change
while (i<9 && myinput >> myfunclist[i++])
{
cout << myinput.rdstate() << endl; // if you really want to know ;-)
}

Simple C++ not reading EOF

I'm having a hard time understanding why while (cin.get(Ch)) doesn't see the EOF. I read in a text file with 3 words, and when I debug my WordCount is at 3 (just what I hoped for). Then it goes back to the while loop and gets stuck. Ch then has no value. I thought that after the newline it would read the EOF and break out. I am not allowed to use <fstream>, I have to use redirection in DOS. Thank you so much.
#include <iostream>
using namespace std;
int main()
{
char Ch = ' ';
int WordCount = 0;
int LetterCount = 0;
cout << "(Reading file...)" << endl;
while (cin.get(Ch))
{
if ((Ch == '\n') || (Ch == ' '))
{
++WordCount;
LetterCount = 0;
}
else
++LetterCount;
}
cout << "Number of words => " << WordCount << endl;
return 0;
}
while (cin >> Ch)
{ // we get in here if, and only if, the >> was successful
if ((Ch == '\n') || (Ch == ' '))
{
++WordCount;
LetterCount = 0;
}
else
++LetterCount;
}
That's the safe, and common, way to rewrite your code safely and with minimal changes.
(Your code is unusual, trying to scan all characters and count whitespace and newlines. I'll give a more general answer to a slightly different question - how to read in all the words.)
The safest way to check if a stream is finished if if(stream). Beware of if(stream.good()) - it doesn't always work as expected and will sometimes quit too early. The last >> into a char will not take us to EOF, but the last >> into an int or string will take us to EOF. This inconsistency can be confusing. Therefore, it is not correct to use good(), or any other test that tests EOF.
string word;
while(cin >> word) {
++word_count;
}
There is an important difference between if(cin) and if(cin.good()). The former is the operator bool conversion. Usually, in this context, you want to test:
"did the last extraction operation succeed or fail?"
This is not the same as:
"are we now at EOF?"
After the last word has been read by cin >> word, the string is at EOF. But the word is still valid and contains the last word.
TLDR: The eof bit is not important. The bad bit is. This tells us that the last extraction was a failure.
The Counting
The program counts newline and space characters as words. In your file contents "this if fun!" I see two spaces and no newline. This is consistent with the observed output indicating two words.
Have you tried looking at your file with a hex editor or something similar to be sure of the exact contents?
You could also change your program to count one more word if the last character read in the loop was a letter. This way you don't have to have newline terminated input files.
Loop Termination
I have no explanation for your loop termination issues. The while-condition looks fine to me. istream::get(char&) returns a stream reference. In a while-condition, depending on the C++ level your compiler implements, operator bool or operator void* will be applied to the reference to indicate if further reading is possible.
Idiom
The standard idiom for reading from a stream is
char c = 0;
while( cin >> c )
process(c);
I do not deviate from it without serious reason.
you input file is
this is fun!{EOF}
two spaces make WordCount increase to 2
and then EOF, exit loop! if you add a new line, you input file is
this is fun!\n{EOF}
I took your program loaded it in to visual studio 2013, changed cin to an fstream object that opened a file called stuff.txt which contains the exact characters "This is fun!/n/r" and the program worked. As previous answers have indicated, be careful because if there's not a /n at the end of the text the program will miss the last word. However, I wasn't able to replicate the application hanging in an infinite loop. The code as written looks correct to me.
cin.get(char) returns a reference to an istream object which then has it's operator bool() called which returns false when any of the error bits are set. There are some better ways to write this code to deal with other error conditions... but this code works for me.
In your case, the correct way to bail out of the loop is:
while (cin.good()) {
char Ch = cin.get();
if (cin.good()) {
// do something with Ch
}
}
That said, there are probably better ways to do what you're trying to do.

How does ifstream's eof() work?

#include <iostream>
#include <fstream>
int main() {
std::fstream inf( "ex.txt", std::ios::in );
while( !inf.eof() ) {
std::cout << inf.get() << "\n";
}
inf.close();
inf.clear();
inf.open( "ex.txt", std::ios::in );
char c;
while( inf >> c ) {
std::cout << c << "\n";
}
return 0;
}
I'm really confused about eof() function. Suppose that my ex.txt's content was:
abc
It always reads an extra character and shows -1 when reading using eof(). But the inf >> c gave the correct output which was 'abc'? Can anyone help me explain this?
-1 is get's way of saying you've reached the end of file. Compare it using the std::char_traits<char>::eof() (or std::istream::traits_type::eof()) - avoid -1, it's a magic number. (Although the other one is a bit verbose - you can always just call istream::eof)
The EOF flag is only set once a read tries to read past the end of the file. If I have a 3 byte file, and I only read 3 bytes, EOF is false, because I've not tried to read past the end of the file yet. While this seems confusing for files, which typically know their size, EOF is not known until a read is attempted on some devices, such as pipes and network sockets.
The second example works as inf >> foo will always return inf, with the side effect of attempt to read something and store it in foo. inf, in an if or while, will evaluate to true if the file is "good": no errors, no EOF. Thus, when a read fails, inf evaulates to false, and your loop properly aborts. However, take this common error:
while(!inf.eof()) // EOF is false here
{
inf >> x; // read fails, EOF becomes true, x is not set
// use x // we use x, despite our read failing.
}
However, this:
while(inf >> x) // Attempt read into x, return false if it fails
{
// will only be entered if read succeeded.
}
Which is what we want.
The EOF flag is only set after a read operation attempts to read past the end of the file. get() is returning the symbolic constant traits::eof() (which just happens to equal -1) because it reached the end of the file and could not read any more data, and only at that point will eof() be true. If you want to check for this condition, you can do something like the following:
int ch;
while ((ch = inf.get()) != EOF) {
std::cout << static_cast<char>(ch) << "\n";
}
iostream doesn't know it's at the end of the file until it tries to read that first character past the end of the file.
The sample code at cplusplus.com says to do it like this: (But you shouldn't actually do it this way)
while (is.good()) // loop while extraction from file is possible
{
c = is.get(); // get character from file
if (is.good())
cout << c;
}
A better idiom is to move the read into the loop condition, like so:
(You can do this with all istream read operations that return *this, including the >> operator)
char c;
while(is.get(c))
cout << c;
eof() checks the eofbit in the stream state.
On each read operation, if the position is at the end of stream and more data has to be read, eofbit is set to true. Therefore you're going to get an extra character before you get eofbit=1.
The correct way is to check whether the eof was reached (or, whether the read operation succeeded) after the reading operation. This is what your second version does - you do a read operation, and then use the resulting stream object reference (which >> returns) as a boolean value, which results in check for fail().