C ++ cin.fail () вопрос - PullRequest
       11

C ++ cin.fail () вопрос

3 голосов
/ 09 января 2010

При запуске следующего кода и вводе номера он работает нормально. Но при вводе буквы программа входит в бесконечный цикл, отображающий «Введите число (0 для выхода): cin failed.»

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

int number;
do{
    cout << "Enter a number (0 to exit): ";
    cin >> number;
    if(cin.fail()){
        cout << "cin failed." << endl;
        cin.clear();
    }else{
        cout << "cin succeeded, " << number << " entered." << endl;
    }
}while(number != 0);

Ответы [ 3 ]

5 голосов
/ 09 января 2010

Необходимо очистить строку от cin , используя cin.ignore , в дополнение к очистке состояния потока (что делает cin.clear ).

У меня есть несколько служебных функций , чтобы упростить это (в частности, вас заинтересует clearline , который очищает состояние потока и текущую строку) и почти точный пример что вы хотите .

Ваш код, более или менее, используя мою clearline :

#include "clinput.hpp" // move my file to a location it can be used from

int main() {
  using namespace std;
  while (true) {
    cout << "Enter a number (0 to exit): ";
    int number;
    if (cin >> number) {
      cout << "Read " << number << '\n';
      if (number == 0) {
        break;
      }
    }
    else {
      if (cin.eof()) { // tested only *after* failed state
        cerr << "Input failed due to EOF, exiting.\n";
        return 1;
      }
      cerr << "Input failed, try again.\n";
      clearline(cin); // "cin >> clearline" is identical
    }
  }
  return 0;
}

Здесь все еще есть потенциальная проблема (исправлена ​​в моем clinput_loop.cpp с blankline ), оставив вход в буфере, который позже испортит IO (см. «42 abc»). «в примере сессии). Извлечение приведенного выше кода в отдельную и самодостаточную функцию оставлено в качестве упражнения для читателя, но вот скелет:

template<class Type, class Ch, class ChTr>
Type read(std::basic_istream<Ch,ChTr>& stream, Ch const* prompt) {
  Type value;
  // *try input here*
  if (could_not_get_input or more_of_line_left) {
    throw std::runtime_error("...");
  }
  return value;
}
template<class Type, class Ch, class ChTr>
void read_into(
  Type& value,
  std::basic_istream<Ch,ChTr>& stream,
  Ch const* prompt
) {
  value = read<Type>(stream, prompt);
}

Пример использования:

int n;
try {
  read_into(n, std::cin, "Enter a number: ");
}
catch (std::runtime_error& e) {
  //...
  raise;
}
cout << "Read " << n << '\n';

clearline функция, извлеченная для потомков, в случае, если вышеупомянутые ссылки когда-либо прерываются (и немного изменяются, чтобы сделать автономными):

#include <istream>
#include <limits>

template<class C, class T>
std::basic_istream<C,T>& clearline(std::basic_istream<C,T>& s) {
  s.clear();
  s.ignore(std::numeric_limits<std::streamsize>::max(), s.widen('\n'))
  return s;
}

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

  • std :: istream - это typedef, равный std::basic_istream<char, std::char_traits<char> >
  • std :: wistream - это typedef, равный std::basic_istream<wchar_t, std::char_traits<wchar_t> >
  • расширение позволяет '\n' стать L'\n' соответствующим образом
  • этот код работает как для обычных char и wchar_t , так и для любых совместимых экземпляров basic_istream
  • написано, что оно называется clearline(stream) или stream >> clearline, сравните с другими манипуляторами, такими как std :: endl , std :: ws , или std :: boolalpha
1 голос
/ 09 января 2010

Это, вероятно, то, что вы намеревались сделать:

#include <iostream>
using namespace std;

int main ()
{
  int i;
  do {
    if (cin.fail())
    {
      cin.ignore(255);
      cin.clear();
    }          
    cout << "Please enter an integer value: ";
    cin >> i;
  } while ( cin.fail() );
  cout << "The value you entered is " << i;
  return 0;
}
0 голосов
/ 07 октября 2015

Это простой пример cin.fail () Он будет обрабатывать ввод, пока не будет предоставлено правильное целочисленное значение

#include <iostream>
using namespace std;

int main()
{
int j;
int i;

i = 0;
while (1) {
    i++;
    cin >> j;
    if (cin.fail()) return 0;
    cout << "Integer " << i << ": " << j << endl;
}
}

Введите:

42 51 85 привет 85

Выход:

Целое число 1: 42

Целое число 2: 51

Целое число 3: 85

...