开发者

While loop with try catch fails at bad cin input

I can't seem to figure out why this falls into a loop after getting non-int input. I've tried cin.flush开发者_JAVA百科(), which doesn't seem to exist, cin.clear(), which seems like it should work, even cin.sync() after reading someone else post about it working, but didn't seem to make much sense. Also tried cin.bad().

Thank you very much for any help

Please enter the first number: f Sorry, I don't think that's a number?

Please enter the first number: Sorry, I don't think that's a number?

Please enter the first number: Sorry, I don't think that's a number?

Please enter the first number: Sorry, I don't think that's a number?

Please enter the first number: Sorry, I don't think that's a number?Sorry, you d on't get any more tries. Press any key to continue . . .

#include <iostream>
using namespace std;

int main(){
    int entry;
    int attempts = 1;
    int result;
    while(attempts <= 5) {
        try {
            cout << "\n\nPlease enter the first number: ";
            cin >> entry;
            if (cin.fail())
                throw "Sorry, I don't think that's a number?";
            if (entry < 0)
                throw "Sorry, no negative numbers. Try something else? ";
            cout << "\nNow the second number: ";
            cin >> entry;
            cin.clear();
            cin.get();
        }
        catch (char* error) {
            cout << error;
            attempts++;
        }
    }
    if (attempts > 5)
        cout << "Sorry, you don\'t get any more tries.\n";
    system("pause");
    return 0;
}


You should think carefully what you want to do if user gives invalid input in this case. Usually in these cases the best solution is to read one line from the input and throw it away.

Try putting cin.clear() and std::cin.ignore(std::numeric_limits<streamsize>::max(),'\n'); in your catch clause. cin.clear() clears the failure state in cin, and cin.ignore() throws away rest of the line waiting in the input buffer.

(And yes, you probably should rethink your use of exceptions).


The most straight-forward (but not usually the easiest nor the fastest) way of dealing with validation of line-based input is to always read it line at a time. This way no extra whitespace (such as linefeed characters) is left unread in the buffer in any case, and discarding erroneous input is also quite automatic.

// Infinite loop for retrying until successful
while (true) {
    // Ask the user something
    std::cout << prompt;
    // Read the answer (one full line)
    std::string line;
    if (!std::getline(std::cin, line))
      throw std::runtime_error("End of input while expecting a value");
    // Put the line read into iss for further parsing
    std::istringstream iss(line);
    int val;
    // Read val from iss and verify that reading was successful and
    // that all input was consumed
    if (iss >> val && iss.get() == EOF) return val;
    std::cout << "Invalid input, try again!\n";
}

It is fun to make a BASIC style input function out of this:

template <typename Val> void input(std::string const& prompt, Val& val) {
    // (the above code goes here, slightly adjusted)
}

int main() {
    int w;
    double l;
    input("Enter weight in kg: ", w);
    input("Enter length in m: ", l);
    std::cout << "BMI: " << w / (l * l) << std::endl;
}

Notes for the pedantics who were going to downvote me:

  • function input should be specialized for std::string
  • exceptions thrown by the input function should be caught in main


My Problem was to block char input to a cin >> number

This error caused an 'infinite' loop showing my prompt cout << prompt with no way of exit but kill the process ...

The following shows what worked for me!

========================================

double fi_trap_d()    // function to return a valid range double catching errors  
{  
  double fi_game_sec;  
//-------------------------------------------  
   do  
   {  
    fi_game_sec = -1;  
    cout << fi_game_sec_c;  

        //------------------------------  
    cin.ignore();  // (1)
        //------------------------------  

    try  
    {  cin >> fi_game_sec;  cin.clear(); }  // (2)
        catch (...)  //out_of_range)  
      {  
        fi_game_sec = -1;  
        cout << " Dis am an error!\n";  
                     // just loop back as we asked for a number  
      }  
    } while (fi_game_sec < 1);  
//-------------------------------------------  
  return fi_game_sec;  
}  

========================================

Despite trying the " Dis am an error! " has NEVER shown up.

The key was (1) & (2) !


Exceptions should be used to handle exceptional, unexpected situations. Incorrect input from a user is neither unexpected nor exceptional -- it's more or less the norm. Personally, I tend to just ignore most bad input completely (when it can't be prevented). When (and only when) they enter something unusable repeatedly is it even worth pointing it out to them. As such, I'd tend to write the code something like:

char ch;
int attempts = 0;

std::cout << "Please enter the first number: ";
do { 
    cin >> ch;
    attempts++;
    if (attempts > 5)
        std::cerr << "The only allowable inputs are '0' through '9'\n";            
} while (cin.good() && !isdigit(ch));
int first_number = ch - '0';

This reads the input as a character, so it's always removed from the input stream. Then it attempts to validate the input, and if it fails, attempts to read again. Of course, you might want/need to get a little more elaborate, such as reading an entire line, attempting to convert it to a number, and reading another line if that fails.


Why are you doing this with exceptions? You're not going to kill the program on input, so you shouldn't throw an exception.

Just print out your error message and attempt to read in again.


It looks like you would be better off with iostream's native exceptions. Enable with

cin.exceptions( ios::failbit );

try {
   …
} catch( ios_base::failure & ) {
  cin.clear();
  …
}

Never, ever throw an an object not derived from std::exception, and especially not a native type like char*.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜