views:

91

answers:

4
void get_english_input() {
    string input = " ";
    stringstream my_string(input);
    int ft;
    double in;

    while(true) {    
        cout << "Enter an integer value of feet." << endl;
        getline(cin, input);
        my_string << input;
        if(my_string >> ft)
            break;
        cout << "Invalid input! Please try again." << endl;
    }
    cout << "you entered " << ft << " as the int value for feet." << endl;
    /*while(true) {
        cout << "Enter a double value of inches." << endl;
        getline(cin, input);
        my_string << input;
            break;
    cout << "Invalid input! Please try again." << endl;
    }
    cout << "we are done entering english input" << endl;
    cout << "feet = " << ft << endl;
    cout << "inches = " << in << endl;*/
}

This code is supposed to test if the input is an integer by trying to put the contents of my_string into ft. If I enter a letter instead of an integer I get the error message "Invalid input! Please try again," which is what is supposed to happen. The problem is, after I get that message once, I will get it for every input after that, even if the next input is valid.


Someone suggested that I should use std::cin.clear(); to clear the error-flags. I tried putting it before the getline() and it did not change the problem. Was I using this incorrectly?

+3  A: 

You could reset the error state of my_string:

my_string.clear();
my_string.ignore( /* big number of choice */ );

But I think it would be easier here just to reinitialize it every time:

while(true) {    
    cout << "Enter an integer value of feet." << endl;
    getline(cin, input);
    stringstream my_string(input);
Potatoswatter
+1 -- in this respect the advice to reset `cin` wasn't too far off the mark, they just used the wrong stream (because `cin` isn't doing the conversion)
Billy ONeal
Thanks a lot! It seems like that has fixed the problem.
Grady Knotts
it's not just the error state, each input is appended onto the preivous. the line `my_string << input` appends text to the buffer.
flies
@flies: Right, I assumed that the final contents of `my_string` are thrown away (it should actually be declared `istringstream`), so I changed the code in that respect. But, if that were a problem, the change would cause a compile error.
Potatoswatter
+1  A: 

Check out lexical_cast from Boost ...

maxschlepzig
A: 

The brute-force solution is to dump your input into a std::string, then loop over the string and check if each character is between 0 and 9.

It's not the most elegant approach. But it's simple and stupid. :-)

bool isnum(char c)
{
   if(! ( c <= '9' && c >= '0'))
   {  
       return false;
   }
   return true;
}


bool has_int(std::string &s)
{
   for( int i = 0; i < s.length(); i++)
   {
      if( ! isnum(s[i])
      {
         return false;
      }
   }

   return true;
}
Paul Nathan
A: 

I think

mystring >> ft

will always evaluate to be true (maybe not if mystring was empty). The operation will still work whether or not mystring actually contains a number or not.

One idea is to

 size_t found=input.find_first_not_of("0123456789 ");
  if (found!=string::npos)
  {
   cout <<   "Invalid input! Please try again."
  }

Adapted from here.

Chance
When I test this function, if I input a character such as 'c' I always get the error message (that was the original problem actually; the error message would not go away). However, if I enter a number, it will accept it and print the output.
Grady Knotts
Hmm, perhaps the problem is that mystring needs to be cleared. After all, if you never do a successful extraction to the int value, the 'c' will always be at the beginning of mystring. All you are doing in successive iterations is simply appending things to the end of mystring. What if you try clearing mystring if unsuccessful? Perhaps have a string garbage and extract mystring to that in case it doesn't extract to an int.
Chance