You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在燃油计算代码中实现高质量的输入校验?

修复加油站燃油计算程序的输入校验缺陷

当前程序存在两处输入校验缺陷:

  • 输入数字后跟随任意字符(如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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.15 19:28:14