为何有效数据错误输出至switch分支?C++汽车程序问题排查
问题:有效汽车记录错误归类到无效分支
我的有效数据(Records.txt)持续被错误输出至无效case分支。当按下1时,仅显示1条有效记录,另外两条有效记录被放到InvalidRecords中。
Records.txt内容
AB12MP349 Fusion5 20 17000.00 33435KMOP324 BMW 40 25000.00 AB12MP349 Audi 100 4000.00 AB12MP349 Pagni 1 2000000.00
程序错误输出
./test Welcome to Car Database Lookup ---------------------------------------- Press 1 to display a table of valid car records: Press 2 to display a table full of InvalidRecords: Type here: 1 Car ID Model Quantity Price AB12MP349 Fusion5 20 17000 Press 2 to display a table full of InvalidRecords: Type here: 2 Invalid car IDs: 33435KMOP324 BMW 40 25000.00 AB12MP349 Audi 100 4000.00 AB12MP349 Pagni 1 2000000.00
原始代码
#include <iostream> #include <string> #include <fstream> #include <iomanip> #include <vector> #include <cctype> using namespace std; // Class to store information about cars class CarData { public: string CarID; string Model; int Quantity; double Price; // Constructor to initialize CarData class(Parameters) CarData(const string &carID, const string &model, int quantity, double price) : CarID(carID), Model(model), Quantity(quantity), Price(price) {} }; // Function prototypes bool dataValidation(char d); bool IsValidCarID(const string &carID); bool DataCarPrice(double price); void TakeCarData(vector<CarData> &carInfo, vector<string> &invalidCarIDs); int main() { // Menu for User enum uiforUser { DISPLAY_CARINFO = 1, DISPLAY_ERROR = 2, }; int userInput; cout << "\nWelcome to Pierce Car Database Lookup\n"; cout << setfill('-'); cout << setw(40) << "-" << endl; cout << "Press " << DISPLAY_CARINFO << " to display a table of valid car records: "; cout << endl; cout << "Press " << DISPLAY_ERROR << " to display a table full of Invalid Records: "; cout << "\nType here: "; cin >> userInput; // Used a Vector because it can hold many values and etc(Sequence Container !) vector<string> invalidCarIDs; vector<CarData> carInfo; switch (userInput) { // Menu To display Valid Records case DISPLAY_CARINFO: { TakeCarData(carInfo, invalidCarIDs); // Getting Parameters from Function(TakeCarData) // Output for valid Records cout << setfill(' '); cout << setw(27) << "Car ID"; cout << setw(20) << "Model"; cout << setw(19) << "Quantity"; cout << setw(16) << "Price"; cout << endl << endl; // for loop that uses a pointer(Record), this allows me to access the data from carInfo! for (const CarData &Record : carInfo) { cout << setw(29) << Record.CarID; cout << setw(19) << Record.Model; cout << setw(18) << Record.Quantity; cout << setw(16) << Record.Price; cout << endl; } } break; // Menu to display Record Errors case DISPLAY_ERROR: { TakeCarData(carInfo, invalidCarIDs); // Grabbing Parameters from Function below cout << "Invalid car IDs:" << endl; // for loop that uses a pointer(invalidID), this is allows me to access to data Validation Function for (const string &invalidID : invalidCarIDs) { cout << invalidID << endl; } } break; } return 0; } // DataValidation Logic ! bool dataValidation(char d) { // Checks if a character's range from A-Z, also checks for "O" return (d >= 'A' && d <= 'Z' && d != 'O'); } bool DataCarPrice(double &price) { if (price <= 5000) { cout << "test"; } return false; } bool IsValidCarID(const string &carID) { // checks length of CarID(9 characters long) if (carID.length() != 9) { return false; } if (!dataValidation(carID[0]) || !dataValidation(carID[1])) { return false; } for (int i = 2; i < 6; ++i) { // isalnum is used because it can check if a value is alphanumeric if (!isalnum(carID[i]) || carID[i] == 'O') { return false; } } for (int i = 3; i < 6; ++i) { if (!isdigit(carID[i])) { return false; } } return true; } void TakeCarData(vector<CarData> &carInfo, vector<string> &invalidCarIDs) { ifstream RecordFile; RecordFile.open("Records.txt"); if (!RecordFile) { cout << "File not found. Please check the file path." << endl; system("pause"); exit(EXIT_FAILURE); } // Read data from the file and add it to the vector string carID, model; int quantity; double price; while (RecordFile >> carID >> model >> quantity >> price) { carInfo.emplace_back(carID, model, quantity, price); // Add car data to the vector } while (RecordFile >> carID) { invalidCarIDs.emplace_back(carID); } RecordFile.close(); // Open an output file (if needed) ofstream DataBase; DataBase.open("Output.txt"); if (!DataBase) { cout << "Output file not found. Please check the file path." << endl; system("pause"); exit(EXIT_FAILURE); } // Close files when done DataBase.close(); }
问题原因
- 未执行验证逻辑:
TakeCarData函数完全没有调用IsValidCarID判断CarID合法性,仅通过是否能读取四个字段来区分有效/无效记录,逻辑完全错误。 - IsValidCarID规则错误:对CarID的格式验证逻辑矛盾,导致合法的CarID会被误判为无效。
- 无效记录收集错误:将读取失败后的所有剩余token单独加入无效列表,而非将整条无效记录的字段作为一组收集。
- 重复读取文件:在不同case分支中重复调用
TakeCarData,导致文件读取状态异常。
修复方案
1. 修正IsValidCarID验证逻辑
根据示例中合法CarID(AB12MP349)的格式,调整验证规则为:
- 总长度9位
- 前两位:大写字母(不含O)
- 第3-4位:数字
- 第5-6位:大写字母(不含O)
- 最后三位:数字
bool IsValidCarID(const string &carID) { if (carID.length() != 9) { return false; } // 验证前两位:大写字母,不含O if (!dataValidation(carID[0]) || !dataValidation(carID[1])) { return false; } // 验证第3-4位:数字 for (int i = 2; i < 4; ++i) { if (!isdigit(carID[i])) { return false; } } // 验证第5-6位:大写字母,不含O for (int i = 4; i < 6; ++i) { if (!dataValidation(carID[i])) { return false; } } // 验证最后三位:数字 for (int i = 6; i < 9; ++i) { if (!isdigit(carID[i])) { return false; } } return true; }
2. 重构TakeCarData函数
读取每条记录后先验证CarID,合法则加入有效列表,否则将整条记录的所有字段加入无效列表:
void TakeCarData(vector<CarData> &carInfo, vector<string> &invalidCarIDs) { ifstream RecordFile("Records.txt"); if (!RecordFile) { cerr << "文件未找到,请检查路径。" << endl; system("pause"); exit(EXIT_FAILURE); } string carID, model; int quantity; double price; // 逐行处理每条记录 while (RecordFile >> carID >> model >> quantity >> price) { if (IsValidCarID(carID)) { carInfo.emplace_back(carID, model, quantity, price); } else { // 将整条无效记录的所有字段加入无效列表 invalidCarIDs.push_back(carID); invalidCarIDs.push_back(model); invalidCarIDs.push_back(to_string(quantity)); invalidCarIDs.push_back(to_string(price)); } } RecordFile.close(); }
3. 修正函数参数不匹配问题
将DataCarPrice的定义与声明统一:
bool DataCarPrice(double price) { if (price <= 5000) { cout << "test"; } return false; }
4. 调整main函数流程
提前读取所有数据,避免重复打开文件:
int main() { enum uiforUser { DISPLAY_CARINFO = 1, DISPLAY_ERROR = 2, }; int userInput; cout << "\nWelcome to Pierce Car Database Lookup\n"; cout << setfill('-'); cout << setw(40) << "-" << endl; cout << "Press " << DISPLAY_CARINFO << " to display a table of valid car records: " << endl; cout << "Press " << DISPLAY_ERROR << " to display a table full of Invalid Records: " << endl; cout << "\nType here: "; cin >> userInput; vector<string> invalidCarIDs; vector<CarData> carInfo; // 提前读取并处理所有数据 TakeCarData(carInfo, invalidCarIDs); switch (userInput) { case DISPLAY_CARINFO: { cout << setfill(' '); cout << setw(27) << "Car ID"; cout << setw(20) << "Model"; cout << setw(19) << "Quantity"; cout << setw(16) << "Price"; cout << endl << endl; for (const CarData &Record : carInfo) { cout << setw(29) << Record.CarID; cout << setw(19) << Record.Model; cout << setw(18) << Record.Quantity; cout << setw(16) << Record.Price; cout << endl; } } break; case DISPLAY_ERROR: { cout << "Invalid car IDs:" << endl; for (const string &invalidID : invalidCarIDs) { cout << invalidID << endl; } } break; default: cout << "无效输入,请输入1或2。" << endl; } return 0; }
修复后效果
- 按下1时,显示所有CarID合法的3条记录
- 按下2时,仅显示无效的那条记录的所有字段
内容的提问来源于stack exchange,提问作者Zximy
相关产品推荐
相关产品推荐

