如何在燃油计算代码中实现高质量的输入校验?
修复加油站燃油计算程序的输入校验缺陷
当前程序存在两处输入校验缺陷:
- 输入数字后跟随任意字符(如
2weewdwfds[e[23)时,程序会提取开头的有效数字继续执行,而非报错要求重新输入 - 选择燃油类型时输入
1.1或1\23b这类包含小数或无效字符的内容,程序会将其截断为整数1,错误判定为选择95号燃油
原因分析
C++标准输入的>>运算符读取数值时,仅会读取到第一个非数字字符为止,后续无效字符会被留在输入缓冲区但不影响当前读取结果;当读取浮点数到整数变量时,会直接截断小数部分,导致不符合预期的输入被误判。
解决方案
通过读取整行输入并验证输入完整性的方式解决问题:
- 编写通用函数,读取整行字符串后,检查是否为纯有效数值(整数或正浮点数),且符合指定范围
- 替换原有
cin>>的读取逻辑,确保输入没有多余无效字符
修改后的完整代码
#include <iostream> #include <limits> #include <string> #include <sstream> #include <cctype> using namespace std; // Constants for fuel prices const double PRICE_95 = 50; // 95号汽油单价 const double PRICE_92 = 45; // 92号汽油单价 const double PRICE_GAS = 30; // 天然气单价 // 验证输入是否为纯整数且在指定范围内 bool isValidInteger(const string& input, int minVal, int maxVal) { if (input.empty()) return false; // 检查是否全为数字 for (char c : input) { if (!isdigit(c)) return false; } // 转换为整数并检查范围 int num; try { num = stoi(input); } catch (...) { return false; } return num >= minVal && num <= maxVal; } // 验证输入是否为正浮点数 bool isValidPositiveDouble(const string& input) { if (input.empty()) return false; bool hasDot = false; for (size_t i = 0; i < input.size(); ++i) { char c = input[i]; if (c == '.' && !hasDot) { hasDot = true; } else if (!isdigit(c)) { return false; } } // 转换为浮点数并检查是否为正 double num; try { num = stod(input); } catch (...) { return false; } return num > 0; } // 读取整数输入并验证 int getValidIntegerInput(const string& prompt, int minVal, int maxVal) { string input; while (true) { cout << prompt; getline(cin, input); if (isValidInteger(input, minVal, maxVal)) { return stoi(input); } cout << "输入错误!请输入" << minVal << "到" << maxVal << "之间的整数。\n"; } } // 读取正浮点数输入并验证 double getValidPositiveDoubleInput(const string& prompt) { string input; while (true) { cout << prompt; getline(cin, input); if (isValidPositiveDouble(input)) { return stod(input); } cout << "输入错误!请输入一个正数。\n"; } } // 选择燃油类型 double selectFuelType() { cout << "选择燃油类型:\n"; cout << "1. 95号汽油\n"; cout << "2. 92号汽油\n"; cout << "3. 天然气\n"; int fuelType = getValidIntegerInput("请输入燃油类型编号: ", 1, 3); switch (fuelType) { case 1: return PRICE_95; case 2: return PRICE_92; case 3: return PRICE_GAS; } return 0; // 不会执行到此处 } // 选择加油模式 int selectRefuelMode() { cout << "选择加油模式:\n"; cout << "1. 输入加油升数\n"; cout << "2. 按金额加油\n"; return getValidIntegerInput("请输入模式编号: ", 1, 2); } // 计算加油费用 void calculateRefuel(double pricePerLiter, int mode) { double liters = 0, amountToSpend = 0, totalCost = 0; if (mode == 1) { // 按升数加油 liters = getValidPositiveDoubleInput("请输入加油升数: "); totalCost = pricePerLiter * liters; } else if (mode == 2) { // 按金额加油 amountToSpend = getValidPositiveDoubleInput("请输入加油金额: "); liters = amountToSpend / pricePerLiter; totalCost = amountToSpend; } cout << "您已加油 " << liters << " 升,总费用: " << totalCost << " 卢布。\n"; } // 主函数 int main() { // 忽略main开始前可能存在的换行符,避免影响整行读取 cin.ignore(numeric_limits<streamsize>::max(), '\n'); double pricePerLiter = selectFuelType(); // 选择燃油类型 if (pricePerLiter == 0) { cout << "选择燃油类型时出错。\n"; return 1; } int mode = selectRefuelMode(); // 选择加油模式 calculateRefuel(pricePerLiter, mode); // 计算加油费用 return 0; }
关键改动说明
- 新增
isValidInteger和isValidPositiveDouble函数,用于验证输入字符串是否为纯有效数值 - 编写
getValidIntegerInput和getValidPositiveDoubleInput通用函数,负责读取整行输入并验证,直到输入符合要求 - 替换原有
cin>>的读取逻辑,改用整行读取,确保输入没有多余无效字符 - 在
main开头添加cin.ignore,避免之前的输入残留影响整行读取
内容的提问来源于stack exchange,提问作者Kirill Sirazov
相关产品推荐
相关产品推荐

