Как заставить cin принимать только числа

#c

Вопрос:

Вот код

 double enter_number()
{
  double number;
  while(1)
  {

        cin>>number;
        if(cin.fail())
        {
            cin.clear();
            cin.ignore(numeric_limits<streamsize>::max(), 'n');
            cout << "Invalid input " << endl;
        }
        else
        break;
        cout<<"Try again"<<endl;
  }
  return number;
}
 

Моя проблема в том, что когда я ввожу что-то вроде 1x, то 1 принимается в качестве входных данных, не замечая символа, который пропущен для другого запуска.
Есть ли способ заставить его работать с любым реальным числом, например 1,8?

Комментарии:

1. Прочитать все в строку и соответственно проанализировать входные данные?

2. Используйте cin.get (), а затем проверьте наличие символа EOF?

Ответ №1:

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

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

  1. Вы должны проверить это состояние ошибки.
  2. Вы должны очистить состояние ошибки.
  3. Вы должны либо альтернативно обработать входные данные, которые породили состояние ошибки, либо удалить их и повторно ввести пользователя.

Следующий код предоставляет один из многочисленных методов выполнения этих трех вещей.

 #include<iostream>
#include<limits>
using namespace std;
int main()
{

    cout << "Enter an int: ";
    int x = 0;
    while(!(cin >> x)){
        cin.clear();
        cin.ignore(numeric_limits<streamsize>::max(), 'n');
        cout << "Invalid input.  Try again: ";
    }
    cout << "You enterd: " << x << endl;        
}
 

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

Вы также можете протестировать cin после попытки ввода и обработать его таким образом, что-то вроде if(!cin){//устранить ошибку} .

Проверьте ссылку на istream для других функций-членов для обработки состояния потока: http://cplusplus.com/reference/iostream/istream/

Комментарии:

1. @Джефф Да, это очищает буфер. Вы также можете использовать его при использовании cin с getline при приеме входных данных, поскольку cin оставляет ‘n’ в буфере и не удаляет (я полагаю, не совсем уверен, возможно, это был cin.get), поэтому getline просто разделяется в тот момент, когда он присоединяется к входному буферу, когда он сталкивается с оставшимся ‘n’.

2. Одна вещь, которую не удается остановить, — это когда пользователь вводит что-то подобное 5a . С помощью этого вы не обнаружите ошибку до следующего раза, когда попытаетесь получить ввод.

Ответ №2:

Я бы использовал std::getline и std::string прочитал всю строку, а затем вырвался бы из цикла только тогда, когда вы сможете преобразовать всю строку в двойную.

 #include <string>
#include <sstream>

int main()
{
    std::string line;
    double d;
    while (std::getline(std::cin, line))
    {
        std::stringstream ss(line);
        if (ss >> d)
        {
            if (ss.eof())
            {   // Success
                break;
            }
        }
        std::cout << "Error!" << std::endl;
    }
    std::cout << "Finally: " << d << std::endl;
}
 

Ответ №3:

 #include<iostream>
#include<cstdlib>
#include<cstring>
using namespace std;
int get_int(void);
int main()
{
    puts("Enter a number");
    cout<<"The integer is "<<get_int()<<endl;
    return 0;
}
int get_int(void)
{
    char str[20];
    char* end;
    int num;
    do{
        fgets(str,20,stdin);
        str[strlen(str)-1]='';
        num=strtol(str,amp;end,10);
        if(!(*end))
            return num;
        else
        {
            puts("Please enter a valid integer");
            num=0;
        }
    }while(num==0);
}
 

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

Комментарии:

1. Этот код действительно плохой. Он смешивает C и C без веской причины, накладывает жестко заданное ограничение на строку, строка, которая добавляет нулевой терминатор, неправильно работает с многобайтовыми новыми строками, и ее нельзя использовать для ввода 0.

2. что касается смешивания C и C , strtol() действительно существует в C .

3. и его можно использовать для ввода 0. Вы, должно быть, не пробовали этого.

4. о str[strlen(str)-1]=»; Мне это было нужно, потому что в противном случае str содержал бы символ новой строки в качестве последнего символа, и код не работал бы. Если вы думаете, что можете сделать лучше, пожалуйста, предложите лучшее решение.