Thread: Failbit trouble

  1. #1
    Registered User OldSchool's Avatar
    Join Date
    Apr 2006
    Location
    Virginia
    Posts
    18

    Failbit trouble

    Hi all... I am a new poster to the site but have lurked in here several times to sort out some sticky issues in the past... You guys & gals are great and I hope to be able to get to your level of programming knowledge at some point!

    I am currently taking a C++ OOP course and have run across an interesting problem. Unfortunately, I am an online student and the instructor is generally not much help.

    I was having fits with the failbit situation to check for valid inputs. I have already found a thread that provided some excellent guidance to get me in the ballpark here . My thanks to those posters for the assistance.

    I have written some code based on several different examples in our Deitel text using stream extraction and insertion and have run across an interesting problem...

    Code:
    #include <iostream>
    
    using std::cin;
    using std::cout;
    using std::endl;
    using std::istream;
    using std::ostream;
    
    #include <limits>
    
    // Class Point
    class Point {
    	friend ostream &operator<<( ostream&, const Point & );
    	friend istream &operator>>( istream&, Point & );
    	
    private:
    	int xCoordinate;  // X coordinate
    	int yCoordinate;  // Y coordinate
    
    };  //end class Point
    
    // overloaded stream-extraction operator 
    istream &operator>>( istream &input, Point &num )
    {
    	input >> num.xCoordinate;
    	input >> num.yCoordinate;
    	
        return input;
    
    } // end function operator>> 
    
    // overloaded stream-insertion operator;
    ostream &operator<<( ostream &output, const Point &num )
    {
    	if (!(cin.fail()))
    		output << "The coordinates you entered were: " << 
    		'[' << num.xCoordinate << ", " << num.yCoordinate << ']';
    	else {
    		cin.clear();
    		cin.ignore(5000,'\n');
    		output << "Invalid data entered." << endl;
    	}
    
        return output;
    
    } // end function operator<< 
    
    // main point test program
    int main()
    {
    	// Create Point objects for program
    	Point point1;
    	Point point2;
    	Point point3;
    
    	cout << "Please enter 2 integers and press Enter:\n";
    	cin >> point1;
    
    	cout << point1 << endl;
    
    	cout << "\n\nPlease enter a character followed by an integer and press Enter:\n";
    	cin >> point2;
    
    	cout << point2 << endl;
    	
    	cout << "\n\nPlease enter an integer followed by a character and press Enter:\n";
    	cin >> point3;
    
    	cout << point3 << endl;
    
    
    	return 0;
    
    }  // end main
    The program does what I need it to with one exception... The first input sets the failbit if either a character or non-int is entered (perfect!). The second input, however, only sets the failbit if a character is entered... If you enter a decimal as the second (y) value, the failbit does not set...

    I added a "cin.fail()" on the output side to confirm this. Why would failbit set for a character and not a non-int on the second value only? I have looked everywhere on the Web I can think of and could not find anything that explained it.

    Another interesting side note is that I noticed that when you enter an invalid value of any kind for the first value, the program goes right to my "invalid" message without waiting for my second input. As my code reads, I would think that the program would wait for two inputs before it performs the ostream failbit check I have added. This problem is not a dealbreaker for my assignment since it does stop the invalid input, but I was curious because I really want to learn and understand the concepts for my benefit.

    Any assistance provided would be greatly appreciated.

  2. #2
    carry on JaWiB's Avatar
    Join Date
    Feb 2003
    Location
    Seattle, WA
    Posts
    1,972
    If you input, for example, 12.34, cin will put 12 into your integer, but leaves the rest of the stream buffer intact. One solution is to simply allow a user to enter a decimal number, but truncate it (in which case you should use ignore to remove everything left in the stream after each input operation). Otherwise, I think you'll have to read the input into a string, then check to make sure there is no decimal present. For example:
    Code:
    #include <iostream>
    #include <sstream>
    
    int main()
    {
      int num1,num2;
      std::string foo;
      getline(std::cin,foo);
      if (foo.find('.')!=std::string::npos)
      {
        std::cout<<"Invalid Input!";
        return 1;
      }
      
      std::istringstream istrm(foo);
      
      if(!(istrm>>num1))
      {
        std::cout<<"Invalid Input!";
        return 1;
      }
      
      if(!(istrm>>num2))
      {
        std::cout<<"Invalid Input!";
        return 1;
      }
      std::cout<<num1<<' '<<num2<<std::endl;
    }
    Also, consider what will happen for you code, as you have it now, if the user enters three numbers instead of two for the first input. (The resulting problem is similar to your decimal problem)
    "Think not but that I know these things; or think
    I know them not: not therefore am I short
    Of knowing what I ought."
    -John Milton, Paradise Regained (1671)

    "Work hard and it might happen."
    -XSquared

  3. #3
    Registered User OldSchool's Avatar
    Join Date
    Apr 2006
    Location
    Virginia
    Posts
    18
    I appreciate the assist JaWiB...

    Unfortunately, my assignment specified integer values for the variables so I don't think I could change them to double and still be in my parameters...

    The string version looks intriguing... I might have to give that a go for my own benefit tomorrow... I have to send in the assignment tonight... Nothing like waiting until the last minute, right? LOL!

  4. #4
    Registered User
    Join Date
    Jan 2005
    Posts
    7,366
    You don't have to read it in as a string. This code reads in an integer and fails on 12.34 or 12abc or any non-integer:
    Code:
    int val;
    while (!(std::cin >> val) || std::cin.get() != '\n')
    {
      std::cin.clear();
      std::cin.ignore(5000,'\n');
      std::cout << "Invalid data entered." << std::endl;
    }
    You can adapt that to use your input parameter instead of cin. One thing to be aware of, though, is that if the user types in two coordinates separated by a space, that will fail. You can do several things to allow it, like add the read for the second coordinate before the check against cin.get().

    BTW, You do input error checking in your output operator, which is a bad idea. Not only are you checking cin for fail() instead of the input paramter (what if the user input from a file?), but it just doesn't make sense to do input error checking in the output code.

  5. #5
    Registered User OldSchool's Avatar
    Join Date
    Apr 2006
    Location
    Virginia
    Posts
    18
    Thanks Daved... I see your point about checking for errors on the input side.

    It appears that your code would check the input against the 'val' variable. Since this would be for a coordinate plane and any integer is allowable, what would be a good value for 'val?' I thought of trying a validation scheme like this but I want the code to allow any int while disallowing any floating-point value so I was at a loss on the value range to use.

    The chapter we read concentrated on using the failbit to detect invalid input and it seemed to work (for the most part)... I am still baffled as to why any invalid input for the first entry caused an immediate exit (even though I moved the check to the ostream side). To me, it looks like the validation is being done prematurely (i.e. - the code runs the ostream validation even before it has a complete input and gets to an ostream entry).

    I also still cannot see why the second value will set failbit for a char entry but does not set failbit for a floating-point entry. Will moving the validation to the input side accomplish that?

    I really want to understand this because I have done fairly well so far with the concepts but this one really seemed to kick my rear a bit!

    Thanks again...

  6. #6
    Registered User
    Join Date
    Jan 2005
    Posts
    7,366
    >> It appears that your code would check the input against the 'val' variable.
    No, it doesn't. It checks the return value of operator>>, which is essentially the value of the failbit. If you want, you can explicitly check the failbit and reach the exact same effect, although looping is more difficult:
    Code:
    int val;
    std::cin >> val;
    if (std::cin.fail() || std::cin.get() != '\n')
    {
      std::cin.clear();
      std::cin.ignore(5000,'\n');
      std::cout << "Invalid data entered." << std::endl;
    }
    The reason the failbit isn't set when you attempt to read an integer from the input 12.34 is that an integer is actually read in. cin >> reads until it can no longer read in a valid value for the type it is reading. So it reads the '1', then the '2', then the '.' and stops because the '.' would make an invalid integer. It succeeds because it has read in 12, and the rest of the input is left in the input stream. The next time you attempt to read from cin, the first thing that will be there is the ".34" leftover from the first input.

    That is why I added the check for '\n'. When the user types in the console, they have to hit enter to send the input to the program. Hitting enter inserts a newline ('\n') into the input. If they type in an integer and press enter, the next character after the integer will be '\n'. If they type in an integer and then some other garbage (like "12.34\n" or "12abc\n" or "12 is a number\n"), then the next character after the integer will not be '\n', and so my code will identify it as invalid input. cin doesn't flag it as invalid because it many cases it is ok for there to be extra characters after the value that is read in.

  7. #7
    Registered User OldSchool's Avatar
    Join Date
    Apr 2006
    Location
    Virginia
    Posts
    18
    EXCELLENT! The light bulb just went on... I see it now!

    I misunderstood the 'val' thing entirely!

    When my code worked with an invalid 1st input, it was because it accepted the integer part. The second cin in my code was actually setting the failbit because the decimal part was read in next (which is why it didn't wait for a second manual input!). A decimal for the second value never set failbit because it never read in the decimal part... Aaaah!

    Really great explanation, Daved. I appreciate your patience with me. The fact that it failed only with a char input for the 2nd value was really weirding me out!

    You are the man! Thanks again...

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Trouble with assignment in C
    By mohanlon in forum C Programming
    Replies: 17
    Last Post: 06-23-2009, 10:44 AM
  2. Is it so trouble?
    By Yumin in forum Tech Board
    Replies: 4
    Last Post: 01-30-2006, 04:10 PM
  3. trouble scanning in... and link listing
    By panfilero in forum C Programming
    Replies: 14
    Last Post: 11-21-2005, 12:58 PM
  4. Usage of badbit and failbit
    By golfinguy4 in forum C++ Programming
    Replies: 5
    Last Post: 07-01-2003, 09:43 AM
  5. C++ program trouble
    By senrab in forum C++ Programming
    Replies: 7
    Last Post: 04-29-2003, 11:55 PM