C语言如何读取.dat文件学生数据并拆分存入不同数组
C语言读取.dat学生答题数据拆分存储实现方案
核心存储结构定义
不需要零散给每道题单独建数组,用下标对齐的一维、二维数组存储即可,同一索引对应同一个学生的所有属性,后续判分遍历效率更高:
- 姓名数组:
char name[最大学生数][姓名最大长度],存每个学生的姓名字符串 - 学号数组:
char stu_id[最大学生数][学号最大长度],存每个学生的学号字符串 - 答案二维数组:
char ans[最大学生数][选择题总数],其中ans[i][j]代表第i个学生第j道题的作答结果,天然适配逐题比对标准答案的判分需求 - 额外定义一个计数器,记录实际读取到的学生总数,避免遍历数组时读到未赋值的空数据
读取与拆分代码实现
直接用fopen、fscanf按固定格式匹配读取即可,不需要手动做字符串分割,注意做好异常校验:
#include <stdio.h> #include <stdlib.h> // 常量定义,后续调整题量、学生上限直接改这里就行 #define MAX_STU_NUM 100 #define MCQ_TOTAL 10 #define NAME_MAX_LEN 20 #define ID_MAX_LEN 10 int main() { // 初始化存储数组 char name[MAX_STU_NUM][NAME_MAX_LEN]; char stu_id[MAX_STU_NUM][ID_MAX_LEN]; char ans[MAX_STU_NUM][MCQ_TOTAL]; int stu_cnt = 0; // 打开文件,必须做返回值校验 FILE *fp = fopen("stu_data.dat", "r"); if (fp == NULL) { perror("文件打开失败"); exit(EXIT_FAILURE); } // 循环读取直到文件结束或达到存储上限 while (stu_cnt < MAX_STU_NUM) { // 先读取姓名、学号两个无空格字符串 int read_ret = fscanf(fp, "%s %s", name[stu_cnt], stu_id[stu_cnt]); // 读不到2个字段说明到文件尾/数据格式损坏,直接跳出循环 if (read_ret != 2) break; // 逐道读取选择题答案 for (int q_idx = 0; q_idx < MCQ_TOTAL; q_idx++) { // 注意%c前面必须加空格:自动跳过所有空白符(空格、换行、制表符),避免把间隔符读成答案 read_ret = fscanf(fp, " %c", &ans[stu_cnt][q_idx]); if (read_ret != 1) { fprintf(stderr, "第%d位学生答题数据缺失\n", stu_cnt + 1); fclose(fp); exit(EXIT_FAILURE); } // 可选:校验答案合法性,只允许A/B/C/D if (ans[stu_cnt][q_idx] < 'A' || ans[stu_cnt][q_idx] > 'D') { fprintf(stderr, "第%d位学生第%d题答案非法\n", stu_cnt + 1, q_idx + 1); fclose(fp); exit(EXIT_FAILURE); } } // 如果你的数据中学生记录之间用中文分号之类的非空白分隔符(比如示例里john记录后接;Paul),在这里加一行读走分隔符即可: // fscanf(fp, " %*c"); // %*c表示读入一个字符但不存储,自动跳过前面的空白 stu_cnt++; } fclose(fp); // 后续判分逻辑示例 char standard_ans[MCQ_TOTAL] = {'A','C','D','B','C','A','B','D','C','A'}; // 替换成实际标准答案 int score[MAX_STU_NUM] = {0}; for (int i = 0; i < stu_cnt; i++) { for (int q = 0; q < MCQ_TOTAL; q++) { if (ans[i][q] == standard_ans[q]) { score[i] += 10; // 按每题分值累加即可 } } // 按需求输出结果即可 printf("姓名:%s 学号:%s 成绩:%d\n", name[i], stu_id[i], score[i]); } return 0; }
关键避坑点
- 读取单个字符答案时,
fscanf的格式串里%c前必须加空格,否则会把答案之间的空格、行尾换行符当成有效答案读入,直接导致所有答案错位。 - 所有字符串数组的长度要比实际最长内容多1位,预留C语言字符串必需的结束符
\0位置,避免出现内存越界。 - 必须校验
fscanf的返回值,遇到文件损坏、格式不符的情况直接终止,不要让脏数据流入后续判分逻辑。 - 不需要为每道选择题单独创建数组,二维数组的索引访问方式写判分逻辑更简洁,后续调整题量只需要修改常量定义即可,不用改一堆数组声明。
内容的提问来源于stack exchange,提问作者Rafsan
相关产品推荐
相关产品推荐

