使用stod()转换string为double触发core dump问题排查求助
问题分析与修复方案
核心错误原因
触发core dump的直接原因是stod()在尝试将无法转换为浮点数的字符串(比如空字符串、非数字字符)转换时,抛出了std::invalid_argument异常,但程序未捕获该异常,导致进程直接终止。
除此之外,代码还存在几个关键逻辑bug:
while (getline(inFile, line))循环内部直接调用inFile.close()和return 0,导致程序只处理第一行学生数据就退出removeLowest()函数未检查输入vector是否为空,若学生成绩列表为空,min_element会返回grades.end(),调用erase会触发未定义行为split()函数会保留csv中的空字段(比如连续逗号、行首尾的逗号),这些空字符串传入stod()会直接触发异常
修复步骤
1. 捕获stod()的转换异常
封装安全转换函数,添加try-catch块处理无效输入,避免异常终止:
double safeStod(const string& token) { try { return stod(token); } catch (const std::invalid_argument& e) { cerr << "Warning: Invalid number '" << token << "', using 0.0 instead" << endl; return 0.0; } catch (const std::out_of_range& e) { cerr << "Warning: Number '" << token << "' out of range, using 0.0 instead" << endl; return 0.0; } }
2. 修复循环逻辑
将文件关闭和程序返回的代码移出while循环,确保所有学生数据都被处理:
// Process each student line in input file string line; while (getline(inFile, line)) { // ... 原有处理逻辑 ... } // Close input and output files inFile.close(); outFile.close(); return 0;
3. 增强removeLowest()的安全性
添加空vector判断,避免非法迭代器访问:
void removeLowest(vector<double>& grades) { if (grades.empty()) { return; } auto it = min_element(grades.begin(), grades.end()); grades.erase(it); }
4. 改进split()函数
过滤csv中的空字段,避免无效的空字符串传入转换函数:
vector<string> split(const string& s, char delimiter) { vector<string> tokens; string token; istringstream tokenStream(s); while (getline(tokenStream, token, delimiter)) { if (!token.empty()) { tokens.push_back(token); } } return tokens; }
5. 校验列数一致性(可选)
确保学生成绩的列数和maxPoints的列数匹配,避免后续计算出错:
if (grades.size() != maxPoints.size()) { cerr << "Mismatched grade count for student: " << name << endl; continue; }
修改后的完整代码
#include <iostream> #include <fstream> #include <sstream> #include <vector> #include <algorithm> #include <numeric> #include <iomanip> #include <stdexcept> using namespace std; // Split string by delimiter, filter empty tokens vector<string> split(const string& s, char delimiter) { vector<string> tokens; string token; istringstream tokenStream(s); while (getline(tokenStream, token, delimiter)) { if (!token.empty()) { tokens.push_back(token); } } return tokens; } // Safely remove lowest grade (no-op if vector is empty) void removeLowest(vector<double>& grades) { if (grades.empty()) { return; } auto it = min_element(grades.begin(), grades.end()); grades.erase(it); } // Safe string-to-double conversion with error handling double safeStod(const string& token) { try { return stod(token); } catch (const std::invalid_argument& e) { cerr << "Warning: Invalid number '" << token << "', using 0.0 instead" << endl; return 0.0; } catch (const std::out_of_range& e) { cerr << "Warning: Number '" << token << "' out of range, using 0.0 instead" << endl; return 0.0; } } int main(int argc, char* argv[]) { if (argc != 3) { cerr << "Usage: " << argv[0] << " input_file output_file" << endl; return 1; } string inputFile(argv[1]); string outputFile(argv[2]); ifstream inFile(inputFile); if (!inFile.is_open()) { cerr << "Error opening input file: " << inputFile << endl; return 1; } ofstream outFile(outputFile); if (!outFile.is_open()) { cerr << "Error opening output file: " << outputFile << endl; return 1; } // Read header line string header; if (!getline(inFile, header)) { cerr << "Error reading input file: " << inputFile << endl; return 1; } // Parse maximum possible points for each lab string maxPointsLine; if (!getline(inFile, maxPointsLine)) { cerr << "Error reading input file: " << inputFile << endl; return 1; } vector<double> maxPoints; for (const auto& token : split(maxPointsLine, ',')) { maxPoints.push_back(safeStod(token)); } // Write output header outFile << "name,points_earned,points_possible" << endl; // Process each student line string line; while (getline(inFile, line)) { auto tokens = split(line, ','); if (tokens.empty()) { continue; } string name = tokens[0]; vector<double> grades; for (size_t i = 1; i < tokens.size(); i++) { grades.push_back(safeStod(tokens[i])); } // Validate grade count matches max points count if (grades.size() != maxPoints.size()) { cerr << "Mismatched grade count for student: " << name << endl; continue; } // Remove lowest grade and corresponding max point removeLowest(grades); vector<double> tempMax = maxPoints; removeLowest(tempMax); // Calculate totals double pointsEarned = accumulate(grades.begin(), grades.end(), 0.0); double pointsPossible = accumulate(tempMax.begin(), tempMax.end(), 0.0); // Write to output outFile << name << ","; outFile << fixed << setprecision(2) << pointsEarned << ","; outFile << fixed << setprecision(2) << pointsPossible << endl; } // Cleanup inFile.close(); outFile.close(); return 0; }
注:额外修复了一个逻辑问题:原代码计算
pointsPossible时直接累加所有maxPoints,但实际上应该和学生成绩一样移除最低分对应的maxPoint,这样总分计算才匹配。
内容的提问来源于stack exchange,提问作者Witch Kas
相关产品推荐
相关产品推荐

