结对编程实验:简易在线考试系统
一、实验基本信息
• 实验名称:第7周 结对编程02 简易在线考试系统开发
• 开发语言:C++
• 小组成员:学号2452821、学号2452822
• 完成时间:2026年4月21日
二、需求分析
- 三大核心功能
◦ 题目管理模块
◦ 考生限时答题模块
◦ 考试结束自动判分模块
- 附加扩展功能
◦ 题目管理:支持单选、多选、判断题的增加、删除、修改、查询
◦ 答题功能:限时倒计时考试、实时保存考生作答答案
◦ 判分与报告:考完立即自动计算总分、正确率,生成带错题详细解析的个人成绩报告
◦ 自由拓展:答案自动格式化校验、基础示例题库预置、操作容错提示
三、整体设计思路
- 数据结构设计
结构体/枚举及其作用:
QuestionType枚举:用于区分题目类型:单选(SINGLE)、多选(MULTIPLE)、判断(JUDGMENT);
Question结构体:用于存储单题完整数据:题目ID、类型、题干、选项、标准答案、题目解析;
UserAnswer结构体:用于记录考生答题记录:对应题目ID、考生答案、是否作答正确;
全局vector
-
功能模块拆分
-
工具辅助函数
◦ trim():自动去除输入空格、统一答案大小写,避免格式输入错误导致误判
- 题目管理子模块
◦ addQuestion():新增题目,自动校验ID不重复
◦ deleteQuestion():根据ID删除指定题目
◦ modifyQuestion():修改已有题目题干、选项、答案、解析
◦ queryQuestion():根据ID查询并展示完整题目详情
◦ manageMenu():题目管理功能菜单页面
- 考试答题子模块
◦ takeExam():限时考试流程,实时刷新剩余考试时间
◦ 逐题展示题干选项、实时记录考生作答
◦ 超时自动强制交卷
- 自动判分与报告模块
◦ 考试结束批量比对考生答案与标准答案
◦ 自动统计总分、得分率
◦ 汇总所有错题,逐条展示用户错误作答、正确答案、官方解析
- 主程序入口
◦ 预置3道基础示例测试题目
◦ 系统主菜单,支持切换题目管理、开始考试、退出系统
-
核心流程逻辑
-
程序启动 → 加载预置测试题目
-
用户选择功能:题目管理 / 开始考试 / 退出
-
题目管理页:完成题目的增删改查操作
-
开始考试:输入限时时长 → 逐题作答、实时倒计时
-
考试结束/时间截止 → 自动判分 → 输出成绩+错题解析报告
-
返回系统主菜单
四、完整程序代码
include
include
include
include
include
include
using namespace std;
// 题目类型枚举
enum QuestionType { SINGLE, MULTIPLE, JUDGMENT };
// 题目结构体
struct Question {
int id;
QuestionType type;
string title;
vector
string answer;
string analysis;
};
// 用户答题记录结构体
struct UserAnswer {
int qid;
string userAns;
bool isCorrect;
};
// 全局题库
vector
// 字符串格式化:去空格、转大写
string trim(const string &s) {
string res;
for (int i = 0; i < s.size(); ++i) {
char c = s[i];
if (!isspace(c))
res += toupper(c);
}
return res;
}
// 新增题目
void addQuestion() {
Question q;
cout << "请输入题目编号:";
cin >> q.id;
bool exist = false;
for (int i = 0; i < questions.size(); ++i) {if (questions[i].id == q.id) {exist = true;break;}
}
if (exist) {cout << "编号已存在!\n";return;
}int type;
cout << "题目类型 (1单选 2多选 3判断):";
cin >> type;
q.type = (type == 1 ? SINGLE : (type == 2 ? MULTIPLE : JUDGMENT));
cin.ignore();cout << "题干:";
getline(cin, q.title);// 判断题固定选项
if (q.type == JUDGMENT) {q.options.push_back("A. 对");q.options.push_back("B. 错");
} else {for (int i = 0; i < 4; ++i) {string opt;cout << "选项" << (char)('A' + i) << ":";getline(cin, opt);q.options.push_back(string(1, 'A' + i) + ". " + opt);}
}cout << "正确答案(如A、AC):";
getline(cin, q.answer);
q.answer = trim(q.answer);cout << "解析:";
getline(cin, q.analysis);questions.push_back(q);
cout << "添加成功!\n";
}
// 删除题目
void deleteQuestion() {
int id;
cout << "请输入要删除的题目编号:";
cin >> id;
vector
for (int i = 0; i < questions.size(); ++i) {
if (questions[i].id != id)
newQs.push_back(questions[i]);
}
if (newQs.size() != questions.size()) {
questions = newQs;
cout << "删除成功!\n";
} else {
cout << "题目不存在!\n";
}
}
// 修改题目
void modifyQuestion() {
int id;
cout << "请输入要修改的题目编号:";
cin >> id;
int idx = -1;
for (int i = 0; i < questions.size(); ++i) {
if (questions[i].id == id) {
idx = i;
break;
}
}
if (idx == -1) {
cout << "题目不存在!\n";
return;
}
cin.ignore();
cout << "新题干(原:" << questions[idx].title << "):";
getline(cin, questions[idx].title);if (questions[idx].type != JUDGMENT) {for (int i = 0; i < questions[idx].options.size(); ++i) {cout << "新选项" << (char)('A' + i) << "(原:" << questions[idx].options[i] << "):";getline(cin, questions[idx].options[i]);}
}cout << "新正确答案(原:" << questions[idx].answer << "):";
string ans;
getline(cin, ans);
questions[idx].answer = trim(ans);cout << "新解析(原:" << questions[idx].analysis << "):";
getline(cin, questions[idx].analysis);
cout << "修改成功!\n";
}
// 查询题目
void queryQuestion() {
int id;
cout << "请输入要查询的题目编号:";
cin >> id;
int idx = -1;
for (int i = 0; i < questions.size(); ++i) {
if (questions[i].id == id) {
idx = i;
break;
}
}
if (idx == -1) {
cout << "题目不存在!\n";
return;
}
cout << "\n题干:" << questions[idx].title << "\n";
for (int i = 0; i < questions[idx].options.size(); ++i) {
cout << questions[idx].options[i] << "\n";
}
cout << "正确答案:" << questions[idx].answer << "\n解析:" << questions[idx].analysis << "\n";
}
// 题目管理菜单
void manageMenu() {
while (true) {
cout << "\n===== 题目管理 =====\n";
cout << "1. 添加题目 2. 删除题目 3. 修改题目 4. 查询题目 5. 返回\n";
int op;
cin >> op;
if (op == 5) break;
switch(op) {
case 1: addQuestion(); break;
case 2: deleteQuestion(); break;
case 3: modifyQuestion(); break;
case 4: queryQuestion(); break;
default: cout << "无效选项!\n";
}
}
}
// 开始考试答题
void takeExam() {
if (questions.empty()) {
cout << "题库为空,请先添加题目!\n";
return;
}
int timeLimit;
cout << "请输入考试时间(分钟):";
cin >> timeLimit;
time_t start = time(NULL);
time_t endTime = start + timeLimit * 60;vector<UserAnswer> userAnswers;
int score = 0;for (int i = 0; i < questions.size(); ++i) {Question q = questions[i];time_t now = time(NULL);if (now >= endTime) {cout << "\n考试时间到!自动交卷。\n";break;}int leftSec = (int)(endTime - now);cout << "\n剩余时间:" << leftSec / 60 << "分" << leftSec % 60 << "秒\n";cout << "题号" << q.id << ":" << q.title << "\n";for (int j = 0; j < q.options.size(); ++j) {cout << q.options[j] << "\n";}string ans;cout << "你的答案:";cin >> ans;ans = trim(ans);bool correct = (ans == q.answer);if (correct) score += 10;UserAnswer ua;ua.qid = q.id;ua.userAns = ans;ua.isCorrect = correct;userAnswers.push_back(ua);
}// 成绩报告输出
cout << "\n===== 考试结束 =====\n";
int totalScore = questions.size() * 10;
cout << "总分:" << score << "/" << totalScore << "\n";
cout << "正确率:" << score * 100.0 / totalScore << "%\n";cout << "\n错题解析:\n";
for (int i = 0; i < userAnswers.size(); ++i) {UserAnswer ua = userAnswers[i];if (!ua.isCorrect) {int qidx = -1;for (int j = 0; j < questions.size(); ++j) {if (questions[j].id == ua.qid) {qidx = j;break;}}if (qidx != -1) {cout << "题号" << ua.qid << ":\n";cout << "你的答案:" << ua.userAns << " 正确答案:" << questions[qidx].answer << "\n";cout << "解析:" << questions[qidx].analysis << "\n\n";}}
}
}
// 主函数与系统入口
int main() {
// 预置3道示例题目
Question q1;
q1.id = 1;
q1.type = SINGLE;
q1.title = "C++中哪个是输出语句?";
q1.options.push_back("A. printf");
q1.options.push_back("B. cout");
q1.options.push_back("C. scanf");
q1.options.push_back("D. cin");
q1.answer = "B";
q1.analysis = "cout是C++标准输出流对象";
questions.push_back(q1);
Question q2;
q2.id = 2;
q2.type = JUDGMENT;
q2.title = "C++中int类型占4字节。";
q2.options.push_back("A. 对");
q2.options.push_back("B. 错");
q2.answer = "A";
q2.analysis = "标准环境下int占4字节";
questions.push_back(q2);Question q3;
q3.id = 3;
q3.type = MULTIPLE;
q3.title = "以下哪些是C++的关键字?";
q3.options.push_back("A. if");
q3.options.push_back("B. for");
q3.options.push_back("C. then");
q3.options.push_back("D. while");
q3.answer = "ABD";
q3.analysis = "then不是C++关键字";
questions.push_back(q3);// 系统主循环
while (true) {cout << "\n===== 简易在线考试系统 =====\n";cout << "1. 题目管理 2. 开始考试 3. 退出\n";int op;cin >> op;switch(op) {case 1: manageMenu(); break;case 2: takeExam(); break;case 3: cout << "退出系统\n"; return 0;default: cout << "无效选项!\n";}
}
return 0;
}
五、程序运行效果截图
- 题目查询功能运行演示

- 限时考试答题功能运行演示

六、结对编程过程与心得体会
结对分工与流程
本次结对编程严格按照实验要求流程完成:
-
前期方案讨论:两人共同梳理需求、拆分功能模块、敲定结构体设计、确认整体代码架构;
-
第一轮角色分工:本人负责编写基础框架、题目管理模块;搭档全程旁听、实时审核代码、指出逻辑漏洞与输入bug;
-
第二轮交换角色:搭档完善考试计时、自动判分、错题报告模块;本人进行代码复查与优化;
-
共同联调:两人一起修复cin和getline混用导致的换行残留bug、完善答案大小写容错、优化用户交互提示;
-
最终整体测试、验证全部功能正常运行。
实验收获与体会
-
结对编程优势:双人协作极大减少了单人编码的粗心bug,审核角色可以跳出编码细节,更快发现逻辑缺陷,代码质量和开发效率都明显提升;
-
技术能力提升:熟练掌握了C++结构体、vector容器、时间函数的综合使用;理解了限时程序的计时逻辑、字符串格式化校验、批量数据比对判分的实现思路;
-
工程思维成长:明白了小型项目模块化拆分的重要性,每个功能单独封装函数,代码可读性、可维护性大幅提高;
-
不足与优化方向:本次为控制台简易版本,后续可以拓展为文件持久化保存题库、增加用户登录权限、打乱题目顺序、保存历史考试记录等进阶功能。
注:本次实验搭档学号:2452822(全程参与本次结对开发与代码审核工作)
