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

如何从txt文件提取学生数据并存入动态分配的Student结构体数组

现有代码存在的问题
  • 结构体内部的exams/quizzes/hw/labs四个指针未预先分配内存,直接写入数据会触发非法内存访问,直接崩溃。
  • 读取逻辑混乱,混用getline和>>运算符会残留换行符在输入缓冲区,导致后续读取到空内容。
  • 错误地将输入的数值直接赋值给指针变量,相当于把成绩数值当成内存地址写入,完全不符合指针的使用逻辑。
  • 没有数组遍历索引,所有读取到的数据都只会写入结构体数组的第一个元素,后续元素全部为空。
  • 语法错误:循环体未闭合,inFile.close()写在了循环内部,第一次读取完就关闭文件,无法读取后续学生数据。
  • numStudents变量没有定义来源,在不知道学生总数的情况下直接分配动态数组,要么分配大小错误要么直接编译报错。
  • 名字读取逻辑错误:示例中姓名是带空格的John Doe,用>>读取字符串默认遇到空格就截断,只能读到John,丢失后面的姓氏。
正确实现方案

我们先约定和示例文本对齐的固定成绩项数:3门考试、2次测验、3次作业、4次实验,如果项数可变需要在文件中提前标注每个类别的数量,对应调整逻辑即可。完整实现代码如下:

#include <iostream>
#include <fstream>
#include <string>
#include <cassert>
using namespace std;

struct Student{
    string name;
    double * exams;
    double * quizzes;
    double * hw;
    double * labs;
};

// 定义成绩项数常量,后续修改方便
const int EXAM_CNT = 3;
const int QUIZ_CNT = 2;
const int HW_CNT = 3;
const int LAB_CNT = 4;

Student* readStudentData(const char* fileName, int& numStudents) {
    ifstream inFile(fileName);
    assert(inFile);
    
    // 第一步:统计学生总数,每个学生固定占5行
    int lineCnt = 0;
    string line;
    while (getline(inFile, line)) {
        lineCnt++;
    }
    numStudents = lineCnt / 5;
    if (numStudents <= 0) {
        inFile.close();
        return nullptr;
    }
    
    // 重置文件指针到开头,准备正式读数据
    inFile.clear();
    inFile.seekg(0, ios::beg);
    
    // 分配结构体数组内存
    Student* studentsData = new Student[numStudents];
    
    for (int i = 0; i < numStudents; i++) {
        // 先给当前学生的各个成绩指针分配内存
        studentsData[i].exams = new double[EXAM_CNT];
        studentsData[i].quizzes = new double[QUIZ_CNT];
        studentsData[i].hw = new double[HW_CNT];
        studentsData[i].labs = new double[LAB_CNT];
        
        // 读取带空格的姓名
        getline(inFile, studentsData[i].name);
        
        // 读取考试成绩
        for (int j = 0; j < EXAM_CNT; j++) {
            inFile >> studentsData[i].exams[j];
        }
        inFile.ignore(); // 忽略行末残留的换行符
        
        // 读取测验成绩
        for (int j = 0; j < QUIZ_CNT; j++) {
            inFile >> studentsData[i].quizzes[j];
        }
        inFile.ignore();
        
        // 读取作业成绩
        for (int j = 0; j < HW_CNT; j++) {
            inFile >> studentsData[i].hw[j];
        }
        inFile.ignore();
        
        // 读取实验成绩
        for (int j = 0; j < LAB_CNT; j++) {
            inFile >> studentsData[i].labs[j];
        }
        inFile.ignore();
    }
    
    inFile.close();
    return studentsData;
}

// 使用完数据后必须调用该函数释放内存,避免内存泄漏
void freeStudentData(Student* data, int numStudents) {
    for (int i = 0; i < numStudents; i++) {
        delete[] data[i].exams;
        delete[] data[i].quizzes;
        delete[] data[i].hw;
        delete[] data[i].labs;
    }
    delete[] data;
}

如果你的文件第一行明确标注了学生总数,可以省去提前统计行数的步骤,直接读取第一行数字作为numStudents即可,读取效率更高。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.15 09:27:00