Бесконечный цикл с cin при вводе строки, когда ожидается число

В следующем цикле, если мы вводим символы в качестве ввода cin вместо ожидаемых чисел, он переходит в бесконечный цикл. Может ли кто-нибудь объяснить мне, почему это происходит?

Когда мы используем cin, если ввод не является числом, то есть ли способы обнаружить это, чтобы избежать вышеупомянутых проблем?

unsigned long ul_x1, ul_x2;

while (1)
{
  cin >> ul_x1 >> ul_x2;
  cout << "ux_x1 is " << ul_x1 << endl << "ul_x2 is " << ul_x2 << endl;
}

person chanwcom    schedule 03.05.2011    source источник


Ответы (4)


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

Причина в том, что cin терпит неудачу в описанной вами ситуации и больше не будет считывать ввод в эти переменные. Давая cin неверный ввод, cin переходит в состояние сбоя и перестает запрашивать ввод командной строки, вызывая петля для свободного бега.

Для простой проверки вы можете попробовать использовать cin для проверки ваших входных данных, проверив, находится ли cin в состоянии отказа. При возникновении сбоя очистить состояние сбоя и принудительно перевести поток в выбросьте неверный ввод. Это возвращает cin к нормальной работе, чтобы вы могли запрашивать дополнительные данные.

  if (cin.fail())
  {
     cout << "ERROR -- You did not enter an integer";

     // get rid of failure state
     cin.clear(); 

     // From Eric's answer (thanks Eric)
     // discard 'bad' character(s) 
     cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');

  }

Для более сложной проверки вы можете сначала прочитать строку и выполнить более сложные проверки строки, чтобы убедиться, что она соответствует вашим ожиданиям.

person Doug T.    schedule 03.05.2011
comment
Или еще лучше, стрингстрим. - person Maxpm; 03.05.2011
comment
Если я вызываю cin.clear() после сбоя cin, почему он по-прежнему не запрашивает ввод при следующем вызове cin ›› x ? - person Eric Z; 03.05.2011
comment
Этот ответ не устраняет проблему, с которой столкнулся ОП, поскольку он неполный. Пожалуйста, взгляните на мой ответ :) - person Eric Z; 03.05.2011
comment
@ Эрик, я исправил ошибку в своем ответе. Спасибо, что указали на это. - person Doug T.; 03.05.2011
comment
@Almo, ты, вероятно, обжигаешься, потому что max - это макрос, определенный где-то в windows.h. Таким образом, это переопределяет то, что находится в C++ std lib. Попробуйте выполнить #undef max перед cin.ignore и посмотрите, что получится. - person Doug T.; 18.07.2012
comment
Бинго, проклятые окна.ч. Спасибо! - person Almo; 18.07.2012

Внимание

Пожалуйста, обратите внимание на следующее решение. Это еще не все, чтобы сбросить ошибку в вашем случае. Вы все равно получите бесконечный цикл!

if (cin.fail())
{
     cout << "Please enter an integer";
     cin.clear();
}

Полное решение

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

if (cin.fail())
{
         cout << "Please enter an integer";
         // clear error state
         cin.clear();
         // discard 'bad' character(s)
         cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
}

Другое решение

Вы также можете использовать getline и stringstream для достижения. Вот краткий пример.

   string input;
   while (1)
   {
      getline(cin, input);
      stringstream(input) >> x;
      cout << x << endl;
   }
person Eric Z    schedule 03.05.2011

Возможно, это потому,

  1. cin — это функция потоковой передачи. Когда вместо чисел вводится нечисловое значение, оно игнорируется. И вам будет предложено повторно войти.
  2. Даже если вы ввели числовые данные, вам будет предложено ввести дополнительные данные, поскольку вы находитесь в бесконечном цикле.

Вы можете решить эту проблему следующим образом: 1. Создайте функцию для ввода строки. 2. вернуть его как числовой после преобразования. Используйте strtod() для преобразования.

Надеюсь это поможет :)

person itsols    schedule 03.05.2011

Другой альтернативой является оператор!, он эквивалентен функции-члену fail()

//from Doug's answer
if ( !cin )
{
   cout << "ERROR -- You did not enter an integer";

   // get rid of failure state
   cin.clear(); 

   // From Eric's answer (thanks Eric)
   // discard 'bad' character(s) 
   cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
}
person Hani Shams    schedule 27.01.2018