单项选择题标准化考试系统设计

单项选择题标准化考试系统设计

这个程序是我大一上学期的期末课程设计,在网上查了许多的资料,用了5天左右的时间和同学一起完成的。因为我们才刚入门c语言,所以程序可能有点拙劣,但还是希望能帮助各位同学。

//所用的IDE是VC++6.0
//所录入的题目是思政课的选择题

功能要求

(1)用文件保存试题库。(每个试题包括题干、4个备选答案、标准答案)
(2)试题录入:可随时增加试题到试题库中
(3)试题抽取:每次从试题库中可以随机抽出N道题(N由键盘输入)
(4)答题:用户可实现输入自己的答案
(5)自动判卷:系统可根据用户答案与标准答案的对比实现判卷并给出成绩。

代码设计

1.结构组与函数

typedef struct
{
	char question[200],A[100],B[100],C[100],D[100];
	char key;
}Question;//结构组,结构类型Question

void Menu();//主菜单
void Remenu();//返回菜单或退出
void Answer();//抽取答题
void Add();//试题录入
void Deleteq();//试题删除
void Readfile();//读取所有题目
void Putques1();//输出问题1(不输出答案)
void Putques2();//输出问题2(输出答案)
int Total();//计算总题目数量

抽取题目首先需要读取题目。我们的设计思路是建立一个结构数组用来存储题目信息,其中包括题目,ABCD四个选项以及答案,结构如下:

typedef struct
{
	char question[200],A[100],B[100],C[100],D[100];
	char key;
}Question;//结构组,结构类型Question

起初我们准备直接建立一个固定的结构数组Question qs[100]用来在内存中存储题目,但发现这样有许多弊病。
①容易造成内存空间的浪费
②读取时容易造成越界(“烫烫烫烫烫烫……”)
③存在题目上限,不方便后续添加题目
于是我们决定利用malloc()进行动态分配内存,生成动态结构数组。但是进行动态分配内存需要实现知道题目数量。于是我们做了int Total()函数来预读一遍题目数量,然后将题目总数返回给total,利用total来生成动态结构数组。这样就解决了上面三个问题,但是伴随而来的问题是题目读取时间变长了。

2.菜单的实现与返回

//主菜单函数:主要用于用户使用时功能的选择,包括了Answer(),Add(),Deleteq(),exit(0)函数
void Menu()
{
	int n;//记录序列号
	system("cls");//清屏
	printf("************************************************************************************************************************\n");
	printf("*                                             单项选择题标准化考试系统 V2.4                                            *\n");
	printf("*                                                                                                                      *\n");
	printf("*                                                      ①抽取答题                                                      *\n");
	printf("*                                                                                                                      *\n");
	printf("*                                                      ②试题录入                                                      *\n");
	printf("*                                                                                                                      *\n");
	printf("*                                                      ③试题删除                                                      *\n");
	printf("*                                                                                                                      *\n");
	printf("*                                                      ④  退出                                                        *\n");
    printf("************************************************************************************************************************\n");//美化菜单

	do
	{
		printf(" ┉┉┉┉┉┉┉┉┉┉┉┉┉┉┉┉┉┉\n");
		printf(" 请输入正确的序列号:\n");
        printf(" ┉┉┉┉┉┉┉┉┉┉┉┉┉┉┉┉┉┉\n");
		scanf("%d",&n);
		printf("\n");
	}while(n<1||n>4);//若输入序列号不正确,返回循环体,重新输入,否则跳出循环

	switch(n)//通过switch-case对序列号对应的要求实现
	{
	case 1:
		Answer();//抽取答题
		break;
	case 2:
		Add();//试题录入
		break;
	case 3:
		Deleteq();//试题删除
		break;
	case 4:
		exit(0);//退出
		break;
	default:
		printf("错误\n");//default语句在此其实并无实际用处
	}
}

单项选择题标准化考试系统设计_第1张图片
主菜单界面签约整洁并且输入序号外的数字无效

3.用文件保存试题库与试题录入

//题目录入函数():录入题目。包含Remenu()函数
void Add()
{
	FILE* readf;
    char ch;
    system("cls");//清屏
	printf("************************************************************************************************************************\n");
    printf("                                                          试题录入                                                      \n");
	printf("************************************************************************************************************************\n");

	readf=fopen("question.txt","a");//a表示对文件追加内容
	if(!readf)
	{
		printf("打开文件失败\n");
		exit(1);
	}

	printf("请按照以下格式分别录入问题、ABCD四个选项及正确答案并以#结束:\n");//可以自由录入题目数量,停止录入只需在末尾加#
	printf("例:步入人生新阶段,确立新目标,开启新征程,需要对()有深入的了解和真切的感悟。\n");//用户友好
    printf("社会\n");
    printf("个人\n");
    printf("新时代\n");
    printf("大学\n");
    printf("C\n");

	ch=getchar();//读取第一个字符
	while(ch!='#')
	{
		fputc(ch,readf);//将读入的字符写入文件
		ch=getchar();//读取下一个字符
	}
	fclose(readf);
	
	Remenu();//返回菜单或退出
}

单项选择题标准化考试系统设计_第2张图片
在主菜单输入2即可进行试题录入
题目会直接加到文本文件里

4.试题抽取、答题与自动判卷

考虑到程序的实用性,我们决定将试题抽取、答题与自动判卷放到一起,实现“抽取答题”的功能。用户进入抽取答题的页面后,只需要输入想要答题的数目即可进行答题。为了让答题方便,我们采用答一题输入下一题的形式,最终会生成总成绩让用户选择是返回主菜单还是退出程序。

//抽取答题函数:用于实现抽取,答题,自动批阅的功能。其中包含了Readfile(),Putques1(),Total(),Remenu()这些功能函数
void Answer()
{
	int i,j,total,n;//i用于索引,j也用于索引同i一起实现生产不重复的随机数组的功能。total用来存储总题目数。n用来存储用户输入的抽取题目数目。
	int *a;//生产整型指针,用于建立动态数组
	Question *qs;//生成Question型指针,用于建立动态结构数组
	int score=0;//用于记分
	char an;//存储用户输入的答案
	
	total=Total();//利用Total()函数将总题目数返回给total
	qs=(Question*)malloc(total*sizeof(Question));//分配空间给动态结构数组
	Readfile(qs,total);//读取题目
	
	system("cls");//清屏
    printf("************************************************************************************************************************\n");//美化界面
    printf("                                                          抽取答题                                                      \n");
	printf("************************************************************************************************************************\n");

	printf("当前题库题目数:%d\n",total);
loop1:printf("请输入抽查题目数量:");//loop1充当前哨,防止用户输入的n>total
	  scanf("%d",&n);
	  printf("正在拼命加载中……\n");
	  printf("………………………………………………………………………………………………………………………………………………………………\n");

	  if(n<=total)
	  {//开始生成不重复的随机数组
		  a=(int*)malloc(n*sizeof(int));//分配空间生成动态数组
		  for(i=0;i<n;i++)
		  {
loop2:srand(time(NULL));//srand和rand一起使用,这条语句大家把它看作用rand之前的一个习惯用法(rand为随机数)
	 a[i]=rand()%total;//保证随机数在total内(小于total)(total为总题数)
	 for(j=i-1;j>=0;j--)
	 {
		 if(a[i]==a[j])
			 goto loop2;//如果新抽出的题目(a[i])与已抽出的题目(a[j])一样,跳到loop:后的语句重新抽取a[i]
	 }
		  }
	  }
	else
	{
		printf("超过最大题数,最大题数为%d\n",total);//保证抽出的题目不重复且在系统支持范围内(题目数量不超出总题数)
		goto loop1;
	}
	for(i=0;i<n;i++)//利用循环输出所抽到的问题
	{
		Putques1(&qs[a[i]],i+1);
        fflush(stdin);//清空键盘缓冲区
		an=getchar();//读取用户输入的答案
		while((int)an<65||((int)an>68&&(int)an<97)||(int)an>100)//用强制转换判断用户输入的是否为选项
		{
			printf("请输入A,B,C,D其中之一作为你的答案\n");
			fflush(stdin);//清空键盘缓冲区
		    an=getchar();//读取用户输入的答案
		}
		if((int)an>96&&(int)an<101)//若用户输入的是小写字母,让其转换为大写字母
			an=toupper(an);
		if(qs[a[i]].key==an)//批改
		{
			score+=1;//正确+1分
			printf("正确\n\n");
		}
		else
			printf("错误\n正确答案为%c\n\n",qs[a[i]].key);
	}
	printf("¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤\n");
	printf("共%d题,您答对了%d道题\n",n,score);
	printf("得分:%f\n",((float)score/n)*100);//评分
    printf("¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤\n");
	free(qs);//释放分配的内存空间
	free(a);//同上
	Remenu();//返回菜单或退出
}

单项选择题标准化考试系统设计_第3张图片
从主菜单输入1,进入抽取答题页面
单项选择题标准化考试系统设计_第4张图片
输入题目数即可开始答题

5.试题删除

介于时间比较充足,又考虑到本程序功能的完整性,我们又添加了一个试题删除功能。

//试题删除函数():用于删除题目。包含Total(),Readfile(),Putques2(),Remenu()函数
void Deleteq()
{
	int i,j;
	char o;
	Question qs[5];
	FILE *rewritef,*readf;

	readf=fopen("question.txt","r");
	if(!readf)
	{
		printf("打开文件失败\n");
		exit(1);
	}
	rewritef=fopen("temp.txt","w+");
	if(!readf)
	{
		printf("打开文件失败\n");
		exit(1);
	}

	while(!feof(readf))
	{
	system("cls");
	printf("************************************************************************************************************************\n");
    printf("                                                          试题删除                                                      \n");
	printf("************************************************************************************************************************\n");
	for(i=0;(feof(readf)==0)&&i<5;i++)
		fscanf(readf,"%s%s%s%s%s%c%c",qs[i].question,qs[i].A,qs[i].B,qs[i].C,qs[i].D,&o,&qs[i].key);

	for(j=0;j<i;j++)
		Putques2(&qs[j],j+1);


	printf("输入题目序号进行删除,输入0进入下一页。\n");
	scanf("%d",&j);
	while(j>i)
	{
		printf("输入题目序号进行删除,输入0进入下一页。\n");
	    scanf("%d",&j);
	}

	if(j>0&&j<i+1)
	{
		while(j!=0)
		{
		    for(j--;j<i-2;j++)//利用循环,覆盖删除
	            qs[j]=qs[j+1];
			i--;
			system("cls");

			for(j=0;j<i;j++)
				Putques2(&qs[j],j+1);
			printf("输入题目序号进行删除,输入0进入下一页。\n");
	        scanf("%d",&j);
			while(j>i)
			{
				printf("输入题目序号进行删除,输入0进入下一页。\n");
				scanf("%d",&j);
			}
		}
	}
	
	for(j=0;j<i;j++)//输出删除后所有题目
		fprintf(rewritef,"%s\n%s\n%s\n%s\n%s\n%c\n",qs[j].question,qs[j].A,qs[j].B,qs[j].C,qs[j].D,qs[j].key);
	}
	fclose(rewritef);
	fclose(readf);
	remove("question.txt");
	rename("temp.txt","question.txt");
	Remenu();//返回菜单或退出
}

单项选择题标准化考试系统设计_第5张图片
从主菜单输入3进入试题删除界面,输入题号可直接删除单项选择题标准化考试系统设计_第6张图片
输入1继续删除,输入其他数字退出

6.其它函数

//返回菜单/退出函数:用于完成一项功能后让用户选择是返回菜单还是退出应用程序
void Remenu()
{
	int n;//存储用户输入的数字(通过数字发出指令)
	do//前哨
	{
		printf("§返回主菜单§请输入①\n");
	    printf("§   退出   §请输入②\n");
		scanf("%d",&n);
	}while(n<1||n>2);//若为1或2跳出循环,否则执行循环体要求用户重新输入
	if(n==1)
		Menu();//n=1,返回主菜单
	else
		exit(0);//n=2,退出
}

//读题函数():用于读取文件内所有题目并存在内存空间中。
void Readfile(Question* qs,int total)//导入Question型指针,以及总题目数量total
{
	int i=0;//作用1:结构数组索引;作用2:其最终值刚好为总题数值,返回i给Menu()函数里的total,使得total为总题数值
	char o;//用于读取回车符,防止题目信息读取错位
	FILE* readf;
	readf=fopen("question.txt","r");//仅用读的方式打开文件
	if(!readf)
	{
		printf("打开文件失败\n");
		exit(1);
	}

	for(i=0;i<total;i++)//利用循环按顺序将所有题目存在内存空间中
		fscanf(readf,"%s%s%s%s%s%c%c",qs[i].question,qs[i].A,qs[i].B,qs[i].C,qs[i].D,&o,&qs[i].key);

	fclose(readf);//关闭文件,结束该函数
}

//计算总题目数函数():功能入其名,利用几个空字符串读取文件内所有题目,读完一题total加一次1。
int Total()
{
	int total;//total用于存储总题目数
	char question[200],A[100],B[100],C[100],D[100];//建立空字符串用于存储读的题目
	char key,o;

	FILE* readf;
	readf=fopen("question.txt","r");
	if(!readf)
	{
		printf("打开文件失败\n");
		exit(1);
	}
    for(total=0;!feof(readf);total++)//每读完一个题目,总题目数+1
		fscanf(readf,"%s%s%s%s%s%c%c",question,A,B,C,D,&o,&key);
	total-=1;
	fclose(readf);//关闭文件
	return total;//返回total的值并退出该函数
}

//输出题目函数():用于题目的打印。一个打印出来无答案,一个有答案。分别用于抽取答题函数和试题删除函数。
void Putques1(Question* qs,int i)//导入Question型指针,以及当前题目序号i
{printf("(%d)%s\n   A.%s\n   B.%s\n   C.%s\n   D.%s\n",i,qs->question,qs->A,qs->B,qs->C,qs->D);}

void Putques2(Question* qs,int i)
{printf("(%d)%s\n   A.%s\n   B.%s\n   C.%s\n   D.%s\n   答案:%c\n",i,qs->question,qs->A,qs->B,qs->C,qs->D,qs->key);}

相关报告书和代码文件在我上传的资源里,需要的可以进我的主页去下载。

你可能感兴趣的:(课设,单项选择题标准化考试系统,C语言)