mmmm...red candy.Stud has a sweet tooth, and I think he would like the red candy he gets
mmmm...red candy.Stud has a sweet tooth, and I think he would like the red candy he gets
Last edited by 7stud; 04-26-2005 at 11:01 AM.
Works differently, yes. But...Originally Posted by 7studThe reason I'd use getline in the condition instead of eof is the point joshdick is trying to make. If something happens and you cannot continue to read the file, the istream's fail bit is set. Only checking for eof could result in an infinite loop with faulty data since eof will never be set. It's helpful to stop reading the file as soon as an error occurs, and then you can check to see if the fail bit is set (which means an error occured) or the eof bit (which means everything worked out).Originally Posted by joshdick
If I did your homework for you, then you might pass your class without learning how to write a program like this. Then you might graduate and get your degree without learning how to write a program like this. You might become a professional programmer without knowing how to write a program like this. Someday you might work on a project with me without knowing how to write a program like this. Then I would have to do you serious bodily harm. - Jack Klein
Also using .eof could result in over-reading the file because the eof flag is not set until you actully hit the eof but using while(whateverinputmethod) will stop at the actual end of the file
Woop?
This is what I thought the discussion was about, and I have not been able to discern how getline() will have a problem setting the eof error flag in the code I posted.Also using .eof could result in over-reading the file because the eof flag is not set until you actully hit the eof but using while(whateverinputmethod) will stop at the actual end of the file
Thank you for explaining this problem. I thought this might work instead:The reason I'd use getline in the condition instead of eof is the point joshdick is trying to make. If something happens and you cannot continue to read the file, the istream's fail bit is set. Only checking for eof could result in an infinite loop with faulty data since eof will never be set. It's helpful to stop reading the file as soon as an error occurs, and then you can check to see if the fail bit is set (which means an error occurred) or the eof bit (which means everything worked out).
...but the eof error flag is not detected by that while condition, and therefore after the eof error flag has been set, the loop continues. Subsequently, another read attempt occurrs, but there is no more data, and a blank line is displayed as a result. When the additional read can't find any data, the failbit error flag is set causing the loop to end.Code:while(myInputFile) //fails for any error flag? { getline(myInputFile, input); cout<<"input: "<<input<<endl; }
Apparently, the while loop condition:
while(myInputFile)
can only detect the failbit error flag or the badbit error flag--but not the eofbit error flag.
I used this code to confirm the eofbit error flag cannot end the loop:
Code:while(myInputFile) { if(myInputFile.eof()) cout<<"eofbit error flag is set."<<endl; getline(myInputFile, input); cout<<"input: "<<input<<endl; if(myInputFile.eof()) cout<<"eofbit error flag is set."<<endl; if(myInputFile.bad()) cout<<"badbit error flag is set."<<endl; if(myInputFile.fail()) cout<<"failbit error flag is set."<<endl; }
Last edited by 7stud; 04-27-2005 at 10:51 PM.
Take a look at what you're doing, though. The eof bit is set on the getline call. Using that code, input has an erroneous value. I modified your code a little so that I could get a clearer understanding of the results. The input file I used was every 9-digit combination of the digits 1-9 (a result of some So Doku experiments).Results:Code:std::ifstream myInputFile; std::string input; myInputFile.open("combo.txt"); while(myInputFile) { if(myInputFile.eof()) cout<<"eofbit1 error flag is set."<<endl; getline(myInputFile, input); cout<<"input: "<<input<<endl; if(myInputFile.eof()) cout<<"eofbit2 error flag is set."<<endl; if(myInputFile.bad()) cout<<"badbit error flag is set."<<endl; if(myInputFile.fail()) cout<<"failbit error flag is set."<<endl; }Note the empty input after the last number. If you used that loop to get input, you'll end up with that faulty input. Instead, just do this:Code:<snip a lot of numbers> input: 999999998 input: 999999999 input: eofbit2 error flag is set. failbit error flag is set.Output:Code:while(getline(myInputFile, input)) { cout<<"input: "<<input<<endl; if(myInputFile.eof()) cout<<"eofbit error flag is set."<<endl; if(myInputFile.bad()) cout<<"badbit error flag is set."<<endl; if(myInputFile.fail()) cout<<"failbit error flag is set."<<endl; }That prevents you from running through your loop with invalid input.Code:<snip a lot of numbers> input: 999999995 input: 999999996 input: 999999997 input: 999999998 input: 999999999
If I did your homework for you, then you might pass your class without learning how to write a program like this. Then you might graduate and get your degree without learning how to write a program like this. You might become a professional programmer without knowing how to write a program like this. Someday you might work on a project with me without knowing how to write a program like this. Then I would have to do you serious bodily harm. - Jack Klein
yep:Originally Posted by pianorain
Originally Posted by 7stud
Last edited by 7stud; 04-28-2005 at 01:43 PM.
Ha...might help if I read the whole post from time to time. I would attempt to blame the lack of attention on illicit substances, but I don't have any.
[edit] Actually, after reading the post again, the code you really want to test is this:You'll see that the eof flag is still enough to tell the while loop to kick out.Code:getline(myInputFile,input) while(myInputFile) { if(myInputFile.eof()) cout<<"eofbit error flag is set."<<endl; if(myInputFile.bad()) cout<<"badbit error flag is set."<<endl; if(myInputFile.fail()) cout<<"failbit error flag is set."<<endl; cout<<"input: "<<input<<endl; getline(myInputFile, input); if(myInputFile.eof()) cout<<"eofbit error flag is set."<<endl; if(myInputFile.bad()) cout<<"badbit error flag is set."<<endl; if(myInputFile.fail()) cout<<"failbit error flag is set."<<endl; }
Last edited by pianorain; 04-28-2005 at 02:09 PM.
If I did your homework for you, then you might pass your class without learning how to write a program like this. Then you might graduate and get your degree without learning how to write a program like this. You might become a professional programmer without knowing how to write a program like this. Someday you might work on a project with me without knowing how to write a program like this. Then I would have to do you serious bodily harm. - Jack Klein
The code above from 7stud's post (third in the thread) is wrong.Code:ifstream myInputFile("C:\\TestData\\input.txt"); string input; while(!myInputFile.eof()) { getline(myInputFile, input); cout<<input<<endl; }
It is legal, but it outputs the input variable one too many times. The reason has been explained. The getline method sets the eof bit after it fails to read due to reaching the end of the file. The getline method and operator>> have the same behavior for this matter.
The common solution, as has been explained, is to make the input operation the condition for the loop. Another option, to more clearly show the behavior, is to check the eof bit after the attempted read, but before using the data:Code:ifstream myInputFile("C:\\TestData\\input.txt"); string input; while(!myInputFile.eof()) { getline(myInputFile, input); if (!myInputFile.eof()) cout<<input<<endl; }
My tests do not show that. Instead, they show that the eofbit does not cause the while loop to end, and it's only when failbit is set that the while loop ends. This is what I'm using:[edit] Actually, after reading the post again, the code you really want to test is this:You'll see that the eof flag is still enough to tell the while loop to kick out.Code:getline(myInputFile,input) while(myInputFile) { if(myInputFile.eof()) cout<<"eofbit error flag is set."<<endl; if(myInputFile.bad()) cout<<"badbit error flag is set."<<endl; if(myInputFile.fail()) cout<<"failbit error flag is set."<<endl; cout<<"input: "<<input<<endl; getline(myInputFile, input); if(myInputFile.eof()) cout<<"eofbit error flag is set."<<endl; if(myInputFile.bad()) cout<<"badbit error flag is set."<<endl; if(myInputFile.fail()) cout<<"failbit error flag is set."<<endl; }
sample output:Code:int count = 1; while(myInputFile) { cout<<count++<<"---------------------"<<endl; if(myInputFile.eof()) cout<<"first if: eofbit error flag is set."<<endl; if(myInputFile.bad()) cout<<"first if: badbit error flag is set."<<endl; if(myInputFile.fail()) cout<<"first if: failbit error flag is set."<<endl; getline(myInputFile, input); cout<<"input: "<<input<<endl; if(myInputFile.eof()) cout<<"2nd if: eofbit error flag is set."<<endl; if(myInputFile.bad()) cout<<"2nd if: badbit error flag is set."<<endl; if(myInputFile.fail()) cout<<"2nd if: failbit error flag is set."<<endl; }
output using your code:1---------------------
input: line 1 of text
2---------------------
input: line 2 of text
3---------------------
input: line 3 of text
2nd if: eofbit error flag is set.
4--------------------- <-----loop continues even though eofbit is set
first if: eofbit error flag is set.
input:
2nd if: eofbit error flag is set.
2nd if: failbit error flag is set. <----- causes loop to end
Press any key to continue
Both of the ouputs show that the while condition:1---------------------
input: line 1 of text
2---------------------
input: line 2 of text
2nd if: eofbit error flag is set.
3---------------------<---- loop continues even though eofbit is set
first if: eofbit error flag is set.
input: line 3 of text
2nd if: eofbit error flag is set.
2nd if: failbit error flag is set. <---- causes loop to end
while(myInputFile)
cannot detect the eofbit error flag, and it's the failbit error flag that causes the loop to fail. The technique of putting an extra read before the loop just ensures you don't get a bad line of input at the end.
Last edited by 7stud; 04-28-2005 at 05:00 PM.
Testing the stream will return false only on fail(), not on eof() by itself.
This is usually irrelevant, since in most cases there is a newline after the last line of input, and so the eofbit is set at the same time as the failbit. In the instance where the last line of valid input is not terminated with a newline, this distinction is important.
I think the tests I posted clearly show the eofbit is set before the last read; the last read, which fails to find any data, sets the failbit error flag.The getline method sets the eof bit after it fails to read due to reaching the end of the file.
No. When I said that the eofbit is set after it fails to read due to reaching the end of the file, I wasn't referring to fail as in the failbit. I meant that the eofbit is set after an attempt to read cannot be completed because the end of the file was reached.Originally Posted by 7stud
In your example, I can only assume there is no newline at the end of your last line of input. That means that the call to getline reaches the end of the file without ever reaching its delimiter. That means that the call to getline cannot be completed because the end of the file was reached. That is why the eofbit is set there, after the call to getline.
If you add a newline to your sample file, you will see that the eofbit is not set until after the fourth call to getline, because the third call will have successfully read a line of text up to its delimiter.
-----------------------------------
Your current argument might be correct, but it misses the point that your original code displays a common error with new programmers who assume that when they read in the last line of code, the input stream will magically be able to look ahead and see that no more data exists. That is not the case. The input stream only tells you its done after it tries to continue on and there is nothing there.
Last edited by Daved; 04-28-2005 at 05:23 PM.
Well, I don't think that is a correct analysis at all. The original code I posted tests for the eofbit error flag--that is a test that specifically detects when no more data exists. The test did not assume the input stream would magically look ahead to see that no more data exists--instead it specifically tested the stream to determine when no more data exists. The problem, as pianorain correctly pointed out, is that there are other possible stream errors besides no more data existing that make the code flawed. The original code can cause an infinite loop if one of those other stream errors should occur. If there were no possibility for other stream errors, the test in the original code would be fine.Your current argument might be correct, but it misses the point that your original code displays a common error with new programmers who assume that when they read in the last line of code, the input stream will magically be able to look ahead and see that no more data exists.
Last edited by 7stud; 04-28-2005 at 05:50 PM.
I don't know if you don't understand or if you disagree, but what I said is correct (note that I didn't say that you think the input stream magically looks ahead, just that your code displays a common error by beginners who think that). Try your original code with an input file that has a newline at the end of the last line of input (the much more common case). It fails by adding an extra line of output.
Ok.No. When I said that the eofbit is set after it fails to read due to reaching the end of the file, I wasn't referring to fail as in the failbit. I meant that the eofbit is set after an attempt to read cannot be completed because the end of the file was reached.
In your example, I can only assume there is no newline at the end of your last line of input. That means that the call to getline reaches the end of the file without ever reaching its delimiter. That means that the call to getline cannot be completed because the end of the file was reached. That is why the eofbit is set there, after the call to getline.