实验要求:
|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| 老师在教学过程中,会经常以试卷的形式来检验学生的学习情况。现在由你来帮助老师设计一个试卷自动生成系统,完成从已有题库(题库包含2个文件,1个是选择题题库文件,1格式填空题题库文件)中随机提取指定题目书的题目生成一份新的试卷。该系统生成的试卷中只有2种题型:单项选择题、填空题(只有一个空)。其中 单项选择题包括题目编号、题目、选项A、选项B、选项C、选项D、答案 填空题包括题目编号、题目、答案 功能: (1)试题添加:向试题库追加 写入一道新的题目,要求题目编号自动生成,且与已存题目的编号不重复;所有内容不能为空。即不断充实题库; (2)试题删除:通过题目编号进行题目的删除,如果删除成功则提示删除成功,否则提示删除失败; (3)备份全部题目; (4)删除全部题目; (5)试题修改:通过题目编号查找对应题目,并修改指定的题目的内容,注意不是修改题目的全部内容,而是可以针对性的修改局部内容; (6)试题查询:通过题目编号查询指定的题目的所有内容; (7)统计共有多少道题目; (8)查询题目中含有某个特定内容(用户输入)的所有题目内容; (9)自动随机生成由单项选择题、填空题合在一起的试卷及标准答案2个文件(exam.txt和answer.txt),各题型的题目数由用户输入。注意选择题和填空题的题目数可以不一样;要求每次生成的试卷题目、顺序都不能完全相同。也就是要求真正的随机提取题目。 (10)以上功能要求通过菜单的方式进行操作;要求对相应内容进行必要的合法性检查。本题要求用链表实现。要求具有良好的人机交互界面。每个题型要提前录入至少10道题。 |
实验总结:
|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| (对实验结果进行分析,问题回答,实验心得体会及改进意见) 问题1:怎么实现的查询指定题目 令中介指针等于头指针,遍历链表,判断题号是否等于待查询的题号,如果相等,则将这道题目打印出来;如果在两个题库中遍历之后没有找到,则回复没有这道题。 问题2:如何做到生成题号且不重复 定义一个全局变量number,并令number为0,令number加1,再添加一个题目,这样实现生成的题目的题号都是升序的且不重复的。在读取题库中原有的题目的时候,令number等于读取到的题目的序号,并在读取完一个题之后令number加一,这样就能保证每次新增题目题号都是按照顺序升序排列并且是最大的。 实验心得体会:这个实验我写了好几遍,每一遍都有不同的感悟,在写第一遍的时候,对于指针安排和链表使用比较混乱,并且内存分配逻辑不清晰,以至于程序写完之后出现bug找不到错误的地方;第二遍的时候优化了内存分配,使得程序可读性增强,但是依然在查找功能无法实行,代码无错误,结果却无法运行;后面的很多遍,在一次次的修改每个模块,实现了每个模块的功能。 通过写这次实验,我更好地理解了动态内存分配,并对链表有了更深刻的认识,提高了我的逻辑性。建立了文件与链表间的联系,将文件内容读到链表,再从链表中写入文件。另外还学习到了查找字符串内容的函数strstr()。 |
源程序:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
typedef struct ChoiceQuestion { //选择题链表
int num;//题目编号
char topic[10000];//题目
char A[1000];//选项
char B[1000];
char C[1000];
char D[1000];
char answer[10000];//答案
struct ChoiceQuestion *next;//保存下一个题目节点地址
} ChoiceQuestion;
typedef struct BlanksQuestion { //填空题链表
int num;
char topic[10000];
char answer[1000];
struct BlanksQuestion *next;//保存下一个题目节点地址
} BlanksQuestion;
int number = 0;
//将链表内容读入到文件中
void readQuestion(ChoiceQuestion *head1,ChoiceQuestion *t1,ChoiceQuestion *p1,BlanksQuestion *head2,BlanksQuestion *t2,BlanksQuestion *p2){
FILE *choiceFile = fopen("D:\\xuanzeti.txt","w");//重写文件
FILE *blanksFile = fopen("D:\\tiankong.txt","w");
p1=head1,p2=head2;//指向头节点位置
while(p1!=NULL){
fprintf(choiceFile,"%d %s\n",p1->num,p1->topic);
fprintf(choiceFile,"%s\n",p1->A);
fprintf(choiceFile,"%s\n",p1->B);
fprintf(choiceFile,"%s\n",p1->C);
fprintf(choiceFile,"%s\n",p1->D);
fprintf(choiceFile,"%s\n",p1->answer);
p1 = p1->next;
}
while(p2!=NULL){
fprintf(blanksFile,"%d %s\n",p2->num,p2->topic);
fprintf(blanksFile,"%s\n",p2->answer);
p2 = p2->next;
}
fclose(choiceFile);
fclose(blanksFile);
}
//1、添加试题
void addQuestion(){
while(1){
system("cls");
FILE *fp;
printf("\n\t添加选择题 1");
printf("\n\t添加填空题 2");
printf("\n\t请选择需要添加的题目种类:");
int type;
scanf("%d",&type);
getchar();
if(type==1){
fp = fopen("D:\\xuanzeti.txt","a+");
number++;
printf("\n\t新增题目的题号是:%d\n",number);
printf("\n\t请输入新题目的内容\n\n\t请分别输入添加的题目、选项、答案\n");
char choice[10000];
printf("\n\t输入题目:");
gets(choice); fprintf(fp,"%d %s\n",number,choice);
printf("\n\t输入选项A:");
gets(choice); fprintf(fp,"%s\n",choice);
printf("\n\t输入选项B:");
gets(choice); fprintf(fp,"%s\n",choice);
printf("\n\t输入选项C:");
gets(choice); fprintf(fp,"%s\n",choice);
printf("\n\t输入选项D:");
gets(choice); fprintf(fp,"%s\n",choice);
printf("\n\t输入答案:");
gets(choice); fprintf(fp,"%s\n",choice);
printf("\n\t题目添加完毕");
}else if(type==2){
fp = fopen("D:\\tiankong.txt","a+");
number++;
printf("\n\t新增题目的题号是:%d\n",number);
printf("\n\t请输入新题目的内容\n\n\t请分别输入添加的题目、答案\n");
char blanks[10000];
printf("\n\t输入题目:");
gets(blanks); fprintf(fp,"%d %s\n",number,blanks);
printf("\n\t输入答案:");
gets(blanks); fprintf(fp,"%s\n",blanks);
printf("\n\t题目添加完毕");
}
fclose(fp);
}
}
//2、删除试题
void deleteQuestion(ChoiceQuestion *head1,ChoiceQuestion *t1,ChoiceQuestion *p1,BlanksQuestion *head2,BlanksQuestion *t2,BlanksQuestion *p2){
int id,count=0;
printf("\n\t请输入待删除的题目的编号:");
scanf("%d",&id);
p1=head1,p2=head2;//遍历节点
if(head1!=NULL){
if(head1->num==id){//如果头节点就是需要找的题目
head1 = head1->next;
count=1;//标记,存在该结点
} else {
while(p1->next!=NULL){//循环遍历
if(p1->next->num==id){
p1->next = p1->next->next;//前驱节点就等于后驱节点
count = 1;
break;
}
p1 = p1->next;
}
}
}
if(head2!=NULL&&!count){
if(head2->num==id){
head2 = head2->next;
count = 1;
} else {
while(p2->next!=NULL){
if(p2->next->num==id){
p2->next = p2->next->next;
count = 1;
break;
}
p2 = p2->next;
}
}
}
readQuestion(head1,t1,p1,head2,t2,p2);
if(count)
printf("\n\t成功删除题目");
else
printf("\n\t删除失败\n");
}
//3、备份所有题目
void backupQuestion(ChoiceQuestion *head1,ChoiceQuestion *t1,ChoiceQuestion *p1,BlanksQuestion *head2,BlanksQuestion *t2,BlanksQuestion *p2){
system("cls");
FILE *choiceFile = fopen("D:\\xuanzeti_choice.txt","w+"),*blanksFile = fopen("D:\\tiankong_blanks.txt","w+");
p1=head1,p2=head2;
while(p1!=NULL&&p1->num!=0){
fprintf(choiceFile,"%d %s\n",p1->num,p1->topic);
fprintf(choiceFile,"%s\n",p1->A);
fprintf(choiceFile,"%s\n",p1->B);
fprintf(choiceFile,"%s\n",p1->C);
fprintf(choiceFile,"%s\n",p1->D);
fprintf(choiceFile,"%s\n",p1->answer);
p1=p1->next;
}
while(p2!=NULL&&p2->num!=0){
fprintf(blanksFile,"%d %s\n",p2->num,p2->topic);
fprintf(blanksFile,"%s\n",p2->answer);
p2=p2->next;
}
printf("\n\t备份成功");
fclose(choiceFile);
fclose(blanksFile);
}
//4、删除全部题目
void deleteAllQuestion(){
system("cls");
remove("D:\\xuanzeti.txt");
remove("D:\\tiankong.txt");
printf("\n\t删除成功!");
}
//5、试题修改
void modifyQuestion(ChoiceQuestion *head1,ChoiceQuestion *t1,ChoiceQuestion *p1,BlanksQuestion *head2,BlanksQuestion *t2,BlanksQuestion *p2){
system("cls");
int id,count=0;
printf("\n\t请输入待修改题目的编号:");
scanf("%d",&id);
getchar();
if(head1==NULL)
printf("\n\t选择题题库是空的\n");
else {
if(head1->num==id){
printf("\n\t修改选择题的题目:"); gets(head1->topic);
printf("\n\t修改A选项:"); gets(head1->A);
printf("\n\t修改B选项:"); gets(head1->B);
printf("\n\t修改C选项:"); gets(head1->C);
printf("\n\t修改D选项:"); gets(head1->D);
printf("\n\t修改答案:"); gets(head1->answer);
printf("\n\t修改完成");
count++;
}else{
while(p1!=NULL){
if(p1->num==id){
printf("\n\t修改选择题的题目:"); gets(p1->topic);
printf("\n\t修改A选项:"); gets(p1->A);
printf("\n\t修改B选项:"); gets(p1->B);
printf("\n\t修改C选项:"); gets(p1->C);
printf("\n\t修改D选项:"); gets(p1->D);
printf("\n\t修改答案:"); gets(p1->answer);
printf("\n\t修改完成\n");
count++;
break;
}else
p1 = p1->next;
}
}
}
if(head2==NULL)
printf("\n\t填空题题库是空的\n");
else{
if(head2->num==id){
printf("\n\t修改填空题题目:"); gets(head2->topic);
printf("\n\t修改答案:"); gets(head2->answer);
printf("\n\t修改完成\n");
count++;
}else{
while(p2!=NULL){
if(p2->num==id){
printf("\n\t修改填空题题目:"); gets(p2->topic);
printf("\n\t修改答案:"); gets(p2->answer);
printf("\n\t修改完成\n");
count++;
break;
}else
p2 = p2->next;
}
}
}
if(count==0)
printf("\n\t修改失败\n");
getchar();
}
//6、试题查询
void findQuestion(ChoiceQuestion *head1,ChoiceQuestion *t1,ChoiceQuestion *p1,BlanksQuestion *head2,BlanksQuestion *t2,BlanksQuestion *p2){
int id,count=0;
printf("\n\t请输入要查找题目的编号:");
scanf("%d",&id);
getchar();
if(head1==NULL)
printf("\n\t选择题题库是空的\n");
else{
if(head1->num==id){
printf("\n\t选择题题目是:"); puts(head1->topic);
printf("\n\t选项A是:"); puts(head1->A);
printf("\n\t选项B是:"); puts(head1->B);
printf("\n\t选项C是:"); puts(head1->C);
printf("\n\t选项D是:"); puts(head1->D);
printf("\n\t答案是:"); puts(head1->answer);
printf("\n\t查找成功\n");
count++;
} else{
while(p1!=NULL){
if(p1->num==id){
printf("\n\t选择题题目是:"); puts(p1->topic);
printf("\n\t选项A是:"); puts(p1->A);
printf("\n\t选项B是:"); puts(p1->B);
printf("\n\t选项C是:"); puts(p1->C);
printf("\n\t选项D是:"); puts(p1->D);
printf("\n\t答案是:"); puts(p1->answer);
printf("\n\t查找成功\n");
count++;
break;
}else
p1 = p1->next;
}
}
}
if(head2==NULL)
printf("\n\t填空题题库是空的\n");
else{
if(head2->num==id){
printf("\n\t填空题题目是:"); puts(head2->topic);
printf("\n\t答案是:"); puts(head2->answer);
count++;
}else{
while(p2!=NULL){
if(p2->num==id){
printf("\n\t填空题题目是:"); puts(p2->topic);
printf("\n\t答案是:"); puts(p2->answer);
printf("\n\t查找成功\n");
count++;
break;
}else
p2 = p2->next;
}
}
}
if(count=0)
printf("\n\t题目查询失败");
getchar();
}
//7、统计数目总数
void totalQuestion(ChoiceQuestion *head1,ChoiceQuestion *t1,ChoiceQuestion *p1,BlanksQuestion *head2,BlanksQuestion *t2,BlanksQuestion *p2){
int n1=0,n2=0;
p1=head1,p2=head2;//遍历链表
while(p1!=NULL){
p1=p1->next;
n1++;
}
while(p2!=NULL){
p2=p2->next;
n2++;
}
printf("\n\t选择题题目总数为:%d",n1);
printf("\n\t填空题题目总数为:%d",n2);
printf("\n\t所有题目总数为:%d",n1+n2);
}
//8、查询含有特定内容的题目内容
void searchQuestion(ChoiceQuestion *head1,ChoiceQuestion *t1,ChoiceQuestion *p1,BlanksQuestion *head2,BlanksQuestion *t2,BlanksQuestion *p2){
system("cls");
printf("\n\t请输入需要查找的内容:");
char s[1000];
gets(s);
int count=0;
p1=head1,p2=head2;
while(p1!=NULL){
if( strstr(p1->topic,s)!=NULL || //查询字符串s是否是该题子串
strstr(p1->A,s)!=NULL ||
strstr(p1->B,s)!=NULL ||
strstr(p1->C,s)!=NULL ||
strstr(p1->D,s)!=NULL ){
count=1;
printf("\n\t待查询的内容属于选择题,题号是:%d\n",p1->num);
printf("\n\t题目是:"); puts(p1->topic);
printf("\n\t选项A是:"); puts(p1->A);
printf("\n\t选项B是:"); puts(p1->B);
printf("\n\t选项C是:"); puts(p1->C);
printf("\n\t选项D是:"); puts(p1->D);
printf("\n\t答案是:"); puts(p1->answer);
}
p1 = p1->next;
}
while(p2!=NULL){
if( strstr(p2->topic,s)!=NULL ){
count=1;
printf("\n\t待查询的内容属于填空题,题号是:%d\n",p2->num);
printf("\n\t题目是:"); puts(p2->topic);
printf("\n\t答案是:"); puts(p2->answer);
}
p2 = p2->next;
}
if(count) printf("\n\t查询成功!");
else printf("\n\t查询失败");
}
//生成试卷
void promoteQuestion(ChoiceQuestion *head1,ChoiceQuestion *t1,ChoiceQuestion *p1,BlanksQuestion *head2,BlanksQuestion *t2,BlanksQuestion *p2){
system("cls");
FILE *examFile = fopen("D:\\exam.txt","w"); //重写
FILE *answerFile = fopen("D:\\answer.txt","w");
int s[1000],w=0,count=0,flag=0;
int n1,r,i,j,k,m;
p1=head1,p2=head2;
while(p1!=NULL){
p1=p1->next;
count++;
}
while(p2!=NULL){
p2=p2->next;
flag++;
}
printf("\n\t选择题题目总数为:%d",count);
printf("\n\t填空题题目总数为:%d",flag);
printf("\n\t请输入你要生成的选择题的数量:");
scanf("%d",&n1); getchar();
printf("\n\t请输入你要生成的填空题的数量:");
scanf("%d",&r); getchar();
if(n1>count||r>flag){
if(n1>count)
printf("\n\t超出了选择题题库中的题目数量");
if(r>flag)
printf("\n\t超出了填空题题库中的题目数量");
}else{
for(i=0;i<n1;i++){
int r=0,y=0;
w=rand()%number;
s[i]=w;
for(j=0;j<i;j++){
if(s[j]==s[i]){
y++;
break;
}
}
if(y!=0){
i=0;
continue;
}
p1=head1;
if(head1->num==w){
fprintf(examFile,"%d %s\n",head1->num,head1->topic);
fprintf(examFile,"%s\n%s\n%s\n%s\n",head1->A,head1->B,head1->C,head1->D);
fprintf(answerFile,"%d %s\n",head1->num,head1->answer);
r++;
}else{
while(p1!=NULL){
if(p1->num==w){
fprintf(examFile,"%d %s\n",p1->num,p1->topic);
fprintf(examFile,"%s\n%s\n%s\n%s\n",p1->A,p1->B,p1->C,p1->D);
fprintf(answerFile,"%d %s\n",p1->num,p1->answer);
r++;
break;
}else
p1=p1->next;
}
}
if(r==0){
i--;
continue;
}
}
for(k=n1;k<n1+r;k++){
int r=0,y=0;
w=rand()%number;
s[k]=w;
for(m=0;m<k;m++){
if(s[m]==s[k]){
y++;
break;
}
}
if(y!=0){
k--;
continue;
}
p2=head2;
if(head2->num==w){
fprintf(examFile,"%d %s\n",head2->num,head2->topic);
fprintf(answerFile,"%d %s\n",head2->num,head2->answer);
r++;
}else{
while(p2!=NULL){
if(p2->num==w){
fprintf(examFile,"%d %s\n",p2->num,p2->topic);
fprintf(answerFile,"%d %s\n",p2->num,p2->answer);
r++;
break;
}else
p2=p2->next;
}
}
if(r==0){
k--;
continue;
}
}
printf("\n\t试卷生成成功");
}
fclose(examFile);
fclose(answerFile);
getchar();
}
int main(){
srand((unsigned)time(NULL));
ChoiceQuestion *head1,*t1,*p1;
BlanksQuestion *head2,*t2,*p2;
FILE *choiceFile = fopen("D:\\xuanzeti.txt","r+");
FILE *blanksFile = fopen("D:\\tiankong.txt","r+");
head1 =NULL, head2 = NULL;
t1=(ChoiceQuestion*)malloc(sizeof(ChoiceQuestion)),t2=(BlanksQuestion*)malloc(sizeof(BlanksQuestion));
//将文件内容读入链表中
while(fscanf(choiceFile,"%d\n",&number)!=EOF){
p1 = (ChoiceQuestion*)malloc(sizeof(ChoiceQuestion));
if(head1==NULL) head1 = p1;
else t1->next=p1;
p1->next = NULL;
fscanf(choiceFile,"%s\n",p1->topic);
fscanf(choiceFile,"%s\n",p1->A);
fscanf(choiceFile,"%s\n",p1->B);
fscanf(choiceFile,"%s\n",p1->C);
fscanf(choiceFile,"%s\n",p1->D);
fscanf(choiceFile,"%c\n",&p1->answer);
p1->num = number;
t1 = p1;
number++;}
while(fscanf(blanksFile,"%d\n",&number)!=EOF){
p2 = (BlanksQuestion*)malloc(sizeof(BlanksQuestion));
if(head2 == NULL) head2 = p2;
else t2->next=p2;
p2->next = NULL;
fscanf(blanksFile,"%s\n",p2->topic);
fscanf(blanksFile,"%s\n",p2->answer);
p2->num = number;
t2 = p2;
number++;
}
fclose(choiceFile);
fclose(blanksFile);
int type;
while(1){
printf("\n\n\t\t欢迎进入试卷管理系统");
printf("\n\n\t菜单:\n");
printf("\n\t 1 试题添加");
printf("\n\t 2 试题删除");
printf("\n\t 3 备份全部试题");
printf("\n\t 4 删除全部试题");
printf("\n\t 5 试题修改");
printf("\n\t 6 试题查询");
printf("\n\t 7 统计共有多少道题目");
printf("\n\t 8 查询题目中含有某个特定内容的所有题目");
printf("\n\t 9 自动随机生成试卷及标准答案2个文件");
printf("\n\t 0 退出\n");
printf("\n\n\t 请选择你需要执行的操作:");
scanf("%d",&type);
getchar();
switch(type){
case 1: addQuestion(); break;
case 2: deleteQuestion(head1,t1,p1,head2,t2,p2); break;
case 3: backupQuestion(head1,t1,p1,head2,t2,p2); break;
case 4: deleteAllQuestion(); break;
case 5: modifyQuestion(head1,t1,p1,head2,t2,p2); break;
case 6: findQuestion(head1,t1,p1,head2,t2,p2); break;
case 7: totalQuestion(head1,t1,p1,head2,t2,p2); break;
case 8: searchQuestion(head1,t1,p1,head2,t2,p2); break;
case 9: promoteQuestion(head1,t1,p1,head2,t2,p2); break;
case 0:
printf("退出系统\n");
exit(0);
break;
default:
break;
}
}
return 0;
}