C语言课程设计:单项选择题标准化考试系统 | JorbanS

本文主要是介绍C语言课程设计:单项选择题标准化考试系统 | JorbanS,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

导入时图片加载异常,故本文图例和图片均已隐去,只保留了功能结构图。

程序设计环境:Visual Studio Code, Sublime 4。

一、课程设计任务

1.1课题背景

本项目旨在开发一个单项选择题标准化考试系统,能够方便地管理试题库,抽取试题,进行答题和自动判卷。该系统的实现需要借助计算机编程技术和文件操作技术,以实现试题库的管理和试题的抽取、答题和判卷等功能。考生可以通过该系统进行模拟考试,系统能够根据考生的答案和标准答案的对比,自动判卷并给出成绩,为考生提供便利和准确的考试评估。

该系统的开发旨在提高考试管理的效率和准确性,同时为考生提供更加便捷和准确的考试体验。同时,该系统也可以应用于各种类型的考试,如教育机构的入学考试、职业资格考试等,具有广泛的应用前景和市场价值。

本系统完全独立开发,力求使系统功能简洁明了,且功能齐全且易于操作。

1.2目的背景和意义

开发这个项目的主要目的是提供一个方便、高效、可靠的单项选择题标准化考试系统,以解决传统考试方式中存在的一些问题,如试题管理不便、考试效率低下、判卷难度大等。

提高考试管理的效率和准确性。传统的考试方式中,试题的管理、抽取、答题和判卷等环节都需要人工操作,存在较大的误差和不确定性。而该系统能够实现试题库的自动管理和试题的自动抽取、判卷等功能,大大提高了考试管理的效率和准确性。

提高考试的公平性和准确性。通过该系统进行考试,每个考生所抽取的试题都是随机的,试题的难度和内容分布也是随机的,因此可以有效避免试题的不公平性和偏差性。同时,系统能够自动判卷,减少了人工判卷所产生的误差和主观性,提高了考试的准确性和公正性。

提高考生的答题效率和体验。传统考试方式中,考生需要在试卷上标出答案,容易出现漏填、误填等情况,同时也需要手动计算分数和核对答案,效率低下。而该系统能够自动记录考生答案并自动判卷,大大提高了答题效率和准确性,同时也提供了更加便捷和舒适的考试体验。

具有广泛的应用前景和市场价值。考试是社会各行业和领域中必不可少的一环,如教育、招聘、职业资格认证等。该系统具有广泛的应用前景和市场价值,可以为各种类型的考试提供方便、快捷、准确的考试管理和评估服务,为社会提供更加高效、公正、科学的考试方式,对于提高社会整体素质和人才培养也具有积极的推动作用。

1.3项目开发的目标

      集成题库管理系统和单项选择题答题,采用计算机对学生答题进行管理,进一步提高办学效益和现代化水平。帮助广大教师提高工作效率,实现学生答题工作流程的系统化、规范化和自动化。

二、总体设计方案

2.1单项选择题标准化考试系统的功能

如图1所示,打印成绩信息,打印题库信息,增、删、改题目,学生答题及判卷,学生和老师权限组分离,读写成绩信息和题库信息。

图 1

2.2模块设

2.2.1主模块

功能:显示欢迎语,建立学生成绩和题库的链表头结点,并文件中读取信息,建立链表,同时返回已答题学生的数量和题目数量,便于后续操作。

2.2.2字符转换模块

             功能:统一输入的选项字符ABCDabcd为大写的ABCD

2.2.3选择随机题目模块

             功能:挑选随机不重复的题目,返回题目指针。

2.2.4清空题目状态信息模块

             功能:初始化所有题目状态为未使用状态。

2.2.5读取题目模块

             功能:从文件中读取所有题目,返回题库中题目数量。

2.2.6读取学生成绩模块

             功能:从文件中读取所有学生成绩信息,返回已答题学生数量。

2.2.7保存题目模块

             功能:读取题库链表所有题目,保存到文件中。

2.2.8保存学生成绩模块

             功能:读取学生链表中所有学生信息,保存到文件中。

2.2.9打印学生成绩模块

             功能:打印所有学生的信息和对应的成绩、题目数量。

2.2.10打印题库题目模块

             功能:打印题库中的所有题目。

2.2.11题目删除模块

             功能:删除不需要的题目,回收内存。

2.2.12题目修改模块

             功能:提供待修改题目信息,便于对比修改题目。

2.2.13增加题目模块

             功能:向题库中增加新题。

2.2.14教师管理模块

             功能:题库打印,题库管理,学生成绩查看。

2.2.15教师登录模块

             功能:验证管理员资格。

2.2.16学生登录答题模块

             功能:学生登录,抽取题目,答题,判题。

2.3所用结构体格式

typedef struct _Student { // 学生成绩链表

        char name[20], idx[20]; // 存储姓名、学号

        int grade, numQue; // 存储分数、答题数量

        _Student* next; // next指针

} Stu;

typedef struct _Problems { // 问题链表

        int idx, state; // 存储学号、状态(是否被使用过)

        char q[50], op[4][25], ans; // 存储问题、四个选项、答案

        _Problems* next; // next指针

} Pro;

2.4所用到的头文件

#include <stdio.h>

#include <string.h>

#include <stdlib.h>

#include <time.h>

#include <windows.h>

2.5 所用到的宏定义

#define cls system("cls") // 便于之后的清屏操作

#define endl puts("") // 便于之后的换行操作

#define title(x) printf("============%s============\n", x) // 便于之后的标题操作

三、详细设计/具体实现

程序开发分为三个部分:界面UI、功能主体(链表存学生信息和题库)和主函数。

3.1字符转换

所用函数:

char convert(char c)

实现功能的方法分析:

如图2所示,将输入的一个字符统一转换为大写字母,用if语句判断,如果该字符是小写字母,则将其转换为对应的大写字母,如果该字符不是小写字母,则保持原样变。

3.2随机抽取问题

所用函数:

 Pro* getRandomProblem(Pro* proHead, int countProblems)

实现功能的方法分析:

如图3所示,从一组问题中随机抽取一个尚未回答过的问题。使用srand(time(NULL));语句来初始化随机数种子,以确保每次随机的结果都不相同,其中结构体的state变量表示是否被使用的状态。使用rand() % countProblems + 1这个语句来生成一个随机数,该随机数的范围是1 ~ countProblems,其中countProblems表示问题的总数。使用for循环遍历问题链表,寻找与随机数所对应的问题。循环中的变量point表示问题链表中的当前节点。如果找到了与随机数所对应的问题,再进一步判断该问题是否已经被回答过。如果该问题已经被回答过,则跳出内层循环,重新生成随机数;否则,返回该问题的指针。如果没有找到与随机数所对应的问题,则继续生成随机数,直到找到为止。

3.3清空题目状态

所用函数:

void clearState(Pro* proHead, int countProblems)

实现功能的方法分析:

如图3所示,清空所有问题的状态,使用for循环遍历问题链表,从链表的第一个节点开始遍历。循环中的变量point表示问题链表中的当前节点。对于每个节点,将其状态标志state设置为0,表示该问题尚未被回答过。循环继续遍历下一个节点,直到遍历完整个链表为止。

3.4从文件中读取题库

所用函数:

 int readProblems(Pro* proHead)

实现功能的方法分析:

如图5所示,从文件中读取一组问题,将其存储到链表中,并返回问题的总数。打开test.txt文件,使用fopen("test.txt", "r")语句打开一个只读文件流。从文件中读取问题总数,使用fscanf(fpReadProblems, "%s", cnt)和for循环将字符串cnt中的数据转换为整数类型。依次读取每个问题,并将其存储到链表中,使用malloc()动态分配内存空间。读取问题的题目、选项和答案,使用fscanf()语句读取。给问题赋予一个唯一的索引值idx。将问题插入到链表中。关闭文件流,使用fclose()语句关闭文件,返回问题的总数。

3.5从文件中读取学生成绩

所用函数:

 int readStudents(Stu* stuHead)

实现功能的方法分析:

如图6所示,打开stu.txt文件,使用fopen("stu.txt", "r")语句打开一个只读文件流。从文件中读取学生总数,使用fscanf(fpReadStudents, "%s", cnt)和for循环将字符串cnt转换为整数类型。忽略文件中的表头,使用fscanf(fpReadStudents, "%*s%*s%*s%*s")语句跳过表头。依次读取每个学生的成绩,并将其存储到链表中,使用malloc()动态分配内存空间。读取学生的姓名、学号、成绩和回答问题的数量,使用fscanf()语句读取。将学生插入到链表中。关闭文件流,使用fclose()语句关闭文件。返回学生的总数。

3.6将链表中的题目信息保存到文件中

所用函数:

void saveProblems(Pro* proHead, int countProblems)

实现功能的方法分析:

如图7所示,打开一个名为test.txt的文件,并指定以只写方式打开,使用fopen("test.txt", "w")语句。写入问题总数信息,使用fprintf(fpWriteProblems, "当前有题目:%d个\n\n", countProblems)语句将问题总数写入文件中。遍历问题链表,使用for循环遍历链表中的每个问题,对于每个问题,使用fprintf()语句将其题目、选项和答案写入文件中。关闭文件,使用fclose(fpWriteProblems)语句关闭文件。将链表头指针的next属性设置为NULL,表示链表已经被清空。

3.7将链表中的学生信息保存到文件中

所用函数:

 void saveStudents(Stu* stuHead, int countStudents)

实现功能的方法分析:

如图8所示,打开一个名为stu.txt的文件,并指定以只写方式打开,使用fopen("stu.txt", "w")语句。写入学生总数信息,使用fprintf(fpSaveStudents, "总计有%d个学生已答题\n\n", countStudents)语句将学生总数写入文件中。写入学生成绩表头,使用fprintf(fpSaveStudents, "姓名\t学号\t成绩\t题目\n")语句写入表头。遍历学生成绩链表,使用for循环遍历链表中的每个学生,对于每个学生,使用fprintf()语句将其姓名、学号、成绩和回答的问题数量写入文件中。将链表头指针的next属性设置为NULL,表示链表已经被清空。关闭文件,使用fclose(fpSaveStudents)语句关闭文件。

3.8 输出所有题目

所用函数:

 void outputProblems(Pro* proHead, int countProblems)

实现功能的方法分析:

如图9所示,清屏,使用cls语句清屏。输出表头,使用title(" 题库题目 ")和endl语句输出表头。遍历问题链表,使用for循环遍历链表中的每个问题,对于每个问题,使用printf()语句将其索引、题目、选项和答案输出到屏幕上。输出问题总数,使用printf("当前有题目:%d个\n\n", countProblems)语句输出问题总数。输出表尾,使用title(" 题库题目 ")语句输出表尾。

3.9输出所有学生成绩

所用函数:

 void outputStudents(Stu* stuHead, int countStudents)

实现功能的方法分析:

如图10所示,清屏,使用cls语句清屏。输出表头,使用title(" 学生成绩表 ")和endl语句输出表头,并通过puts()语句输出表格的列名。遍历学生成绩链表,使用for循环遍历链表中的每个学生,对于每个学生,使用printf()语句将其姓名、学号、成绩和回答的问题数量输出到屏幕上。输出学生总数,使用printf("已有%d人完成答题\n", countStudents)语句输出学生总数。输出表尾,使用title("===========")语句输出表尾。

3.10删除指定序号的题目

所用函数:

 void deleteProblem(Pro* proHead, int toBeDeleted)

实现功能的方法分析:

如图11所示,从链表头开始遍历链表,使用for循环遍历链表中的每个问题,对于每个问题,使用if语句判断其索引是否等于待删除的索引。如果找到了待删除的问题,使用last->next = point->next语句将待删除的问题从链表中删除,同时使用free()函数释放该问题所占用的内存空间。如果没有找到待删除的问题,继续遍历下一个问题。

3.11编辑指定序号的题目

所用函数:

 int editProblem(Pro* proHead, int countProblems, int problemToBeEdited)

实现功能的方法分析:

如图12所示,清屏,使用cls语句清屏。输出表头,使用title(" 变更题目 ")和endl语句输出表头,并使用puts()语句输出编辑操作的选项。读取用户输入,使用scanf()函数读取用户选择的编辑操作。如果用户选择退出,使用return countProblems语句返回问题总数。如果用户选择删除问题,使用deleteProblem()函数删除指定问题,并使用countProblems语句将问题总数减1,然后使用return countProblems语句返回问题总数。如果用户选择修改问题,使用for循环遍历链表中的每个问题,找到指定的问题。对于指定的问题,使用printf()语句输出其题目和选项,然后使用scanf()函数读取用户输入的修改信息。如果用户输入的修改信息不为next,则使用相关的字符串处理函数修改问题的题目或选项,使用strcmp()函数进行字符串比较和strcpy()函数进行字符串复制。对于指定的问题,使用printf()语句输出其答案,然后使用scanf()函数读取用户输入的修改信息。如果用户输入的修改信息不为next,则修改问题的答案。使用return countProblems语句返回问题总数。

3.12新增题目

所用函数:

 int (Pro* proHead, int countProblems)

实现功能的方法分析:

如图13所示,清屏,使用cls语句清屏。输出表头,使用title(" 新增题目 ")和endl语句输出表头。动态分配内存,使用malloc()函数动态分配一个新的问题节点addNewProblems。使用scanf()函数读取用户输入的新问题的题目。使用for循环读取用户输入的新问题的选项,并将其存储到addNewProblems->op[i]中。使用sprintf()和strcpy()函数将选项和选项的标号合并起来,然后将其存储到addNewProblems->op[i]中。使用getchar()函数读取用户输入的新问题的答案,并使用convert()函数将其转换为大写字母,然后将其存储到addNewProblems->ans中。将新问题节点插入到链表头部,使用addNewProblems->next = proHead->next和proHead->next = addNewProblems语句。将问题总数加1,使用countProblems ++语句。使用return countProblems语句返回问题总数。

3.13管理题库

所用函数:

 int manageProblems(Pro* proHead, int countProblems)

实现功能的方法分析:

如图14所示,清屏,使用cls语句清屏。输出表头,使用title(" 管理题目 ")和endl语句输出表头,并使用puts()语句输出管理操作的选项。读取用户输入,使用scanf()函数读取用户选择的管理操作。如果用户选择退出,使用return countProblems语句返回问题总数。如果用户选择更改题目,使用outputProblems()函数输出问题列表,并使用scanf()函数读取用户输入的待编辑问题的编号,然后使用editProblem()函数编辑指定问题,并使用返回的问题总数更新countProblems的值。如果用户选择新增题目,使用addProblem()函数向链表中添加新问题,并使用返回的问题总数更新countProblems的值。使用return countProblems语句返回问题总数。

3.14老师管理界面

所用函数:

 int startTeacher(Stu* stuHead, Pro* proHead, int countStudents, int countProblems)

实现功能的方法分析:

如图15所示,使用while (true)循环,直到用户输入正确的账号和密码为止。清屏,使用cls语句清屏。输出表头,使用title(" 教师登录 ")和endl语句输出表头,并使用scanf()函数读取用户输入的账号和密码。如果用户输入的账号和密码正确,使用break语句跳出循环。如果用户输入的账号和密码错误,使用cls语句清屏,输出错误提示信息,使用Sleep()函数暂停程序执行1.5秒后重新进入循环。使用while (true)循环,直到用户选择退出操作为止。清屏,使用cls语句清屏。输出表头,使用title(" 教师管理 ")和endl语句输出表头,并使用puts()语句输出管理操作的选项。读取用户输入,使用scanf()函数读取用户选择的管理操作。如果用户选择退出,使用return countProblems语句返回问题总数。如果用户选择显示所有题目,使用outputProblems()函数输出问题列表,然后使用scanf()函数读取任意字符,等待用户输入任意字符后返回操作界面。如果用户选择管理题库,使用manageProblems()函数管理题库,并使用返回的问题总数更新countProblems的值。如果用户选择学生成绩查看,使用outputStudents()函数输出学生列表,然后使用scanf()函数读取任意字符,等待用户输入任意字符后返回操作界面。使用saveProblems()函数保存题库数据,使用readProblems()函数重新读取题库数据。

3.15学生答题界面

所用函数:

 void startStudent(Stu* stuHead, Pro* proHead, int countStudents, int countProblems)

实现功能的方法分析:

如图16所示,动态分配内存,使用malloc()函数动态分配一个新的学生节点addNewStudent。清屏,使用cls语句清屏。输出表头,使用title(" 考生登录 ")和endl语句输出表头,并使用scanf()函数读取用户输入的姓名和学号。使用clearState()函数清除所有问题的状态信息。清屏,使用cls语句清屏。输出表头,使用title(" 考生答题 ")和endl语句输出表头,并使用scanf()函数读取用户输入的要抽取的题目数。使用for循环随机抽取题目,并使用getRandomProblem()函数从题库中随机抽取题目。输出题目和选项,并使用scanf()函数读取用户选择的答案,并使用convert()函数将其转换为大写字母。如果用户选择的答案与题目的正确答案相同,使用countRightProblems++语句将答对题目数加1。计算成绩,使用addNewStudent->grade = (double)(countRightProblems * 100) / countSelectedProblems语句计算学生得分,并使用addNewStudent->numQue = countSelectedProblems语句存储学生答题数目。清屏,使用cls语句清屏。输出表头,使用title(" 答题结果 ")和endl语句输出表头,并输出答对题目数和学生得分。使用saveStudents()函数保存学生数据,使用readStudents()函数重新读取学生数据。使用printf()函数输出提示信息,等待用户输入任意字符后返回操作界面。

四、课程设计结果

4.1主界面菜单

如图17所示,主菜单界面,共有保存退出、教师登录、学生登陆三个功能模块可供选择。

4.2教师登录界面

如图18所示,教师登录界面需要输入管理员账号和密码,默认账号为admin,默认密码为admin。

4.3教师管理界面

如图19所示,教师管理页面有四项选择,分别为退出、显示所有题目、管理题库和学生成绩查看。

4.4题库打印界面

如图20所示,教师可以打印题库中所有题目的信息。

4.5成绩打印界面

如图21所示,教师可以直接打印所有已答学生的信息。

4.6题库管理界面(增删改)

如图22、图23所示,教师管理功能涵盖更改题目、新增题目选项,其中更改题目先输入题目序号后,可进行删除和修改,修改可修改题目的标题、四个选项和答案。

4.7学生成绩信息存储到文件中

如图24所示,可以在同目录下的stu.txt文件中直接查看所有已答学生的数据。

4.8题目存储到文件中

如图25所示,可以在同目录下的test.txt文件中直接查看所有题目。

五、课程设计总结

C语言课程设计是一个很重要的环节,它可以帮助学生巩固所学的C语言知识,提高编程能力和实践能力。它通常要求学生独立完成一个小型的程序,要求程序具有一定的实用性和可行性,并且能够通过编译和测试。

选题是C语言课程设计的关键之一,学生可以根据自己的兴趣和爱好选择一个适合自己的主题。在选定了课程设计的主题之后,需要考虑程序的设计思路。可以先画出流程图和算法,然后再根据算法编写代码。在编写代码时,需要注意代码的规范性和可读性,要遵循一定的编程规范,例如命名规范、缩进规范等等。同时,还需要注意代码的注释,方便他人阅读和理解。在完成代码编写后,需要进行调试和测试,确保程序能够正常运行。在完成程序设计后,需要编写相关文档,包括程序说明、使用说明、设计思路、测试结果等等,以方便其他人理解和使用该程序。在其中,通过反复的debug,加深了对C语言链表的认识,更深入地认识到了链表的优越性。

在完成课程设计后,需要对整个过程进行总结和反思,分析自己在设计和编程过程中遇到的问题和解决方法,以及自己在编程能力和实践能力方面的提高程度。C语言课程设计可以帮助更好地理解和掌握C语言知识,提高编程能力和实践能力,是一个非常有意义的学习和实践过程。

附录:附源程序

//课题7、单项选择题标准化考试系统
//在磁盘上创建一个test.txt文件,使用记事本打开后先写入40道单选题和相应的选项和正确答案。再编写一个单项选择题标准化考试系统,该系统功能要求:
//A、用文件保存试题库。(每个试题包括题干、4个备选答案、标准答案)。
//B、试题录入、修改和删除。
//C、试题抽取:每次从试题库中可以随机抽出N道题(N由键盘输入)。
//D、考生答题:用户抽取N道试题进行答题,键盘输入每道题的答案。
//E、自动判卷:系统可根据用户答案与标准答案的对比实现判卷并给出成绩。
//系统操作过程中能够正确读取和更新试题文件,并进行正常的试题管理、抽取、答题和判卷操作,该过程在控制台中显示,人机交互方便。#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <time.h>
#include <windows.h>
#define cls system("cls")
#define endl puts("")
#define title(x) printf("============%s============\n", x)typedef struct _Student { // 学生成绩链表存储char name[20], idx[20];int grade, numQue;_Student* next;
} Stu;typedef struct _Problems { // 问题链表存储int idx, state;char q[50], op[4][25], ans;_Problems* next;
} Pro;char convert(char c) { // 统一小写字母为大写字母if ('a' <= c && c <= 'z') c += 'A' - 'a';return c;
}Pro* getRandomProblem(Pro* proHead, int countProblems) { // 抽取随机问题while (true) {srand(time(NULL));int selectedProblem = rand() % countProblems + 1;for (Pro* point = proHead->next; point != NULL; point = point->next) {if (point->idx == selectedProblem) {if (point->state) { // 判重break;} else {return point;}}}}
}void clearState(Pro* proHead, int countProblems) { // 清空题目状态for (Pro* point = proHead->next; point != NULL; point = point->next) {point->state = 0;}
}int readProblems(Pro* proHead) { // 读取题目FILE *fpReadProblems = fopen("test.txt", "r");char cnt[20];int countProblems = 0;fscanf(fpReadProblems, "%s", cnt);for (int i = 12; i < strlen(cnt); i ++) { // 将字符串转化为int型的题目数量char c = cnt[i];if ('0' <= c && c <= '9') {countProblems = countProblems * 10 + c - '0';} else {break;}}for (int i = 0; i < countProblems; i++) { // 读入题目Pro* readSavedProblems = (Pro*)malloc(sizeof(Pro));fscanf(fpReadProblems, "%s", readSavedProblems->q);for (int i = 0; i < 4; i ++) {fscanf(fpReadProblems, "%s", readSavedProblems->op[i]);}char ans[10];fscanf(fpReadProblems, "%s", ans);readSavedProblems->ans = ans[6]; // 读取答案readSavedProblems->idx = countProblems - i;readSavedProblems->next = proHead->next;proHead->next = readSavedProblems;}fclose(fpReadProblems);return countProblems;
}int readStudents(Stu* stuHead) { // 读入学生成绩FILE *fpReadStudents = fopen("stu.txt", "r");char cnt[40];fscanf(fpReadStudents, "%s", cnt);int countStudents = 0;for (int i = 6; i < strlen(cnt); i ++) { // 将字符串转化为int型的已答学生数量char c = cnt[i];if ('0' <= c && c <= '9') {countStudents = countStudents * 10 + c - '0';} else {break;}}fscanf(fpReadStudents, "%*s%*s%*s%*s"); // 忽略表头for (int i = 0; i < countStudents; i ++) {Stu* readSavedStudents = (Stu*)malloc(sizeof(Stu));fscanf(fpReadStudents, "%s%s%d%d", readSavedStudents->name, readSavedStudents->idx, &readSavedStudents->grade, &readSavedStudents->numQue);readSavedStudents->next = stuHead->next;stuHead->next = readSavedStudents;}fclose(fpReadStudents);return countStudents;
}void saveProblems(Pro* proHead, int countProblems) { // 保存题目FILE *fpWriteProblems = fopen("test.txt", "w");fprintf(fpWriteProblems, "当前有题目:%d个\n\n", countProblems);for (Pro* writeProblems = proHead->next; writeProblems != NULL; writeProblems = writeProblems->next) {fprintf(fpWriteProblems, "%s\n", writeProblems->q);for (int i = 0; i < 4; i ++) {fprintf(fpWriteProblems, "%s\n", writeProblems->op[i]);}fprintf(fpWriteProblems, "答案:%c\n\n", writeProblems->ans);}proHead->next = NULL;fclose(fpWriteProblems);}void saveStudents(Stu* stuHead, int countStudents) { // 保存学生成绩FILE *fpSaveStudents = fopen("stu.txt", "w");fprintf(fpSaveStudents, "总计有%d个学生已答题\n\n", countStudents);fprintf(fpSaveStudents, "姓名\t学号\t成绩\t题目\n");for (Stu* point = stuHead->next; point != NULL; point = point->next) {fprintf(fpSaveStudents, "%s\t%s\t%d\t%d\n", point->name, point->idx, point->grade, point->numQue);}stuHead->next = NULL;fclose(fpSaveStudents);}void outputProblems(Pro* proHead, int countProblems) { // 输出所有题目cls;title(" 题库题目 ");endl;for (Pro* outProblems = proHead->next; outProblems != NULL; outProblems = outProblems->next) {printf("%03d. %s\n", outProblems->idx, outProblems->q);for (int i = 0; i < 4; i ++) {printf("%s\n", outProblems->op[i]);}printf("答案:%c\n\n", outProblems->ans);}endl;printf("当前有题目:%d个\n\n", countProblems);endl;title(" 题库题目 ");
}void outputStudents(Stu* stuHead, int countStudents) { // 输出所有学生cls;title(" 学生成绩表 ");endl;puts("姓名\t学号\t成绩\t题目");for (Stu* point = stuHead->next; point != NULL; point = point->next) {printf("%s\t%s\t%d\t%d\n", point->name, point->idx, point->grade, point->numQue);}endl;printf("已有%d人完成答题\n", countStudents);endl;title("===========");
}void deleteProblem(Pro* proHead, int toBeDeleted) { // 删除指定题目Pro* last = proHead;for (Pro* point = proHead->next; point != NULL; last = point, point = point->next) {if (point->idx == toBeDeleted) {last->next = point->next;// free(point); // 回收内存}}
}int editProblem(Pro* proHead, int countProblems, int problemToBeEdited) { // 编辑题目cls;title(" 变更题目 ");endl;puts("\t0 > 退出");puts("\t1 > 删除");puts("\t2 > 修改");endl;title("==========");int choose;scanf("%d", &choose);if (choose == 0) { // 选择更改题目与删除题目return countProblems;} else if (choose == 1) {countProblems--;deleteProblem(proHead, problemToBeEdited);return countProblems;}Pro* point;for (point = proHead->next; point != NULL; point = point->next) {if (point->idx == problemToBeEdited) {break;}}cls;title(" 变更题目 ");printf("题目为:%s\n你要修改成:(不变输入next)\n", point->q);char q2[50];scanf("%s", q2);if (strcmp(q2, "next") != 0) {strcpy(point->q, q2);}for (int i = 0; i < 4; i ++) {cls;title(" 变更题目 ");printf("%c 选项为:%s\n你要修改成:(不变输入next)\n", 'A' + i, point->op[i]);char op[25];scanf("%s", op);if (strcmp(op, "next") != 0) {sprintf(point->op[i], "%c.%s", 'A' + i, op);}}cls;printf("答案原为:%c\n你要修改成:(不变输入next)\n", point->ans);char anss[10];scanf("%s", anss);if (strcmp(anss, "next") != 0) {anss[0] = convert(anss[0]);point->ans = anss[0];}return countProblems;
}int addProblem(Pro* proHead, int countProblems) { // 新增题目cls;title(" 新增题目 ");Pro* addNewProblems = (Pro*)malloc(sizeof(Pro));printf("题  目:");scanf("%s", addNewProblems->q);for (int i = 0; i < 4; i ++) {printf("%c 选项:", 'A' + i);scanf("%s", addNewProblems->op[i]);char index[30] = "";sprintf(index, "%c.%s", 'A' + i, addNewProblems->op[i]);strcpy(addNewProblems->op[i], index);}char ans;printf("答  案:");getchar();scanf("%c", &ans);ans = convert(ans);addNewProblems->ans = ans;addNewProblems->next = proHead->next;proHead->next = addNewProblems;countProblems ++;return countProblems;
}int manageProblems(Pro* proHead, int countProblems) { // 管理题库cls;title(" 管理题目 ");endl;puts("\t0 > 退出");puts("\t1 > 更改题目");puts("\t2 > 新增题目");endl;title("==========");int chooseManageProblems;scanf("%d", &chooseManageProblems);switch (chooseManageProblems) {case 0:return countProblems;case 1:outputProblems(proHead, countProblems);printf("请选择要更改的题目编号:");int problemToBeEdited;scanf("%d", &problemToBeEdited);countProblems = editProblem(proHead, countProblems, problemToBeEdited);break;case 2:countProblems = addProblem(proHead, countProblems);break;}return countProblems;
}int startTeacher(Stu* stuHead, Pro* proHead, int countStudents, int countProblems) { // 老师管理界面while (true) {cls;title(" 教师登录 ");endl;char account[20], password[20];const char acc[20] = "admin", pswd[20] = "admin";printf("\t账号:");scanf("%s", account);printf("\t密码:");scanf("%s", password);if (strcmp(account, acc) == 0 && strcmp(password, pswd) == 0) {break;}cls;title(" 教师登录 ");printf("\n\t账号或密码错误\n\n");title("==========");Sleep(1500);}while (true) {cls;title(" 教师管理 ");endl;puts("\t0 > 退出");puts("\t1 > 显示所有题目");puts("\t2 > 管理题库");puts("\t3 > 学生成绩查看");endl;title("==========");int choooseTeacherManage;scanf("%d", &choooseTeacherManage);switch (choooseTeacherManage) {case 0:return countProblems;case 1:outputProblems(proHead, countProblems);printf("输入任意字符退出:");char c2quit[20];scanf("%s", c2quit);break;case 2:countProblems = manageProblems(proHead, countProblems);break;case 3:outputStudents(stuHead, countStudents);printf("输入任意字符退出:");char c3quit[20];scanf("%s", c3quit);break;}saveProblems(proHead, countProblems);countProblems = readProblems(proHead);}}void startStudent(Stu* stuHead, Pro* proHead, int countStudents, int countProblems) { // 学生答题界面Stu* addNewStudent = (Stu*)malloc(sizeof(Stu));cls;title(" 考生登录 ");endl;printf("\t姓名:");scanf("%s", addNewStudent->name);printf("\t学号:");scanf("%s", addNewStudent->idx);clearState(proHead, countProblems);cls;title(" 考生答题 ");endl;printf("\t要抽取题目数:");int countSelectedProblems, countRightProblems = 0;scanf("%d", &countSelectedProblems);for (int i = 0; i < countSelectedProblems; i ++) {cls;title(" 考生答题 ");endl;Pro* selectedProblem = getRandomProblem(proHead, countProblems);printf("第%d题:%s\n", i + 1, selectedProblem->q);for (int i = 0; i < 4; i ++) {printf("%s\n", selectedProblem->op[i]);}printf("\n选择:");getchar();char choose;scanf("%c", &choose);choose = convert(choose);if (choose == selectedProblem->ans) {countRightProblems ++;}}addNewStudent->grade = (double)(countRightProblems * 100) / countSelectedProblems;addNewStudent->numQue = countSelectedProblems;cls;title(" 答题结果 ");endl;printf("\t答对:%d/%d\n", countRightProblems, countSelectedProblems);printf("\t得分:%d分\n", addNewStudent->grade);puts("\t更新数据中,请稍后");endl;title("==========");// 更新数据addNewStudent->next = stuHead->next;stuHead->next = addNewStudent;countStudents ++;saveStudents(stuHead, countStudents);countStudents = readStudents(stuHead);printf("输入任意字符退出:");char c4quit[20];scanf("%s", c4quit);
}int main() {while (true) { // 保持不退出cls;title(" 单项选择题标准化考试系统 ");endl;puts("\t\t0 > 保存退出");puts("\t\t1 > 教师登录");puts("\t\t2 > 学生登录");endl;title("==========================");// 初始化学生和问题链表Stu *stuHead = (Stu *)malloc(sizeof(Stu));Pro *proHead = (Pro *)malloc(sizeof(Pro));stuHead->next = NULL;proHead->next = NULL;int countProblems = readProblems(proHead);int countStudents = readStudents(stuHead);int chooseTorS;scanf("%d", &chooseTorS);switch (chooseTorS) {case 0:cls;title(" 单项选择题标准化考试系统 ");endl;puts("\t\t      已退出");endl;title("==========================");return 0;case 1:countProblems = startTeacher(stuHead, proHead, countStudents, countProblems);break;case 2:startStudent(stuHead, proHead, countStudents, countProblems);break;}saveProblems(proHead, countProblems);}return 0;
}

这篇关于C语言课程设计:单项选择题标准化考试系统 | JorbanS的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/163370

相关文章

Python FastAPI+Celery+RabbitMQ实现分布式图片水印处理系统

《PythonFastAPI+Celery+RabbitMQ实现分布式图片水印处理系统》这篇文章主要为大家详细介绍了PythonFastAPI如何结合Celery以及RabbitMQ实现简单的分布式... 实现思路FastAPI 服务器Celery 任务队列RabbitMQ 作为消息代理定时任务处理完整

Linux系统中卸载与安装JDK的详细教程

《Linux系统中卸载与安装JDK的详细教程》本文详细介绍了如何在Linux系统中通过Xshell和Xftp工具连接与传输文件,然后进行JDK的安装与卸载,安装步骤包括连接Linux、传输JDK安装包... 目录1、卸载1.1 linux删除自带的JDK1.2 Linux上卸载自己安装的JDK2、安装2.1

C语言中的数据类型强制转换

《C语言中的数据类型强制转换》:本文主要介绍C语言中的数据类型强制转换方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录C语言数据类型强制转换自动转换强制转换类型总结C语言数据类型强制转换强制类型转换:是通过类型转换运算来实现的,主要的数据类型转换分为自动转换

利用Go语言开发文件操作工具轻松处理所有文件

《利用Go语言开发文件操作工具轻松处理所有文件》在后端开发中,文件操作是一个非常常见但又容易出错的场景,本文小编要向大家介绍一个强大的Go语言文件操作工具库,它能帮你轻松处理各种文件操作场景... 目录为什么需要这个工具?核心功能详解1. 文件/目录存javascript在性检查2. 批量创建目录3. 文件

Linux系统之主机网络配置方式

《Linux系统之主机网络配置方式》:本文主要介绍Linux系统之主机网络配置方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录一、查看主机的网络参数1、查看主机名2、查看IP地址3、查看网关4、查看DNS二、配置网卡1、修改网卡配置文件2、nmcli工具【通用

Linux系统之dns域名解析全过程

《Linux系统之dns域名解析全过程》:本文主要介绍Linux系统之dns域名解析全过程,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录一、dns域名解析介绍1、DNS核心概念1.1 区域 zone1.2 记录 record二、DNS服务的配置1、正向解析的配置

C语言实现两个变量值交换的三种方式

《C语言实现两个变量值交换的三种方式》两个变量值的交换是编程中最常见的问题之一,以下将介绍三种变量的交换方式,其中第一种方式是最常用也是最实用的,后两种方式一般只在特殊限制下使用,需要的朋友可以参考下... 目录1.使用临时变量(推荐)2.相加和相减的方式(值较大时可能丢失数据)3.按位异或运算1.使用临时

使用C语言实现交换整数的奇数位和偶数位

《使用C语言实现交换整数的奇数位和偶数位》在C语言中,要交换一个整数的二进制位中的奇数位和偶数位,重点需要理解位操作,当我们谈论二进制位的奇数位和偶数位时,我们是指从右到左数的位置,本文给大家介绍了使... 目录一、问题描述二、解决思路三、函数实现四、宏实现五、总结一、问题描述使用C语言代码实现:将一个整

Linux系统中配置静态IP地址的详细步骤

《Linux系统中配置静态IP地址的详细步骤》本文详细介绍了在Linux系统中配置静态IP地址的五个步骤,包括打开终端、编辑网络配置文件、配置IP地址、保存并重启网络服务,这对于系统管理员和新手都极具... 目录步骤一:打开终端步骤二:编辑网络配置文件步骤三:配置静态IP地址步骤四:保存并关闭文件步骤五:重

C语言字符函数和字符串函数示例详解

《C语言字符函数和字符串函数示例详解》本文详细介绍了C语言中字符分类函数、字符转换函数及字符串操作函数的使用方法,并通过示例代码展示了如何实现这些功能,通过这些内容,读者可以深入理解并掌握C语言中的字... 目录一、字符分类函数二、字符转换函数三、strlen的使用和模拟实现3.1strlen函数3.2st