2013-05-29 5 views
4

В C++ для обработки неправильных входов (например, когда программа запрашивает целое число, но вы вводите символ), он должен быть способен что-то сделать, а затем цикл, чтобы повторить ввод.застрял в бесконечном цикле

Моего цикл повторяется бесконечно при вводе символа, когда необходимо целое и наоборот:

#include<iostream> 

int main() 
{ 
    while (cout << "Enter a number" && !(cin >> num)) 
    { 
     cin.sync(); 
     cin.clear(); 
     cout << "Invalid input; please re-enter.\n"; 
    } 
} 

Что я должен сделать так, чтобы программа снова запрашивает новый вход?

+3

Вы действительно не должны писать такой код, очень сложно понять, что происходит и где ошибка. – Djon

+1

Подсказка: http://en.cppreference.com/w/cpp/io/basic_istream/ignore – aschepler

+0

@Djon Я нахожу код достаточно понятным и ошибку легко обнаружить. Что именно вас беспокоит? – jrok

ответ

5

Если cin >> num не удалось получить недопустимый вход, необходимо удалить его из потока. Я предлагаю использовать ignore вместо sync для этого. Причиной является sync is не гарантированно должен удалить оставшийся вход в все реализации стандартной библиотеки.

#include <iostream> 
#include <limits> 

int main() 
{ 
    int num; 
    while (cout << "Enter a number" && !(cin >> num)) 
    { 
     cin.clear(); // clear the error 

     // Remove input up to a new line 
     cin.ignore(std::numeric_limits<std::streamsize>::max(),'\n'); 
     cout << "Invalid input; please re-enter.\n"; 
    } 
} 

Приведенный выше пример использует std::numeric_limits<std::streamsize>::max() используется для получения максимального числа символов входной буфер может содержать. Это позволяет ignore() удалить как можно больше символов до новой строки. Это идиоматический C++ и предпочтительнее использования magic numbers, которые скорее всего скроют проблему, с которой вы в настоящее время работаете.

Это хорошо работает, но не обрабатывает ситуации, когда ввод содержит дополнительные символы после номера. Чтобы справиться с этими ситуациями, цикл необходимо немного изменить для обработки дополнительной проверки. Один из вариантов состоит в том, чтобы прочитать целую строку от cin, поместить ее в std::stringstream, прочитать номер из этого и затем выполнить дополнительную проверку. Существует один особый случай, который, возможно, нужно учитывать, хотя это - строка, где единственными символами после числа являются пробелы. К счастью, стандартная библиотека предоставляет модификатор потока std::skipws, который позволяет легко обрабатывать ситуацию. В приведенном ниже примере показано, как сделать это без особого effor

#include <iostream> 
#include <sstream> 

int main() 
{ 
    int num; 

    for(;;) 
    { 
     std::cout << "Enter a number: " << std::flush; 

     std::string line; 
     std::getline(std::cin, line); // Read a line from console 
     std::stringstream text(line); // store in a string stream 

     char ch = 0; 
     if(!(text >> num).fail() && (text >> std::skipws >> ch).fail()) 
     { 
      break; 
     } 

     std::cout << "Invalid input; please re-enter.\n"; 
    } 

    return 0; 
} 

Выражение (text >> std::skipws >> ch).fail() пропускает все пробелы, которые появляются после того, как числа, а затем пытается читать один символ. Если символ не доступен, чтение не будет выдаваться, если пользователь вводит только номер и ничего больше. Если мы попытаемся сделать это с помощью cin, он будет ожидать ввода пользователем большего текста, даже если вход действителен.

+0

он не работает, если я даю '233dsjfeu4' в качестве ввода, поскольку он читает его как 233, а затем передает ошибку, но отлично работает с '342365465235436436' или 'ddsfdfdggv' –

+0

@AmolakChandel Я обновил свой ответ, включив проверку, которая обеспечивает вводится только число. Любые конечные символы, кроме пробелов, указывают на сбой. –

2

Использование cin.ignore() вместо cin.sync() и посмотреть, почему from this answer

while (cout << "Enter a number" && !(cin >> num)) { 
    cin.clear();   // clear error 
    cin.ignore(100, '\n'); // ignore characters until next '\n' (or at most 100 chars) 
    cout << "Invalid input; please re-enter.\n"; 
} 

More on cin.ignore

Обратите внимание, что вы можете расширить сферу числа игнорируемых символов, до максимального

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

Почему волшебное число? – jrok

+0

@jrok Мне не нравится значение по умолчанию (1, EOF). И конкретный пример (100) для новичка более явный, чем 'std :: numeric_limits :: max()' например. Действительно, я должен был добавить ссылку на документ (сделано). –

+1

И что произойдет, если пользователь вводит более 100 символов? –

-1

Вы можете просто прочитать ввод как строку, преобразовать его в целое и подтвердить его.

#include <iostream> 
#include <string> 
using namespace std; 
int main() 
{ 
    int number = 0; 
    string input; 
    do { 
     cout << "Enter a number: "; 
     cin >> input; 
     number = atoi(input.c_str()); // atoi returns 0 on error.. 
     if (number != 0 || input.compare("0") == 0) // but maybe the user really entered "0". 
      break; 
     cout << endl; 
     cout << "Invalid input; please re-enter.\n"; 
    } while (1); 
    cout << "You entered " << number << endl; 
    return 0; 
} 

Пример выполнения программы:

% ./foo 
Enter a number: abc 

Invalid input; please re-enter. 
Enter a number: 2 
You entered 2 
% ./foo 
Enter a number: 0 
You entered 0 

.. хотя это, вероятно, не самое элегантное решение.

Смежные вопросы