Это правильный подход для проверки входных данных со значениями с плавающей запятой?
Потратив достаточно много времени на изучение проверки ввода, я объединил несколько идей и придумал следующее:
Функция для проверки правильности строки double
...
bool isDouble(double& destination, string& source)
{ // 64 bit
bool goodValue = false;
if (!source.empty()) {
errno = 0;
char *garbage = nullptr;
destination = strtod(source.c_str(), &garbage);
if (*garbage == '\0' && errno != ERANGE)
goodValue = true;
}
return goodValue;
}
Функция для проверки строки на правильность 32 бит integer
...
bool isLong(long& destination, string& source)
{ // 32 bit (base 10)
const short BASE = 10;
bool goodValue = false;
if (!source.empty()) {
errno = 0;
char* garbage = nullptr;
destination = strtol(source.c_str(), &garbage, BASE);
if (*garbage == '\0' && errno != ERANGE)
goodValue = true;
}
return goodValue;
}
Пример реализации
using namespace std;
int main() {
string buffer;
double value;
cout << "Enter a value: ";
getline(cin, buffer, '\n');
if (isDouble(value, buffer))
cout << "Value: " << value << endl;
else
cout << "ERROR: Invalid input\n";
return 0;
}
Кто-нибудь может прокомментировать, если я что-то упускаю из виду при таком подходе?
4 ответа
Основываясь на отзывах тех, кто ответил, и на некоторых примерах из других вопросов, я ответил на свой вопрос. Согласно предложению FailedDev, этот вопрос должен быть помечен как ответ. Итак, вот принятый ответ.:)
Я не уверен насчет "правильного" способа, но это определенно не то, как я это сделаю. Первый и, вероятно, самый очевидный, этот кусок кода:
for (i = 0, d = 0; i < BUFFSIZE && buffer[i] != 0 && buffer[i] >= '0' &&
buffer[i] <= '9' || (buffer[i] == '.' && d == 0); i++)
if (buffer[i] == '.') ++d;
дублируется в нескольких местах (по крайней мере, я думаю, что другой экземпляр идентичен, и, вероятно, должен быть в любом случае).
Во-вторых, вы не можете разрешить такие номера, как 1e23
или же -1.2
, которые обычно принимаются как с плавающей запятой.
Вне руки, думаю, я бы использовал strtod
попытаться преобразовать вход. Вы можете использовать его второй параметр, чтобы определить, достиг ли преобразование конца входной строки (если нет, вы будете знать, что хотя бы часть ввода не была принята). Затем вы (очевидно) захотите проверить, что возвращаемое значение было в желаемом диапазоне.
Возможно, strtod()
здесь может помочь функция, так как она говорит вам, сколько было преобразовано:
const char * buf = get_raw_data(); // somehow
char * endptr;
const double value = strtod(buf, &endptr);
if (endptr != buf + std::strlen(buf)) { /* ... error ... */ }
В качестве источника для buf
Вы можете маркировать свой вклад с std::string token; std::cin >> token;
или что-то подобное и использовать token.c_str()
,
Если это упражнение, которое вы хотите, это понятно. Но в противном случае вы можете использовать istringstream
чтобы не изобретать велосипед:
#include <iostream>
#include <sstream>
#include <string>
using namespace std;
int main () {
int n,val;
string stringvalues;
stringvalues = "3.14159254 f01fhasfljk";
istringstream iss(stringvalues);
float x,y;
iss >> x;
cout << x * 2 << endl;
iss >> y;
if ( ! iss.fail() )
{
cout << y * 2 << endl;
}
else
{
cout << "second value not a number..." << endl;
}
return 0;
}