Loop question

This is a discussion on Loop question within the C++ Programming forums, part of the General Programming Boards category; Stud has a sweet tooth, and I think he would like the red candy he gets mmmm...red candy....

  1. #16
    Registered User
    Join Date
    Apr 2003
    Posts
    2,662
    Stud has a sweet tooth, and I think he would like the red candy he gets
    mmmm...red candy.
    Last edited by 7stud; 04-26-2005 at 11:01 AM.

  2. #17
    Anti-Poster
    Join Date
    Feb 2002
    Posts
    1,399
    Quote Originally Posted by 7stud
    The code sample at that link uses the >>operator. The code I posted uses getline(). The >>operator works differently then getline() which you don't seem to understand.
    Works differently, yes. But...
    Quote Originally Posted by joshdick
    getline() returns a reference to an istream just like the extraction operator does. An istream returns false when an error condition or EOF is reached.
    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 occured) or the eof bit (which means everything worked out).
    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

  3. #18
    Sweet
    Join Date
    Aug 2002
    Location
    Tucson, Arizona
    Posts
    1,807
    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?

  4. #19
    Registered User
    Join Date
    Apr 2003
    Posts
    2,662
    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
    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.

    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).
    Thank you for explaining this problem. I thought this might work instead:
    Code:
    while(myInputFile) //fails for any error flag?
    {
    	getline(myInputFile, input);
    	cout<<"input: "<<input<<endl;
    }
    ...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.

    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.

  5. #20
    Anti-Poster
    Join Date
    Feb 2002
    Posts
    1,399
    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).
    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;
    }
    Results:
    Code:
    <snip a lot of numbers>
    input: 999999998
    input: 999999999
    input:
    eofbit2 error flag is set.
    failbit error flag is set.
    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:
    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;
    }
    Output:
    Code:
    <snip a lot of numbers>
    input: 999999995
    input: 999999996
    input: 999999997
    input: 999999998
    input: 999999999
    That prevents you from running through your loop with invalid input.
    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

  6. #21
    Registered User
    Join Date
    Apr 2003
    Posts
    2,662
    Quote Originally Posted by pianorain
    Note the empty input after the last number. If you used that loop to get input, you'll end up with that faulty input.
    yep:
    Quote Originally Posted by 7stud
    I thought this might work instead:

    while(myInputFile) //fails for any error flag?

    ...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.
    Last edited by 7stud; 04-28-2005 at 01:43 PM.

  7. #22
    Anti-Poster
    Join Date
    Feb 2002
    Posts
    1,399
    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:
    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;
    }
    You'll see that the eof flag is still enough to tell the while loop to kick out.
    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

  8. #23
    Registered User
    Join Date
    Jan 2005
    Posts
    7,318
    Code:
    ifstream myInputFile("C:\\TestData\\input.txt");
    string input;
     
    while(!myInputFile.eof())
    {
    	getline(myInputFile, input);
    	cout<<input<<endl;
    }
    The code above from 7stud's post (third in the thread) is wrong.

    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;
    }

  9. #24
    Registered User
    Join Date
    Apr 2003
    Posts
    2,662
    [edit] Actually, after reading the post again, the code you really want to test is this:
    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;
    }
    You'll see that the eof flag is still enough to tell the while loop to kick out.
    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:
    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;
    }
    sample output:
    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
    output using your code:
    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
    Both of the ouputs show that the while condition:

    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.

  10. #25
    Registered User
    Join Date
    Jan 2005
    Posts
    7,318
    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.

  11. #26
    Registered User
    Join Date
    Apr 2003
    Posts
    2,662
    The getline method sets the eof bit after it fails to read due to reaching the end of the file.
    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.

  12. #27
    Registered User
    Join Date
    Jan 2005
    Posts
    7,318
    Quote Originally Posted by 7stud
    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.
    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.

    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.

  13. #28
    Registered User
    Join Date
    Apr 2003
    Posts
    2,662
    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.
    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.
    Last edited by 7stud; 04-28-2005 at 05:50 PM.

  14. #29
    Registered User
    Join Date
    Jan 2005
    Posts
    7,318
    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.

  15. #30
    Registered User
    Join Date
    Apr 2003
    Posts
    2,662
    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.
    Ok.

Page 2 of 3 FirstFirst 123 LastLast
Popular pages Recent additions subscribe to a feed

Similar Threads

  1. For loop question
    By JuzMe in forum C++ Programming
    Replies: 11
    Last Post: 04-20-2009, 08:39 AM
  2. Loop question
    By kwood965 in forum C Programming
    Replies: 6
    Last Post: 10-29-2008, 11:12 PM
  3. simple for loop function question
    By felicityxiv in forum C Programming
    Replies: 7
    Last Post: 05-06-2006, 11:43 PM
  4. Please don't laugh...SIMPLE loop question!
    By the_lumin8or in forum C++ Programming
    Replies: 5
    Last Post: 03-31-2006, 12:08 PM
  5. while loop question
    By rayrayj52 in forum C++ Programming
    Replies: 2
    Last Post: 10-19-2004, 05:13 PM

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21