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

ifstream仅读取3次数据:性别统计与GPA计算异常排查

问题描述

我编写了一段C++代码,用于统计不同性别的人数、GPA总和及GPA平均值。男女统计的逻辑几乎完全一致,但第二次循环无法从文件中读取任何数据。我尝试交换男女统计的顺序,结果发现无论哪部分放在第二位,都无法完成统计。代码会输出“File Opened”,说明文件已成功打开,但我无法理解为何无法多次遍历文件内容。附上代码及输出情况:

#include<iostream>
#include<iomanip>
#include<fstream>
using namespace std;

void openFiles(ifstream& read, ofstream& write)
{
    read.open("StudentsPreformanceData.txt");

    if (read.is_open())
        cout << "File Opened" << endl;
    else
        cout << "Error try again";

    write.open("Results.txt");
    write << fixed << showpoint << setprecision(2);
}
void initialize(int& countFemale, int& countMale, double& sumFemale, double& sumMale)
{
    countFemale = 0;
    countMale = 0;
    sumFemale = 0.00;
    sumMale = 0.00;
}
void sumGrades(ifstream& read, double& sum, char gender)
{
    char student;
    double grade;
    while (!read.eof())
    {
        read >> student;
        read >> grade;
        if (student == gender)
            sum = sum + grade;

        //cout << student << " " << grade << " " << sum << endl;
    }
    read.close();
}
double averageGrades(ifstream& read, double sum, int& count, char gender)
{
    char student;
    double grade;
    while (!read.eof())
    {
        read >> student;
        read >> grade;
        if (student == gender)
        {
            count = count + 1;
        }
        cout << student << " " << count << " " << sum << endl;
    }
    return sum / count;
    read.close();
}
void printResults()
{

}

int main()
{
    ifstream read;
    ofstream write;
    openFiles(read, write);

    int countFemale, countMale;
    double sumFemale, sumMale;
    initialize(countFemale, countMale, sumFemale, sumMale);

    cout << countFemale << sumFemale << countMale << sumMale << endl;

    sumGrades(read, sumFemale, 'f');
    cout << countFemale << " " << sumFemale << " " << countMale << " " << sumMale << endl;

    openFiles(read, write);

    sumGrades(read, sumMale, 'm');
    cout << countFemale << " " << sumFemale << " " << countMale << " " << sumMale << endl;

    openFiles(read, write);

    averageGrades(read, sumMale, countMale, 'm');
    cout << countFemale << " " << sumFemale << " " << countMale << " " << sumMale << endl;

    openFiles(read, write);

    averageGrades(read, sumFemale, countFemale, 'f');
    cout << countFemale << " " << sumFemale << " " << countMale << " " << sumMale << endl;
}

输出显示多次打印“File Opened”,但后续统计的数值未更新,第二次及之后的循环没有读取到任何数据。

问题原因及解决方法

核心问题

  • 文件流状态未重置:第一次读取文件后,文件指针移到末尾,流的eof标志被置位。即使重新调用openFiles,流对象仍处于错误状态,不清除标志的话无法正常读取。
  • read.close()位置错误:averageGrades函数中,read.close()写在return语句之后,永远不会执行,导致流资源无法正确释放。
  • 重复IO效率低下:多次打开关闭文件不仅效率低,还容易引发流状态异常,更合理的方式是一次性读取数据到内存再统计。

修复方案

方案1:修复流状态,正确重复打开文件

修改openFiles函数,先清除旧流的状态并关闭:

void openFiles(ifstream& read, ofstream& write)
{
    if (read.is_open())
    {
        read.close();
    }
    read.clear(); // 清除所有错误标志
    read.open("StudentsPreformanceData.txt");

    if (read.is_open())
        cout << "File Opened" << endl;
    else
        cout << "Error try again";

    if (!write.is_open())
    {
        write.open("Results.txt");
        write << fixed << showpoint << setprecision(2);
    }
}

同时修正averageGrades中read.close()的位置:

double averageGrades(ifstream& read, double sum, int& count, char gender)
{
    char student;
    double grade;
    count = 0;
    while (!read.eof())
    {
        read >> student;
        read >> grade;
        if (student == gender)
        {
            count = count + 1;
        }
        cout << student << " " << count << " " << sum << endl;
    }
    read.close();
    return count > 0 ? sum / count : 0; // 避免除以0
}

方案2:一次性读取数据(推荐)

一次性读取所有数据到容器,再遍历统计,避免多次IO操作:

#include<iostream>
#include<iomanip>
#include<fstream>
#include<vector>
using namespace std;

struct Student {
    char gender;
    double gpa;
};

void openFiles(ifstream& read, ofstream& write)
{
    read.open("StudentsPreformanceData.txt");
    if (!read.is_open())
    {
        cout << "Error try again";
        exit(1);
    }
    write.open("Results.txt");
    write << fixed << showpoint << setprecision(2);
}

void loadStudents(ifstream& read, vector<Student>& students)
{
    char gender;
    double gpa;
    while (read >> gender >> gpa) // 用读取操作作为循环条件,避免eof陷阱
    {
        students.push_back({gender, gpa});
    }
    read.close();
}

void calculateStats(const vector<Student>& students, int& countF, double& sumF, int& countM, double& sumM)
{
    countF = 0; sumF = 0.0;
    countM = 0; sumM = 0.0;
    for (const auto& s : students)
    {
        if (s.gender == 'f')
        {
            countF++;
            sumF += s.gpa;
        }
        else if (s.gender == 'm')
        {
            countM++;
            sumM += s.gpa;
        }
    }
}

void printResults(ofstream& write, int countF, double sumF, int countM, double sumM)
{
    write << "Female Stats:" << endl;
    write << "Count: " << countF << endl;
    write << "Total GPA: " << sumF << endl;
    if (countF > 0)
        write << "Average GPA: " << sumF / countF << endl;

    write << "\nMale Stats:" << endl;
    write << "Count: " << countM << endl;
    write << "Total GPA: " << sumM << endl;
    if (countM > 0)
        write << "Average GPA: " << sumM / countM << endl;
}

int main()
{
    ifstream read;
    ofstream write;
    openFiles(read, write);

    vector<Student> students;
    loadStudents(read, students);

    int countF, countM;
    double sumF, sumM;
    calculateStats(students, countF, sumF, countM, sumM);

    printResults(write, countF, sumF, countM, sumM);

    cout << "Female Count: " << countF << ", Total GPA: " << sumF << ", Average: " << (countF>0 ? sumF/countF : 0) << endl;
    cout << "Male Count: " << countM << ", Total GPA: " << sumM << ", Average: " << (countM>0 ? sumM/countM : 0) << endl;

    return 0;
}

额外注意点

  • 避免使用while(!read.eof())作为循环条件,应直接用读取操作while(read >> student >> grade),避免最后一次读取异常。
  • 统计平均值时需判断人数是否为0,防止除以0的错误。

内容的提问来源于stack exchange,提问作者Alexander Chapman

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.06 11:44:53