结对编程
结对编程
目录
- 系统简介
- 核心功能
- 小组成员
- 代码
- 算法设计思路
- 运行结果展示
- 结对编程体会
一、系统简介
本系统为中学语文在线考试系统,基于C++语言实现,面向管理员与考生两类用户,提供题库管理、在线考试、自动判分、成绩存档、考试进度断点续考等完整功能。系统采用文件持久化存储数据,适用于课堂小测、课后练习等轻量化考试场景。
二、核心功能
- 管理员题库管理:
管理员通过密码验证后,可对语文题目进行添加、修改、删除、查看,支持单选题、多选题、判断题三种题型,可设置题干、选项、标准答案、分值、题目解析。 - 考生在线考试:
考生可直接进入考试,系统支持10 分钟限时作答,答题过程实时保存进度,支持中途退出后断点续考,也可手动提前交卷或查看剩余时间。 - 自动判分与错题编辑:
交卷后系统自动批改,计算总分与正确率,展示所有错题及对应解析,方便考生查漏补缺。 - 成绩历史记录:
自动保存每次考试的考生姓名、考试时间、得分与满分,支持查看历史成绩列表。 - 数据持久化:
题库、考试进度、历史成绩均以二进制文件形式保存,程序重启数据不丢失。
三、小组成员
2452802
2452808
四、代码
点击查看代码
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <ctype.h>
#define MAX_QUESTIONS 100
#define MAX_OPTION_LEN 100
#define MAX_TEXT_LEN 256
#define MAX_ANSWER_LEN 10
#define MAX_EXPLANATION_LEN 200
#define EXAM_DURATION_SEC 600 // 考试时长:10分钟(600秒)
#define PROGRESS_FILE "exam_progress.dat"
#define SCORE_FILE "scores.dat"
// 题目类型
#define TYPE_SINGLE 1
#define TYPE_MULTI 2
#define TYPE_JUDGE 3
// 题目结构体
typedef struct {
int id; // 题目编号
int type; // 类型:1单选 2多选 3判断
char text[MAX_TEXT_LEN]; // 题干
char options[4][MAX_OPTION_LEN]; // 选项(判断题忽略)
char answer[MAX_ANSWER_LEN]; // 标准答案(单选如"A",多选如"ABD",判断"T"/"F")
float score; // 分值
char explanation[MAX_EXPLANATION_LEN]; // 解析
} Question;
// 考试进度结构体(用于实时保存答案)
typedef struct {
int totalQuestions; // 总题目数
int currentIndex; // 下一题索引(0~totalQuestions)
time_t startTime; // 考试开始时间戳
int durationSec; // 考试时长(秒)
char answers[MAX_QUESTIONS][MAX_ANSWER_LEN]; // 每道题的答案
} ExamProgress;
// 成绩记录结构体
typedef struct {
char name[50];
time_t examTime;
float totalScore;
float fullScore;
} ScoreRecord;
Question g_questions[MAX_QUESTIONS];
int g_questionCount = 0;
// 函数声明
void clearScreen();
void loadQuestions();
void saveQuestions();
void adminMenu();
void addQuestion();
void editQuestion();
void deleteQuestion();
void listQuestions();
void examMenu();
void startExam();
void calculateAndReport(ExamProgress *progress, const char *studentName);
int compareAnswer(const char *userAns, const char *stdAns, int type);
void saveProgress(const ExamProgress *progress);
int loadProgress(ExamProgress *progress);
void deleteProgress();
void saveScoreRecord(const char *name, float score, float fullScore);
void showScoreHistory();
void initSampleQuestions();
// 工具函数:去除字符串首尾空格和换行
void trim(char *str) {
char *start = str;
char *end;
while (isspace((unsigned char)*start)) start++;
if (*start == 0) {
str[0] = '\0';
return;
}
end = start + strlen(start) - 1;
while (end > start && isspace((unsigned char)*end)) end--;
end[1] = '\0';
memmove(str, start, strlen(start) + 1);
}
// 清屏函数
void clearScreen() {
#ifdef _WIN32
system("cls"); // Windows 系统
#else
system("clear"); // Linux/Mac 系统
#endif
}
// 将答案字符串标准化(去空格转大写)
void normalizeAnswer(char *dest, const char *src) {
char temp[MAX_ANSWER_LEN] = {0};
int idx = 0;
for (int i = 0; src[i] && idx < MAX_ANSWER_LEN-1; i++) {
if (!isspace((unsigned char)src[i])) {
temp[idx++] = toupper(src[i]);
}
}
temp[idx] = '\0';
strcpy(dest, temp);
}
int main() {
clearScreen();
// 设置随机种子(暂未用到,但留用)
srand(time(NULL));
loadQuestions(); // 加载题库,若文件不存在则初始化示例题目
int choice;
do {
printf("\n========== 中学语文在线考试系统 ==========\n");
printf("1. 题目管理(管理员)\n");
printf("2. 参加考试(考生)\n");
printf("3. 查看历史成绩\n");
printf("4. 退出系统\n");
printf("请选择操作: ");
scanf("%d", &choice);
getchar(); // 吸收回车
switch (choice) {
case 1:
adminMenu();
break;
case 2:
examMenu();
break;
case 3:
showScoreHistory();
break;
case 4:
printf("感谢使用,再见!\n");
break;
default:
printf("无效选择,请重新输入!\n");
}
} while (choice != 4);
return 0;
}
// 加载题库(二进制文件)
void loadQuestions() {
FILE *fp = fopen("questions.dat", "rb");
if (fp == NULL) {
// 文件不存在,初始化示例题目(中学语文)
initSampleQuestions();
saveQuestions();
return;
}
// 读取题目数量
if (fread(&g_questionCount, sizeof(int), 1, fp) != 1) {
fclose(fp);
initSampleQuestions();
saveQuestions();
return;
}
if (g_questionCount > MAX_QUESTIONS) g_questionCount = MAX_QUESTIONS;
// 读取题目数组
fread(g_questions, sizeof(Question), g_questionCount, fp);
fclose(fp);
}
// 保存题库到二进制文件
void saveQuestions() {
FILE *fp = fopen("questions.dat", "wb");
if (fp == NULL) {
printf("错误:无法保存题库文件!\n");
return;
}
fwrite(&g_questionCount, sizeof(int), 1, fp);
fwrite(g_questions, sizeof(Question), g_questionCount, fp);
fclose(fp);
printf("题库已保存。\n");
}
// 初始化中学语文示例题目
void initSampleQuestions() {
g_questionCount = 5;
// 1. 单选题
g_questions[0].id = 1;
g_questions[0].type = TYPE_SINGLE;
strcpy(g_questions[0].text, "下列哪项不属于《诗经》的艺术特色?");
strcpy(g_questions[0].options[0], "A. 赋比兴手法");
strcpy(g_questions[0].options[1], "B. 重章叠句");
strcpy(g_questions[0].options[2], "C. 以四言为主");
strcpy(g_questions[0].options[3], "D. 格律严整");
strcpy(g_questions[0].answer, "D");
g_questions[0].score = 2.0;
strcpy(g_questions[0].explanation, "《诗经》以四言为主,多用赋比兴和重章叠句,格律严整是唐代近体诗的特点。");
// 2. 多选题
g_questions[1].id = 2;
g_questions[1].type = TYPE_MULTI;
strcpy(g_questions[1].text, "下列哪些是唐宋八大家中唐代的作家?");
strcpy(g_questions[1].options[0], "A. 韩愈");
strcpy(g_questions[1].options[1], "B. 柳宗元");
strcpy(g_questions[1].options[2], "C. 欧阳修");
strcpy(g_questions[1].options[3], "D. 王安石");
strcpy(g_questions[1].answer, "AB");
g_questions[1].score = 3.0;
strcpy(g_questions[1].explanation, "唐宋八大家中唐代两位是韩愈、柳宗元,其余六位为宋代。");
// 3. 判断题
g_questions[2].id = 3;
g_questions[2].type = TYPE_JUDGE;
strcpy(g_questions[2].text, "“床前明月光”中的“床”指的是卧具(床铺)。");
strcpy(g_questions[2].options[0], "A. 正确");
strcpy(g_questions[2].options[1], "B. 错误");
strcpy(g_questions[2].answer, "B");
g_questions[2].score = 1.0;
strcpy(g_questions[2].explanation, "此处“床”指井栏或坐具,并非卧具。");
// 4. 单选题
g_questions[3].id = 4;
g_questions[3].type = TYPE_SINGLE;
strcpy(g_questions[3].text, "“无边落木萧萧下,不尽长江滚滚来”出自杜甫的哪首诗?");
strcpy(g_questions[3].options[0], "A. 《春望》");
strcpy(g_questions[3].options[1], "B. 《登高》");
strcpy(g_questions[3].options[2], "C. 《望岳》");
strcpy(g_questions[3].options[3], "D. 《兵车行》");
strcpy(g_questions[3].answer, "B");
g_questions[3].score = 2.0;
strcpy(g_questions[3].explanation, "该句出自杜甫《登高》,被誉为“七律第一”。");
// 5. 判断题
g_questions[4].id = 5;
g_questions[4].type = TYPE_JUDGE;
strcpy(g_questions[4].text, "《史记》是我国第一部纪传体通史。");
strcpy(g_questions[4].options[0], "A. 正确");
strcpy(g_questions[4].options[1], "B. 错误");
strcpy(g_questions[4].answer, "A");
g_questions[4].score = 1.0;
strcpy(g_questions[4].explanation, "《史记》由司马迁所著,是中国第一部纪传体通史。");
}
// 管理员菜单
void adminMenu() {
clearScreen();
char pwd[20];
printf("请输入管理员密码(默认admin): ");
fgets(pwd, sizeof(pwd), stdin);
trim(pwd);
if (strcmp(pwd, "admin") != 0) {
printf("密码错误,返回主菜单。\n");
return;
}
int choice;
do {
printf("\n===== 题目管理 =====\n");
printf("1. 添加题目\n");
printf("2. 修改题目\n");
printf("3. 删除题目\n");
printf("4. 查看所有题目\n");
printf("5. 返回上一级\n");
printf("请选择: ");
scanf("%d", &choice);
getchar();
switch (choice) {
case 1: addQuestion(); break;
case 2: editQuestion(); break;
case 3: deleteQuestion(); break;
case 4: listQuestions(); break;
case 5: printf("返回主菜单。\n"); break;
default: printf("无效选项!\n");
}
} while (choice != 5);
}
// 添加题目
void addQuestion() {
if (g_questionCount >= MAX_QUESTIONS) {
printf("题库已满,无法添加!\n");
return;
}
Question newQ;
newQ.id = g_questionCount + 1; // 简单自增
printf("请输入题目类型(1单选 2多选 3判断): ");
scanf("%d", &newQ.type);
getchar();
if (newQ.type < TYPE_SINGLE || newQ.type > TYPE_JUDGE) {
printf("无效类型!\n");
return;
}
printf("请输入题干: ");
fgets(newQ.text, MAX_TEXT_LEN, stdin);
trim(newQ.text);
if (newQ.type != TYPE_JUDGE) {
for (int i = 0; i < 4; i++) {
printf("请输入选项%c: ", 'A' + i);
fgets(newQ.options[i], MAX_OPTION_LEN, stdin);
trim(newQ.options[i]);
}
} else {
// 判断题固定选项
strcpy(newQ.options[0], "A. 正确");
strcpy(newQ.options[1], "B. 错误");
}
printf("请输入标准答案(单选如A,多选如ABD,判断T/F): ");
char ansBuf[MAX_ANSWER_LEN];
fgets(ansBuf, MAX_ANSWER_LEN, stdin);
normalizeAnswer(newQ.answer, ansBuf);
printf("请输入分值(例如2.0): ");
scanf("%f", &newQ.score);
getchar();
printf("请输入题目解析: ");
fgets(newQ.explanation, MAX_EXPLANATION_LEN, stdin);
trim(newQ.explanation);
g_questions[g_questionCount] = newQ;
g_questionCount++;
saveQuestions();
printf("题目添加成功!\n");
}
// 修改题目
void editQuestion() {
listQuestions();
int id;
printf("请输入要修改的题目ID: ");
scanf("%d", &id);
getchar();
int idx = -1;
for (int i = 0; i < g_questionCount; i++) {
if (g_questions[i].id == id) {
idx = i;
break;
}
}
if (idx == -1) {
printf("未找到该题目!\n");
return;
}
Question *q = &g_questions[idx];
printf("当前题目:%s\n", q->text);
printf("留空表示不修改。\n");
char buffer[512];
// 修改题干
printf("新题干: ");
fgets(buffer, sizeof(buffer), stdin);
trim(buffer);
if (strlen(buffer) > 0) strcpy(q->text, buffer);
// 修改类型(简单起见只提示)
int newType;
printf("新类型(1单选2多选3判断,0不变): ");
scanf("%d", &newType);
getchar();
if (newType >= 1 && newType <= 3) q->type = newType;
// 修改选项(非判断题)
if (q->type != TYPE_JUDGE) {
for (int i = 0; i < 4; i++) {
printf("新选项%c: ", 'A'+i);
fgets(buffer, sizeof(buffer), stdin);
trim(buffer);
if (strlen(buffer) > 0) strcpy(q->options[i], buffer);
}
}
// 答案
printf("新答案: ");
fgets(buffer, MAX_ANSWER_LEN, stdin);
trim(buffer);
if (strlen(buffer) > 0) normalizeAnswer(q->answer, buffer);
// 分值
printf("新分值: ");
fgets(buffer, sizeof(buffer), stdin);
if (strlen(buffer) > 0) sscanf(buffer, "%f", &q->score);
// 解析
printf("新解析: ");
fgets(buffer, MAX_EXPLANATION_LEN, stdin);
trim(buffer);
if (strlen(buffer) > 0) strcpy(q->explanation, buffer);
saveQuestions();
printf("题目修改成功!\n");
}
// 删除题目
void deleteQuestion() {
listQuestions();
int id;
printf("请输入要删除的题目ID: ");
scanf("%d", &id);
getchar();
int idx = -1;
for (int i = 0; i < g_questionCount; i++) {
if (g_questions[i].id == id) {
idx = i;
break;
}
}
if (idx == -1) {
printf("未找到该题目!\n");
return;
}
for (int i = idx; i < g_questionCount - 1; i++) {
g_questions[i] = g_questions[i+1];
g_questions[i].id = i+1; // 重新编号
}
g_questionCount--;
saveQuestions();
printf("题目删除成功!\n");
}
// 列出所有题目
void listQuestions() {
clearScreen();
if (g_questionCount == 0) {
printf("暂无题目,请先添加。\n");
return;
}
printf("\n===== 当前题库列表 =====\n");
for (int i = 0; i < g_questionCount; i++) {
Question *q = &g_questions[i];
printf("ID:%d | 类型:%s | 分值:%.1f\n", q->id,
q->type == TYPE_SINGLE ? "单选" : (q->type == TYPE_MULTI ? "多选" : "判断"),
q->score);
printf("题干: %s\n", q->text);
if (q->type != TYPE_JUDGE) {
for (int j = 0; j < 4; j++)
printf(" %s\n", q->options[j]);
} else {
printf(" A.正确 B.错误\n");
}
printf("答案: %s\n", q->answer);
printf("解析: %s\n", q->explanation);
printf("------------------------\n");
}
}
// 考生菜单
void examMenu() {
if (g_questionCount == 0) {
printf("当前题库为空,请管理员先添加题目。\n");
return;
}
startExam();
}
// 开始考试
void startExam() {
clearScreen();
ExamProgress progress;
int hasProgress = loadProgress(&progress);
int resume = 0;
if (hasProgress && progress.totalQuestions == g_questionCount) {
printf("检测到未完成的考试,是否继续?(y/n): ");
char ch = getchar();
getchar();
if (ch == 'y' || ch == 'Y') {
resume = 1;
// 检查是否已超时
time_t now = time(NULL);
if (difftime(now, progress.startTime) >= progress.durationSec) {
printf("考试时间已过,将强制交卷判分!\n");
calculateAndReport(&progress, "考生");
deleteProgress();
return;
}
} else {
deleteProgress();
resume = 0;
}
}
if (!resume) {
// 新考试
memset(&progress, 0, sizeof(progress));
progress.totalQuestions = g_questionCount;
progress.currentIndex = 0;
progress.startTime = time(NULL);
progress.durationSec = EXAM_DURATION_SEC;
for (int i = 0; i < g_questionCount; i++) {
progress.answers[i][0] = '\0';
}
saveProgress(&progress);
}
// 开始答题
char input[20];
int lastIndex = progress.currentIndex;
for (int i = lastIndex; i < g_questionCount; i++) {
progress.currentIndex = i; // 当前正要答的题
// 超时检测
time_t now = time(NULL);
double elapsed = difftime(now, progress.startTime);
if (elapsed >= progress.durationSec) {
printf("\n考试时间到!自动交卷。\n");
break;
}
// 显示题目
Question *q = &g_questions[i];
printf("\n[第%d题/%d题] 分值:%.1f\n", i+1, g_questionCount, q->score);
printf("题干: %s\n", q->text);
if (q->type != TYPE_JUDGE) {
for (int j = 0; j < 4; j++) {
printf("%s\n", q->options[j]);
}
} else {
printf("A. 正确 B. 错误\n");
}
printf("请输入答案(多选如ABD,交卷输入Q,查看剩余时间输入T): ");
fgets(input, sizeof(input), stdin);
trim(input);
if (strlen(input) == 1 && toupper(input[0]) == 'Q') {
printf("您已选择提前交卷。\n");
break;
}
if (strlen(input) == 1 && toupper(input[0]) == 'T') {
int remain = progress.durationSec - (int)elapsed;
printf("剩余时间: %d分%d秒\n", remain/60, remain%60);
i--; // 重新回答本题
continue;
}
// 保存答案
normalizeAnswer(progress.answers[i], input);
// 实时保存进度
progress.currentIndex = i+1;
saveProgress(&progress);
}
// 判分并生成报告
calculateAndReport(&progress, "考生");
deleteProgress(); // 考试完成后删除进度文件
}
// 计算总分
float getFullScore() {
float total = 0;
for (int i = 0; i < g_questionCount; i++) {
total += g_questions[i].score;
}
return total;
}
// 自动判分,生成错题报告
void calculateAndReport(ExamProgress *progress, const char *studentName) {
clearScreen();
float totalScore = 0;
int wrongCount = 0;
int wrongIds[MAX_QUESTIONS];
char wrongExplanations[MAX_QUESTIONS][MAX_EXPLANATION_LEN+50];
printf("\n========== 考试成绩报告 ==========\n");
for (int i = 0; i < progress->totalQuestions; i++) {
Question *q = &g_questions[i];
char *userAns = progress->answers[i];
int correct = 0;
if (strlen(userAns) == 0) {
correct = 0; // 未作答
} else {
correct = compareAnswer(userAns, q->answer, q->type);
}
if (correct) {
totalScore += q->score;
} else {
wrongIds[wrongCount] = q->id;
snprintf(wrongExplanations[wrongCount], MAX_EXPLANATION_LEN+50,
"第%d题(%s) 正确答案:%s 您的答案:%s\n解析:%s",
q->id, q->type==TYPE_SINGLE?"单选":(q->type==TYPE_MULTI?"多选":"判断"),
q->answer, strlen(userAns)?userAns:"未作答", q->explanation);
wrongCount++;
}
}
printf("考生: %s\n", studentName);
printf("总分: %.1f / %.1f\n", totalScore, getFullScore());
printf("正确率: %.1f%%\n", totalScore/getFullScore()*100);
if (wrongCount == 0) {
printf("恭喜您,全对!\n");
} else {
printf("错题数量: %d\n", wrongCount);
printf("\n===== 错题解析 =====\n");
for (int i = 0; i < wrongCount; i++) {
printf("%s\n", wrongExplanations[i]);
printf("------------------------\n");
}
}
// 保存成绩记录
saveScoreRecord(studentName, totalScore, getFullScore());
}
// 比较答案是否正确
int compareAnswer(const char *userAns, const char *stdAns, int type) {
char u[MAX_ANSWER_LEN], s[MAX_ANSWER_LEN];
strcpy(u, userAns);
strcpy(s, stdAns);
// 转为大写比较
for (int i = 0; u[i]; i++) u[i] = toupper(u[i]);
for (int i = 0; s[i]; i++) s[i] = toupper(s[i]);
if (type == TYPE_SINGLE || type == TYPE_JUDGE) {
return strcmp(u, s) == 0;
} else if (type == TYPE_MULTI) {
// 多选:比较集合是否相同(排序后比较)
int lenU = strlen(u);
int lenS = strlen(s);
if (lenU != lenS) return 0;
// 简单排序
char uSorted[MAX_ANSWER_LEN], sSorted[MAX_ANSWER_LEN];
strcpy(uSorted, u);
strcpy(sSorted, s);
for (int i = 0; i < lenU-1; i++) {
for (int j = i+1; j < lenU; j++) {
if (uSorted[i] > uSorted[j]) {
char tmp = uSorted[i]; uSorted[i] = uSorted[j]; uSorted[j] = tmp;
}
if (sSorted[i] > sSorted[j]) {
char tmp = sSorted[i]; sSorted[i] = sSorted[j]; sSorted[j] = tmp;
}
}
}
return strcmp(uSorted, sSorted) == 0;
}
return 0;
}
// 保存考试进度(实时保存答案)
void saveProgress(const ExamProgress *progress) {
FILE *fp = fopen(PROGRESS_FILE, "wb");
if (fp == NULL) {
printf("警告:无法保存考试进度!\n");
return;
}
fwrite(progress, sizeof(ExamProgress), 1, fp);
fclose(fp);
}
// 加载考试进度,返回值1表示存在有效进度,0表示无
int loadProgress(ExamProgress *progress) {
FILE *fp = fopen(PROGRESS_FILE, "rb");
if (fp == NULL) return 0;
int ret = fread(progress, sizeof(ExamProgress), 1, fp);
fclose(fp);
return (ret == 1);
}
// 删除进度文件
void deleteProgress() {
remove(PROGRESS_FILE);
}
// 保存成绩记录到文件
void saveScoreRecord(const char *name, float score, float fullScore) {
FILE *fp = fopen(SCORE_FILE, "ab");
if (fp == NULL) {
printf("无法保存成绩记录!\n");
return;
}
ScoreRecord rec;
strncpy(rec.name, name, 49);
rec.name[49] = '\0';
rec.examTime = time(NULL);
rec.totalScore = score;
rec.fullScore = fullScore;
fwrite(&rec, sizeof(ScoreRecord), 1, fp);
fclose(fp);
}
// 显示历史成绩
void showScoreHistory() {
clearScreen();
FILE *fp = fopen(SCORE_FILE, "rb");
if (fp == NULL) {
printf("暂无历史成绩记录。\n");
return;
}
ScoreRecord rec;
printf("\n========== 历史成绩 ==========\n");
int idx = 1;
while (fread(&rec, sizeof(ScoreRecord), 1, fp) == 1) {
char timeStr[30];
struct tm *tm_info = localtime(&rec.examTime);
strftime(timeStr, sizeof(timeStr), "%Y-%m-%d %H:%M:%S", tm_info);
printf("%d. %s %s 得分: %.1f / %.1f\n", idx++, rec.name, timeStr, rec.totalScore, rec.fullScore);
}
fclose(fp);
}
五、算法设计思路
- 题型与数据结构设计:
定义Question结构体统一封装单选、多选、判断三种题型,完整包含题目编号、题型标识、题干内容、选项内容、标准答案、题目分值、题目解析七大核心字段,用单一数据结构适配三类题型,实现数据结构复用与题库数据的统一管理,同时搭配ExamProgress和ScoreRecord两个结构体,分别承载考试答题进度与成绩记录数据,搭建起系统完整的数据存储与流转框架,全程通过全局变量实现模块间数据共享,配合二进制文件完成数据持久化。 - 答案标准化与比对算法:
对用户输入的答案先做去空格+转大写的标准化处理,彻底规避输入空格、大小写不一致导致的误判问题,保障判分公平准确。针对不同题型采用差异化比对逻辑:单选题和判断题直接进行字符串全等匹配,匹配成功即判定为正确;多选题采用字符排序后比对的算法,先将用户答案与标准答案的字符分别排序,再进行字符串匹配,确保ABD、DBA这类顺序不同但选项一致的答案能被判定为正确,大幅提升多选题判分的合理性与严谨性。 - 限时考试与超时控制:
考试启动时实时记录开始时间戳,固定设置10分钟考试时长,考生每作答一道题目前,都会通过当前时间与开始时间的差值计算已用时长,实时校验是否超出规定时限,一旦超过10分钟,系统立即强制触发自动交卷流程,终止答题并启动判分,严格恪守考试限时规则,杜绝超时答题的情况,保证考试流程的规范性。 - 进度断点续考算法:
依托ExamProgress结构体承载考试进度数据,考生答题过程中实时将当前题目序号、已作答的所有题目答案、考试开始时间同步写入专属进度文件,实现答题进度的实时保存。考生重新进入系统时,系统自动读取进度文件,校验题库一致性后,直接恢复上一次的考试状态,精准定位到未完成的题目,实现中途退出后的无缝续考,彻底避免意外退出导致答题数据丢失。 - 成绩统计与错题汇总:
交卷后系统遍历全部题库题目,逐题调用答案比对函数校验对错,同步累加正确题目对应的分值,计算出考生最终总分与考试正确率;与此同时,实时收集所有错题的编号、题型、正确答案、考生作答内容及对应解析,分类汇总错题信息,最终统一生成完整的成绩报告,清晰展示总分、正确率,并逐条呈现错题详情,方便考生复盘纠错。
六、运行结果展示
系统首页

管理员登陆

添加题目

修改题目

删除题目

查看所有题目

考生答题

查看考试剩余时间

考试成绩报告(含错题解析)

查看历史成绩

七、结对编程体会
- 分工协作提升效率:
结对过程中,一人负责核心逻辑(结构体设计、文件读写、判分算法),另一人负责交互界面、菜单流程、输入校验与异常处理,模块边界清晰,开发速度明显快于单人开发。 - 实时纠错减少 Bug:
双人共同审查代码逻辑,如答案比对、多选题排序、进度文件读写等关键环节,及时发现数组越界、字符串未截断、文件打开失败未处理等问题,大幅降低调试成本。 - 思路互补优化设计:
针对考试续考、限时交卷、错题展示等功能,通过讨论不断完善交互逻辑,例如增加输入标准化、续考超时判断、成绩格式化显示,让系统更易用、更健壮。 - 代码规范与可读性提升:
结对过程中统一命名规范、函数拆分粒度与注释风格,避免单人开发时代码混乱、函数臃肿的问题,后期维护与功能扩展更便捷。 - 沟通与团队意识增强:
频繁沟通需求细节与实现方案,学会倾听对方思路并达成共识,在功能取舍、逻辑简化上达成一致,提升了团队协作与问题解决能力。
浙公网安备 33010602011771号