Мой cin игнорируется внутри цикла while

Я пытаюсь закодировать простой вопрос и средство проверки чисел в свою первую программу на C++. Проблема в том, что когда я набираю строку типа один, два или три, программа превращается в бесконечный цикл и игнорирует функцию cin для переназначения жизней на число.

cout << "How many lives would you like 1 (hard), 2 (medium), or 3 (easy)?" << endl;
cin >> lives;


while(lives != 1 && lives != 2 && lives != 3 && !isdigit(lives))
{
    cout << "You need to input a number, not words." << endl;
    cout << "How many lives would you like 1 (hard), 2 (medium), or 3 (easy)?" << endl;
    cin >> lives;
}

Вот мой текущий код с вашими предложениями:

    cout << "How many lives would you like 1 (hard), 2 (medium), or 3 (easy)?" << endl;
std::cin.ignore();
std::cin.clear();
if (std::cin >> lives)
{


    while(lives != 1 && lives != 2 && lives != 3)
    {
        cout << "You need to input a number, not words." << endl;
        cout << "How many lives would you like 1 (hard), 2 (medium), or 3 (easy)?" << endl;
        cin >> lives;
    }

}

person Logan Saso    schedule 03.08.2013    source источник
comment
Какой тип lives?   -  person Borgleader    schedule 03.08.2013
comment
Я попытался преобразовать его в строку, и проблема не устранена.   -  person Logan Saso    schedule 03.08.2013
comment
тип жизни, вероятно, целочисленный или что-то в этом роде. Используйте cin.get() вместо cin, потому что ваше возвращаемое значение (введите нажатие) остается в стандартном вводе...   -  person DaMachk    schedule 03.08.2013
comment
Итак, при использовании cin.get это не повторяется бесконечно. Тем не менее, он выдает мне сообщение об ошибке в цикле примерно 5 или 6 раз и отказывается принимать даже нормальное число, когда он останавливается.   -  person Logan Saso    schedule 03.08.2013
comment
Почему бы вам не использовать пространство имен std?   -  person Andrei Diaconu    schedule 04.08.2013


Ответы (2)


#include <iostream>
#include <limits>

int main()
{
    int lives = 0;
    std::cout << "How many lives would you like 1 (hard), 2 (medium), or 3 (easy)?" << std::endl;


    while(!(std::cin >> lives) || lives < 1 || lives > 3)
    {
        std::cout << "You need to input a number, not words." << std::endl;
        std::cout << "How many lives would you like 1 (hard), 2 (medium), or 3 (easy)?" << std::endl;
        std::cin.clear();
        std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
    }

    return 0;
}

Хорошо. std::cin.clear(); заботится о сбросе битов отказа. std::cin.ignore удаляет любой неверный ввод, оставшийся в потоке. И я скорректировал условие остановки. (isDigit было лишней проверкой, если жизни от 1 до 3, то это явно цифра).

person Borgleader    schedule 03.08.2013
comment
Борг, это говорит о том, что max() ожидает идентификатор и не будет компилироваться - person Logan Saso; 04.08.2013
comment
@LoganSaso Я не знаю, что вы используете, но для меня это компилируется в Mingw/QtCreator, компилируется на ideone и VS2012. - person Borgleader; 04.08.2013
comment
Я использую Visual Studio 2012, это придирчивая вещь. - person Logan Saso; 04.08.2013
comment
Вероятно, тянет #define вместо min и max. Попробуйте добавить #undef max перед включением ограничений и после включения заголовков, специфичных для Windows. - person Captain Obvlious; 04.08.2013
comment
использование пространства имен std; У меня есть iostream и лимиты - person Logan Saso; 04.08.2013
comment
Подождите, я только что понял, я не менял странный _tmain и прочее на просто main - person Logan Saso; 04.08.2013
comment
Я не знаю, что конкретно делает #undef, но работает отлично, так что... Хорошая работа - person Logan Saso; 04.08.2013
comment
@LoganSaso max - это макрос, что-то вроде #define max(x,y) x > y? x: y;, и он конфликтует с numeric_limits, undef удаляет его. Также вы можете принять ответ, если он работает;) - person Borgleader; 04.08.2013
comment
Это работает, но я не знаю, как принять ответ. Только что сделал свой профиль стека сегодня. - person Logan Saso; 04.08.2013

Когда std::istream не может прочитать значение, он переходит в режим сбоя, т. е. устанавливается std::failbit, и при проверке поток дает false. Вы всегда хотите проверить, была ли операция чтения успешной:

if (std::cin >> value) {
    ...
}

Чтобы восстановить поток в хорошем состоянии, вы должны использовать std::cin.clear() и вам, вероятно, придется игнорировать плохие символы, например, используя std::cin.ignore().

person Dietmar Kühl    schedule 03.08.2013
comment
Диета, у него та же проблема: добавить две строки перед циклом while. Какой бы ценности пчелы в вашем примере не было. Жизни...? - person Logan Saso; 03.08.2013
comment
value — это то, что вы хотите прочитать, например, int. Кстати, ваш тест для isdigit() не будет работать, если lives является int: эта функция работает с char. Я почти уверен, что проблема соответствует описанию, и вы можете распечатать то, что было получено... - person Dietmar Kühl; 04.08.2013
comment
Хорошо, при использовании оператора if он вообще никогда не переходит в цикл while. Даже если я наберу три или три, это просто скажет, что мои жизни сохранены, что позже не сработает с моими жизнями--. - person Logan Saso; 04.08.2013
comment
Вы пытаетесь ввести three, чтобы его читали как int? Это не удастся! Попробуйте использовать 3. Если вы хотите поддерживать ввод one, two и three, вам нужно самостоятельно реализовать синтаксический анализ строк. - person Dietmar Kühl; 04.08.2013
comment
Нет, это было не то, чем я занимался. - person Logan Saso; 04.08.2013