如何从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
相关产品推荐
相关产品推荐

