В то время как цикл с try catch завершается неудачно при неправильном вводе cin - PullRequest
3 голосов
/ 19 февраля 2010

Я не могу понять, почему это попадает в цикл после получения нецелого ввода. Я пробовал cin.flush (), который, кажется, не существует, cin.clear (), который, похоже, должен работать, даже cin.sync () после прочтения поста другого человека о его работе, но не смог кажется, имеет большой смысл. Также попробовал cin.bad ().

Большое спасибо за любую помощь

Пожалуйста, введите первое число: f Извините, я не думаю, что это число?

Пожалуйста, введите первый номер: Извините, Я не думаю, что это число?

Пожалуйста, введите первый номер: Извините, Я не думаю, что это число?

Пожалуйста, введите первый номер: Извините, Я не думаю, что это число?

Пожалуйста, введите первый номер: Извините, Я не думаю, что это число? Извините, у тебя больше не будет попыток. Нажмите любой ключ, чтобы продолжить. , .

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

Ответы [ 6 ]

9 голосов
/ 19 февраля 2010

Тщательно продумайте, что вы хотите сделать, если в этом случае пользователь вводит неверные данные. Обычно в этих случаях лучшее решение состоит в том, чтобы прочитать одну строку из ввода и выбросить ее.

Попробуйте указать cin.clear() и std::cin.ignore(std::numeric_limits<streamsize>::max(),'\n'); в предложении catch. cin.clear() очищает состояние ошибки в cin, а cin.ignore() выбрасывает остаток строки, ожидающий во входном буфере.

(И да, вам, вероятно, следует переосмыслить использование исключений).

3 голосов
/ 19 февраля 2010

Самый простой (но обычно не самый простой и не самый быстрый) способ справиться с проверкой ввода на основе строки - это всегда читать ее по очереди. Таким образом, ни один лишний пробел (например, символы перевода строки) не остается непрочитанным в буфере в любом случае, и отбрасывание ошибочного ввода также происходит полностью автоматически.

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

Интересно сделать из этого функцию ввода в базовом стиле:

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

Заметки для педантиков, которые собирались понизить меня:

  • ввод функции должен быть специализирован для std :: string
  • исключения, выдаваемые функцией ввода, должны быть перехвачены в main
2 голосов
/ 02 мая 2011

Моя проблема заключалась в том, чтобы заблокировать ввод символов в коде cin >> number

Эта ошибка вызвала «бесконечный» цикл, показывающий мой запрос prompt cout << без выхода, но завершающий процесс ... </p>

Ниже показано, что сработало для меня!

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

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

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

Несмотря на попытку «Dis am error!» НИКОГДА не показывалось.

Ключ был (1) & (2)!

0 голосов
/ 19 февраля 2010

Исключения следует использовать для обработки исключительных, неожиданных ситуаций. Неправильный ввод от пользователя не является ни неожиданным, ни исключительным - это более или менее норма. Лично я склонен полностью игнорировать самые плохие входные данные (когда это невозможно предотвратить). Когда (и только когда) они постоянно вводят что-то непригодное, стоит ли им на это указывать. Поэтому я склонен писать код примерно так:

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

Это считывает ввод как символ, поэтому он всегда удаляется из потока ввода. Затем он пытается проверить входные данные, и, если это не удается, пытается прочитать снова. Конечно, вам может понадобиться / нужно немного сложнее, например, прочитать целую строку, попытаться преобразовать ее в число и прочитать другую строку в случае неудачи.

0 голосов
/ 19 февраля 2010

Похоже, вам будет лучше с нативными исключениями iostream. Включить с

cin.exceptions( ios::failbit );

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

Никогда, никогда throw объект, не производный от std::exception, и особенно не нативный тип, такой как char*.

0 голосов
/ 19 февраля 2010

Почему вы делаете это с исключениями? Вы не собираетесь убивать программу при вводе, поэтому не следует выдавать исключение.

Просто распечатайте сообщение об ошибке и попробуйте снова прочитать.

...