Как предотвратить повторный цикл ввода, когда я запрашиваю число, а пользователь вводит не число? - PullRequest
3 голосов
/ 01 февраля 2011

Мне нужно знать, как сделать так, чтобы мой оператор cin не выдавал себя, если вы вводите неправильный тип.Код здесь:

int mathOperator()
{
  using namespace std;

  int Input;
  do
  {
    cout << "Choose: ";
    el();
    cout << "1) Addition";
    el();
    cout << "2) Subtraction";
    el();
    cout << "3) Multiplication";
    el();
    cout << "4) Division";
    el();
    el();
    cin >> Input;

  }
  while (Input != 1 && Input != 2 && Input!=3 && Input!=4);
  return Input;
}

Выполните, введите, например, символ, и он зациклится без остановок, действуя так, как будто оператора cin нет.

Ответы [ 6 ]

5 голосов
/ 01 февраля 2011

Вы должны проверить, что ввод был успешным и обрабатывать, когда это не так:

int mathOperator() {
  using namespace std;

  int Input;
  do {
    cout << "Choose: ";
    el();
    cout << "1) Addition";
    el();
    cout << "2) Subtraction";
    el();
    cout << "3) Multiplication";
    el();
    cout << "4) Division";
    el();
    el();
    while (!(cin >> Input)) {  // failed to extract
      if (cin.eof()) {  // testing eof() *after* failure detected
        throw std::runtime_error("unexpected EOF on stdin");
      }
      cin.clear();  // clear stream state
      cin.ignore(INT_MAX, '\n');  // ignore rest of line
      cout << "Input error.  Try again!\n";
    }
  } while (Input != 1 && Input != 2 && Input!=3 && Input!=4);
  return Input;
}

Если вы не проверяете, что извлечение завершилось успешно, то cin остается в неудачном состоянии (cin.fail ()). В случае сбоя последующие извлечения будут немедленно возвращены вместо попытки чтения из потока, что фактически делает их неактивными - что приводит к бесконечному циклу.

3 голосов
/ 01 февраля 2011

Если вы не вполне уверены, что ввод находится в правильном формате, вы редко хотите использовать operator>> непосредственно из входного потока.

Обычно легче читатьстрока с std::getline, поместите это в std::istringstream и прочитайте оттуда.Если это не удается, вы распечатываете / регистрируете сообщение об ошибке, выбрасываете оставшуюся часть строки и (возможно) переходите к следующей строке.

2 голосов
/ 01 февраля 2011

После прочтения неверного значения cin находится в состоянии «сбой».Вы должны сбросить это.

Вы должны очистить флаг ошибки и очистить буфер.таким образом:

   cin.clear(); 
   cin.ignore(std::numeric_limits<streamsize>::max(), '\n');

Второй вызов «очищает» входной буфер любых данных, которые могут быть там, чтобы подготовить вас к следующему вызову «cin».

Если вы окажетесьзаписав эти 2 строки «по всему вашему коду», вы можете написать простую встроенную функцию, чтобы заменить ее.

   inline void reset( std::istream & is )
   {
       is.clear();
       is.ignore( std::numeric_limits<std::streamsize>::max(), '\n' );
   }

Хотя я заставил эту функцию принимать любой поток, большую часть времени он будет использоваться только дляcin, где пользователь вводит и вводит что-то недопустимое.Если это неверный файл или ввод строки, нет способа исправить это, и вам лучше всего просто выбросить исключение.

2 голосов
/ 01 февраля 2011

не читайте int, читайте char, поэтому cin пропустит любой недопустимый символ

2 голосов
/ 01 февраля 2011
char Input;

 do
 {
// same code 
 }
 while (Input != '1' && Input != '2' && Input != '3' && Input!='4');
 return Input;

[EDIT]

Если вы хотите преобразовать char в int, вы можете использовать этот фрагмент кода

int i = (Input - 48);
0 голосов
/ 01 февраля 2011

Я согласен, что char так же удобен, так как вы всегда можете привести к int, чтобы ответить на ваш вопрос о том, почему это происходит, когда входные данные cin ожидаются как int, но вводятся символы, ввод хранится во входном потоке в течение всего цикла, поэтому кажется, что он «исчезает».

Для получения дополнительной информации: см. Сообщение от Наруэ в http://www.daniweb.com/forums/thread11505.html

...