сбой std ::cin, приводящий к зацикленному оператору if в цикле while

#c #error-handling #cin #numeric-limits

#c #обработка ошибок #cin #числовые ограничения

Вопрос:

Итак, я полагаю, что я помещу это здесь, поскольку мне пришлось просмотреть множество документов и форумов, чтобы найти окончательный ответ. Я пытался получить входные данные от пользователя и проверить, является ли ввод целым числом, используемым isdigit() в операторе if. Если оператор if не выполняется, программа выдает сообщение об ошибке. Хотя, когда вводился нецифровый символ, программа бесконечно просматривала сообщение об ошибке. Вот этот код:

 int guess = -1;
while (game.getCurQuestion() <= 4) {
    std::cout << "Guess: " << game.getCurQuestion()   1 << std::endl;
    std::cin >> guess;
    if(isdigit(guess))
    {
        game.guess(guess);
    else
    {
        std::cout << "Errorn"; //this would be looped endlessly
    }
    
}
std::cout << "You got " << game.getCorrect() << " correct"  << std::endl;
return 0;
 

}

ПРИМЕЧАНИЕ: Решаемая, опубликованная только для включения моего решения. Не стесняйтесь исправлять, если я что-то неправильно указал.

Ответ №1:

Опубликованный способ иногда завершается ошибкой и преобразует удвоения в целые числа, если вводятся какие-либо удвоения.

Используйте что-то вроде следующего

 int getIntInput() {
    try {
        std::string input;
        std::cout << "nPlease Enter a valid Integer:t";
        std::cin >> input;
        size_t takenChars;
        int num = std::stoi(input, amp;takenChars);
        if (takenChars == input.size()) return num;
    } catch (...) {}
    return getIntInput();
}
 

Комментарии:

1. Мне нравится этот, поскольку он также позволяет избежать цикла cin при вводе символа. Это определенно выглядит намного лучше, чем странный оператор cin.ignore . Мой единственный вопрос: я слышал, что использование catch(…) было плохой практикой, считается ли это приемлемым в данном случае использования?

2. @CrypticEthosIt здесь неплохо, потому что я знаю причину исключения и пытаюсь получить новый ввод, который позволяет избежать выдачи того же исключения.

3. Ах, я вижу, что изначально в моем коде был смысл, у меня действительно был try catch, но я убрал его из-за (…), еще раз спасибо!

Ответ №2:

Проблема: программа сохранила нецелочисленное значение, сохраненное в буфере cin. Это приводит к тому, что программа никогда не выводит сообщение об ошибке.

Решение:

  1. Используется std::cin.fail() для проверки соответствия входных данных переменному типу данных. Т.Е. int ожидаемый ввод, но пользователь ввел a char . В этом случае std::cin.fail() это было бы правдой.
  2. В случае std::cin.fail() , используйте std::cin.clear() и std::cin.ignore(std::numeric_limits<int>::max(), 'n') std::cin.clear() сбросит флаг ошибки. std::cin.ignore(std::numeric_limits<int>::max(), 'n') Будет игнорироваться любой другой ввод, который не является целым числом, и перейдет к новой строке. Эффективное продвижение программы.

Решение, реализованное в моем коде, выглядит следующим образом:

 int guess = -1;
while (game.getCurQuestion() <= 4) {
    std::cout << "Guess: " << game.getCurQuestion()   1 << std::endl;
    std::cin >> guess;
    if (std::cin.fail())
    {
        std::cout << "Please enter a valid numbern";
        std::cin.clear();
        std::cin.ignore(std::numeric_limits<int>::max(), 'n');
    }
    game.guess(guess);
}
 

Надеюсь, это поможет и избавит некоторых людей от утомительных исследований из-за того, что они никогда не учатся std::cin обработке ошибок! Примечание: я знаю, что моя реализация пропускает текущий ход, назовите это наказанием 😉

Комментарии:

1. Примечание: asmmo дал очень хороший ответ выше, который сводит на нет необходимость в std ::cin.clear() и std ::cin.ignore() , что также предотвращает ввод двойных значений в этом варианте использования