Я знаю, что этот вопрос задавался ранее, но ответы не решили мою проблему, поэтому я задаю этот вопрос.
У меня есть простая программа, чтобы найти наибольшее из трех чисел, которые должны принимать только плавающие числа. В случае ввода символа или строки должна отображаться ошибка, и пользователь должен ввести снова.
У меня есть функция, чтобы принять действительный плавающий ввод
float validInput()
{
float x;
cout<< flush;
cin >> x;
while(cin.fail())
{
cin.clear();
cin.ignore(numeric_limits<streamsize>::max(),'\n');
cout << "Not a numeric value please enter again\n";
cin >> x;
}
return x;
}
поэтому я беру ввод в основной функции, используя validInput как
int main()
{
float x = validInput();
float y = validInput();
float z = validInput();
findGreatest(x,y,z);
return 0;
}
Этот метод работает для большинства входов. Сбой, когда я ввожу число, за которым следует символ, функция validInput не работает странным образом. При таком вводе выводит сообщение об ошибке «Не числовое значение, пожалуйста, введите снова» но не принимает другой ввод, вместо этого он считает числовое значение перед символами вводом и сохраняет его. Мое требование — игнорировать весь ввод и запрашивать новый ввод
Из моего понимания
cin.ignore(numeric_limits<streamsize>::max(),'\n');
не игнорирует числа, которые вводятся в начале ввода, но только удаляет символы из потока, даже если cin.fail () был равен true.
Есть ли способ это исправить? вероятно, для cin.ignore нужны другие параметры, хотя я не уверен.
заранее спасибо
источники:
https://stackoverflow.com/a/16934374/5236575
PS: я не могу использовать какие-либо специальные библиотеки, такие как boost. Код предназначен для реализации контрольных примеров для тестирования программного обеспечения, поэтому он должен правильно обрабатывать любые типы ввода.
Возможно, вы захотите посмотреть, что на самом деле происходит, потому что поведение совсем не странное: когда вы вводите число с плавающей запятой, за которым следует не число в одной строке, значение с плавающей запятой извлекается просто ОК. Случай неудачи вашего validInput()
функция не хит — с этим вызовом! Тем не менее, поскольку есть нечто, что не может быть проанализировано как число с плавающей запятой при вызове функции снова второй вызов вызывает сбой!
Вы можете увидеть, что это действительно так, добавив вывод между вашими validInput()
звонки. Таким образом, вы можете сказать, какой из вызовов фактически вызвал ошибку. Сохранение значения при отсутствии ошибок — ожидаемое поведение!
Вы можете убедиться, что строка не содержит недопустимого ввода, прочитав строку и проверив, что вы можете читать из строки и что в этой строке нет ничего, кроме пробела. Например:
float validInput()
{
float x;
// cout<< flush; There is *NO* reason to flush cout: it is flushed when using cin
for (std::string line; std::getline(std::cin, line); ) {
std::istringstream lin(line);
if (lin >> x && (lin >> std::ws).eof()) {
break;
}
cout << "Not a numeric value please enter again\n";
}
throw std::runtime_error("reached end of input before getting a valid value!");
return x;
}
Использование lin >> std::ws
пропускает все потенциальные конечные пробелы (новая строка уже удалена std::getline()
) на этой линии. После этого поток должен быть использован и eof()
Флаг устанавливается, если дальнейших вводов действительно нет (это одно из немногих допустимых применений eof()
…).
std::cin
будет читать последовательно из потока, поэтому, если первые символы представляют действительное число, он думает, что все в порядке. Если вы хотите убедиться, что вы действительно читаете просто число (не сопровождаемое некоторыми дополнительными символами), одним из вариантов является чтение с использованием std::getline
в std::string
, затем преобразовать строку в число с плавающей запятой, используя std::stof
(C ++, 11). Последний принимает в качестве второго аргумента указатель на местоположение первого символа, который не может быть преобразован. Если это местоположение меньше длины строки, тогда ваша строка содержит больше, чем просто число, поэтому ввод неверен.
Пример:
#include <iostream>
int main()
{
float x;
std::size_t pos;
std::string str;
while (std::getline(std::cin, str))
{
try
{
x = std::stof(str, &pos);
}
catch(...)
{
std::cout << "Not a numeric value please enter again\n";
continue;
}
if(pos != str.length())
{
std::cout << "Not a numeric value please enter again\n";
continue;
}
break;
}
std::cout << x;
}