C语言CSV成绩计算程序异常:每学期首个科目数据丢失
问题:读取学期成绩CSV时丢失首行科目数据
编写的C程序读取grades.csv计算学期平均、总体平均及科目组平均时,每个学期第一行(与学期名称同列)的科目数据未被读取,导致统计结果缺失该科目(如示例中的TH科目未出现在分组统计中,学期平均也因少算一个科目而错误)。
问题原因分析
原代码中,判断行首非逗号时,仅通过sscanf(line, "%[^,],", grades[numGrades].grade)读取学期名称,完全忽略了同一行中紧随其后的科目数据(如TH31101,Thai Language 1,1.0,1.5部分),这直接导致每个学期的第一个科目被遗漏。
修正后的代码
#include <stdio.h> #include <stdlib.h> #include <string.h> #define MAX_GRADES 100 #define MAX_SUBJECTS 100 // struct to store subject data typedef struct { char code[50]; char subjectName[50]; float cr; float grade; } Subject; // struct to store grade data typedef struct { char grade[50]; Subject subjects[MAX_SUBJECTS]; int numSubjects; float avgGrade; } GradeData; // struct to store subject group data typedef struct { char subjectGroup[3]; float totalGrade; int count; } SubjectGroup; // 提取并处理科目数据的函数,避免代码重复 void processSubject(Subject newSubject, GradeData grades[], int *numGrades, float *totalGradeSum, int *totalNumSubjects, SubjectGroup subjectGroups[], int *numSubjectGroups) { if (grades[*numGrades - 1].numSubjects < MAX_SUBJECTS) { strcpy(grades[*numGrades - 1].subjects[grades[*numGrades - 1].numSubjects].code, newSubject.code); strcpy(grades[*numGrades - 1].subjects[grades[*numGrades - 1].numSubjects].subjectName, newSubject.subjectName); grades[*numGrades - 1].subjects[grades[*numGrades - 1].numSubjects].cr = newSubject.cr; grades[*numGrades - 1].subjects[grades[*numGrades - 1].numSubjects].grade = newSubject.grade; grades[*numGrades - 1].numSubjects++; *totalGradeSum += newSubject.grade; *totalNumSubjects++; // Calculate subject group averages char subjectGroup[3]; strncpy(subjectGroup, newSubject.code, 2); // get first 2 characters of subject code subjectGroup[2] = '\0'; // add null terminator int found = 0; for (int i = 0; i < *numSubjectGroups; i++) // check if subject group already exists { if (strcmp(subjectGroup, subjectGroups[i].subjectGroup) == 0) // if subject group exists { // add grade to total grade and increment count subjectGroups[i].totalGrade += newSubject.grade; // add grade to total grade subjectGroups[i].count++; // increment count found = 1; // set found to true break; } } if (!found) // if subject group does not exist { strcpy(subjectGroups[*numSubjectGroups].subjectGroup, subjectGroup); // copy subject group to subject group data subjectGroups[*numSubjectGroups].totalGrade = newSubject.grade; // set total grade to grade subjectGroups[*numSubjectGroups].count = 1; // set count to 1 (*numSubjectGroups)++; // increment number of subject groups } } } int main() { // change file name here char filename[] = "grades.csv"; FILE *file, *outputFile; char line[100]; GradeData grades[MAX_GRADES]; int numGrades = 0; float totalGradeSum = 0; int totalNumSubjects = 0; SubjectGroup subjectGroups[MAX_SUBJECTS]; int numSubjectGroups = 0; int isFirstLine = 1; file = fopen(filename, "r"); // in case file does not exist if (file == NULL) { perror("Error opening file"); return -1; } // create output file outputFile = fopen("output.csv", "w"); // in case file does not exist if (outputFile == NULL) { perror("Error creating output file"); return -1; } // read file line by line while (fgets(line, sizeof(line), file)) { if (isFirstLine) { isFirstLine = 0; continue; } // 跳过空行 if (strlen(line) <= 1 || strcmp(line, ",,,,\n") == 0) { continue; } if (line[0] != ',') { // 读取学期名称和同一行的科目数据 Subject newSubject; if (sscanf(line, "%[^,],%[^,],%[^,],%f,%f", grades[numGrades].grade, newSubject.code, newSubject.subjectName, &newSubject.cr, &newSubject.grade) == 5) { grades[numGrades].numSubjects = 0; numGrades++; // 处理该行的科目数据 processSubject(newSubject, grades, &numGrades, &totalGradeSum, &totalNumSubjects, subjectGroups, &numSubjectGroups); } } else { Subject newSubject; if (sscanf(line,",%[^,],%[^,],%f,%f", newSubject.code, newSubject.subjectName, &newSubject.cr, &newSubject.grade) == 4) { processSubject(newSubject, grades, &numGrades, &totalGradeSum, &totalNumSubjects, subjectGroups, &numSubjectGroups); } } } // calculate average grade for each grade for (int i = 0; i < numGrades; i++) { // calculate average grade float sum = 0; for (int j = 0; j < grades[i].numSubjects; j++) { sum += grades[i].subjects[j].grade; // add grade to sum } grades[i].avgGrade = sum / grades[i].numSubjects; // calculate average grade } // write to output file // write grade data fprintf(outputFile, "Grade,Average Grade\n"); // write header for (int i = 0; i < numGrades; i++) // write grade data { fprintf(outputFile, "%s,%.2f\n", grades[i].grade, grades[i].avgGrade); } // write overall average grade fprintf(outputFile, "Overall Average Grade,%.2f\n", totalGradeSum / totalNumSubjects); // write subject group averages fprintf(outputFile, "\nSubject Group,Average Grade\n"); for (int i = 0; i < numSubjectGroups; i++) // write subject group data { fprintf(outputFile, "%s,%.2f\n", subjectGroups[i].subjectGroup, subjectGroups[i].totalGrade / subjectGroups[i].count); } fclose(file); // close input file fclose(outputFile); // close output file return 0; }
修正要点说明
- 新增
processSubject函数,复用科目处理逻辑,避免代码重复,同时确保学期首行和后续行的科目处理逻辑一致。 - 修改学期行的解析逻辑:用
sscanf(line, "%[^,],%[^,],%[^,],%f,%f", ...)同时读取学期名称和科目数据,然后调用processSubject处理该科目。 - 添加空行判断,跳过CSV中的空行,避免无效处理。
正确输出结果
Grade,Average Grade Grade 10 Term 1,3.38 Grade 10 Term 2,3.90 Overall Average Grade,3.67 Subject Group,Average Grade TH,2.75 MA,4.00 SC,3.75 EN,4.00
内容的提问来源于stack exchange,提问作者peemai2004
相关产品推荐
相关产品推荐

