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

使用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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.24 13:05:09