c ++ проверяет число и останавливает бесконечный цикл - PullRequest
2 голосов
/ 27 декабря 2010

Я делаю консольное приложение, я передаю целое число в приложение, и оно работает нормально, но если я передаю письмо, оно сходит с ума,

int opt=0;
std::cout<<"Pick lang:"<<'\n';
std::cout<<"1.[es-ES]:"<<'\n';
std::cout<<"2.[en-US]:"<<'\n';
std::cin >> opt;

while(opt<1 || opt>2)
{
    std::cout<<"\nERROR!"<<'\n';
    std::cout<<"Pick lang again:"<<'\n';
    std::cout<<"1.[es-ES]:"<<'\n';
    std::cout<<"2.[en-US]:"<<'\n';
    std::cin >> opt;
}

Я пытался использовать isdigit (), но получаю тот же результат. Спасибо

Ответы [ 4 ]

7 голосов
/ 27 декабря 2010

После выполнения извлечения cin >> вы хотите проверить, исправен ли поток cin или нет.Если вы ожидаете, что cin извлечет число, но вместо этого он получит что-то другое, например.как буква, тогда поток будет установлен в плохое состояние, и поэтому вы видите, что он «сходит с ума».

Что вам нужно сделать, это после ввода, проверить, все ли в порядке cin.Если он в плохом состоянии, вам нужно очистить его флаги, а затем удалить все ненужные данные в потоке.Если вы этого не сделаете, то последующее использование cin просто не сможет функционировать.

Взяв, например, ваш фрагмент кода, вы можете изменить его на что-то вроде этого:

int opt = 0;
bool inputGood = false;

do
{
    std::cout << "Pick lang again:" << '\n';
    std::cout << "1.[es-ES]:" << '\n';
    std::cout << "2.[en-US]:" << '\n';
    inputGood = std::cin >> opt;
    if(!inputGood)
    {  
      std::cout << "\nERROR! Invalid choice." << '\n';
      cin.clear();
      while( cin.get() != '\n' );
    }
}while(!inputGood || opt < 1 || opt > 2);

Редактировать: К сожалению незначительные ошибки в обработке ошибок CIN.Исправлено и должно работать сейчас.:)

2 голосов
/ 27 декабря 2010

Проблема в том, что при вызове std::cin >> opt не удается проанализировать символ и немедленно возвращается (без использования буфера), затем он находит то же содержимое и завершается ошибкой ....

Вы должны проверить результат операции и отреагировать на него. Одной из возможностей может быть проверка бита сбоя (std::cin.fail()) и сбой всей операции или использование частей буфера (может быть, одного символа, а может и больше, в зависимости от того, как приложение будет работать).

Простейшей вещью, вероятно, будет не чтение числа, а символ, а затем сравнение с ожидаемым символом:

char opt = 0;
do {
   // prompt user for input
   if (! (std::cin >> opt) ) {
      // io error, report and bail out
      break;
   }
} while ( opt != '0' && opt != '1' );
1 голос
/ 27 декабря 2010

Чтение в числах напрямую проблематичный

Если std :: cin представлен входными данными не может обработать, std :: cin переходит в состояние «сбой» Вход не может процесс остается во входном потоке.

Все вводимые данные будут игнорироваться std :: cin пока состояние "сбой" не будет очищено: std :: cin.clear ()

Подпрограмма, которая читает номер напрямую должен:

  1. Читать в номер

  2. Убедитесь, что вход поток все еще действителен

  3. Если на входе поток не хорош (! std :: cin)

    1. Вызов std :: cin.clear () чтобы принять поток из состояния "сбой".
    2. Удалить из поток вход, который вызвал проблема: std :: cin.ignore (...)
    3. Получить введите еще раз, если необходимо, или в противном случае обработайте ошибку

подробнее здесь: http://www.augustcouncil.com/~tgibson/tutorial/iotips.html

1 голос
/ 27 декабря 2010

Когда вы вставляете букву, это происходит:

  1. operator>> извлекает символы из потока и пытается преобразовать их в число;
  2. при преобразовании происходит сбой, поэтомуустанавливает состояние потока на ios::failbit и возвращает;opt, вероятно, не тронут (стандарт делегирует этот материал в библиотеку локалей, которая является зоной C ++, которую я никогда не понимал - для достаточно смелых, это в §22.2.2.1.2);так как он вернулся и (вероятно) opt остался как есть, цикл продолжается;
  3. когда выполнение возвращается к std::cin >> opt;, operator>> видит, что состояние все еще ios::failbit, поэтомудаже не пытается извлечь что-либо;
  4. Перейти к 3.

Чтобы исправить проблему, вы должны очистить состояние ошибки и удалить «неправильные» символы из буфера ввода.Поскольку вы, вероятно, не хотите добавлять весь этот код к каждому cin>>, полезно создать функцию для решения этой распространенной проблемы;лично я создал этот маленький заголовок (AcquireInput.hpp), который оказался полезным много раз:

#ifndef ACQUIREINPUT_HPP_INCLUDED
#define ACQUIREINPUT_HPP_INCLUDED

#include <iosfwd>
#include <limits>
#include <string>

    template<typename InType> void AcquireInput(std::ostream & Os, std::istream & Is, const std::string & Prompt, const std::string & FailString, InType & Result)
    {
        do
        {
            Os<<Prompt.c_str();
            if(Is.fail())
            {
                Is.clear();
                Is.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
            }
            Is>>Result;
            if(Is.fail())
                Os<<FailString.c_str();
        } while(Is.fail());
    }

    template<typename InType> InType AcquireInput(std::ostream & Os, std::istream & Is, const std::string & Prompt, const std::string & FailString)
    {
        InType temp;
        AcquireInput(Os,Is,Prompt,FailString,temp);
        return temp;
    }

    /* Usage example: 

        //1st overload
        int AnInteger;
        AcquireInput(cout,cin,"Please insert an integer: ","Invalid value.\n",AnInteger);

        //2nd overload (more convenient, in this case)
        int AnInteger=AcquireInput(cout,cin, "Please insert an integer: ","Invalid value.\n");
    */

#endif
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...