题目分析
任务二:例2为单词小助手,要求完成以下任务:
1.改写程序为良好程序风格(文档注释,函数注释,语句注释)。
2.将单词测试中的功能完善,可针对做错的单词重复记忆。
3.查询单词的功能添加英文词查询,中文查询的功能完善(考虑如何显示同样中文意义,不同的英文单词)
提高要求:
可将程序中的不足(如数据验证,排名功能)等根据自己的能力与理解完成。
算法构造
流程图:
总图:
英中单词测试:
中英测试:
增加单词:
查询单词:
N-S图:
英中测试:
中英测试:
添加单词:
程序实现
#author:lyq
#time:2019-04-03
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define MAX_CHAR 20 // 最大字符
#define MAX_NUM 200 // 单词的最大个数
#define MAX_MAN 1000 // 用户最大个数
struct word
//单词的结构体
{
char en[MAX_CHAR]; // 英文形式
char ch[MAX_CHAR]; //中文形式
} s[MAX_NUM]; //单词数组
struct user
{ int d;//用户正确次数
int c;//用户错误次数
}users[MAX_MAN];
struct man//用户结构体
{
int no;
int score;
};
struct man mans[MAX_MAN];//用户的结构体数组
struct man temp;
//int score[MAX_MAN]={0}; //用户得分数组
int num; //单词个数
int select=1;//select 为是否退出系统的标记
//返回0:无中文,返回1:有中文
int ifChinese(char *str)
{
int n = 0;
char c;
while(c=*str++)
{
//如果字符高位为1且下一字符高位也是1则有中文字符
if((c&0x80)&&(*str & 0x80))
{
n = 1;
break;
}
}
return n;
}
//返回0:无英文,返回1:有英文或者数字这些符号
int ifEnglish(char *str)
{
int n = 0;
char c;
while(c=*str++)
{
//如果字符高位为1且下一字符高位也是1则有中文字符
if('a'<=c&&c<='z'||'A'<=c&&c<='Z'||'0'<=c&&c<='9')
{
n = 1;
break;
}
}
return n;
}
//帮助
void help()
{
printf("\n本系统主要实现英语单词学习的功能。用户可对词典文件中的单词进行预览,增删改查。");
printf("\n同时还可进行中英、英中测试。本系统还提供了测试单人成绩,成绩排行的显示功能。\n");
}
//向文件中输入单词信息
void readfile()
{
FILE *fp;
int i=0;
fp=fopen("E://data1.txt","r");
if(!fp)
{
printf("\n打开文件data1.txt失败!");
}
while(fscanf(fp,"%s %s ",s[i].en,s[i].ch)==2)
{
i++;
}
num=i;
if(0==i)
printf("\n文件为空,请选择词典维护!");
else
printf("\n");
fclose(fp);
}
//从文件中读取单词的信息
void writefile()//输出文件中单词的信息
{
FILE *fp;
int i=0;
fp=fopen("E://data1.txt","w");
if(!fp)
{
printf("\n打开文件data1.txt失败!");
}
for(i=0;i<num;i++)
{
fprintf(fp,"\n%s %s ",s[i].en,s[i].ch);
}
printf("\n");
fclose(fp);
}
void vsort()/*按字典排序*/
{
int i,j;
char temp[MAX_CHAR];
for(i=0;i<num-1;i++)
{
for(j=num-1;j>i;j--)
if(strcmp(s[j-1].en,s[j].en)>0)
{
strcpy(temp,s[j-1].en);
strcpy(s[j-1].en,s[j].en);
strcpy(s[j].en,temp);
strcpy(temp,s[j-1].ch);
strcpy(s[j-1].ch,s[j].ch);
strcpy(s[j].ch,temp);
}
}
}
//添加单词信息
void add()
{
int i=num,j,flag=1;
while(flag)
{
flag=0;
printf("\n请输入单词的英文形式:");
scanf("%s",s[i].en);
while(ifChinese(s[i].en)==1)//输入中包含中文字符
{
printf("输入错误!请重新输入!\n");
scanf("%s",s[i].en);
}
for(j=0;j<i;j++)
if(strcmp(s[i].en,s[j].en)==0)
{
printf("已有该单词,请检查后重新录入!\n");
flag=1;
break; /*如有重复立即退出该层循环,提高判断速度*/
}
}
printf("\n请输入单词的中文形式:");
scanf("%s",s[i].ch);
while(ifEnglish(s[i].ch)==1)//输入中包含英文字符和数字
{
printf("输入错误!请重新输入!\n");
scanf("%s",s[i].ch);
}
num++;
printf("\n您输入的信息为: 英文: %s 中文: %s ",s[i].en,s[i].ch);
vsort();
}
//删除单词信息
void del()
{
int i=0,j=0;
char en[MAX_CHAR]; //英文形式
printf("\n请输入你要删除的单词英文形式:");
scanf("%s",en);
for(i=0;i<num;i++)//先找到该英文形式对应的序号
if(strcmp(s[i].en,en)==0)
{
for(j=i;j<num-1;j++)
s[j]=s[j+1];
num--; //数量减少 1
return;
}
printf("\n没有这个单词!");
}
//修改单词信息
void modify()
{
int i=0,choose=0,flag=1;//chooses代表选项标识,flag代表是否找到单词
char en[MAX_CHAR]; //英文形式
while(flag||choose)
{
printf("\n请输入你要修改的单词英文形式:");
scanf("%s",en);
for(i=0;i<num;i++)//先找到该英文形式对应的序号
if(strcmp(s[i].en,en)==0)
{
printf("\n请输入单词正确的英文形式:");
scanf("%s",s[i].en);
while(ifChinese(s[i].en)==1)//输入中包含中文字符
{
printf("输入错误!请重新输入!\n");
scanf("%s",s[i].en);
}
printf("\n请输入此单词正确的的中文形式:");
scanf("%s",s[i].ch);
while(ifEnglish(s[i].ch)==1)//输入中包含英文字符
{
printf("输入错误!请重新输入!\n");
scanf("%s",s[i].ch);
}
printf("\n继续修改请选1,返回上一级请选0:");
scanf("%d",&choose);
if(choose==0) return;
}
flag=0;
}
if(!flag) printf("\n没有这个单词!");
}
//单词预览
void show()
{
int i=0;
printf("\n单词: 英文 中文 ");
for(i=0;i<num;i++)
printf("\n %-12s%-12s",s[i].en,s[i].ch);
printf("\n");
}
//查询单词
void search()
{
int i=0,flag=1;
int choose;
char ch[MAX_CHAR];
printf("中文查询请选1,英文查询请按2\n");
scanf("%d",&choose);
while(choose||flag)
{
switch(choose)
{
case 1:
{
int eng[num]={0};//记录对应的词的对应下标序号
int d=0;
printf("\n请输入你要查询的单词中文形式:");
scanf("%s",ch);
while(ifEnglish(s[i].ch)==1)//输入中包含英文字符和数字
{
printf("输入错误!请重新输入!\n");
scanf("%s",s[i].ch);
}
for(i=0;i<num;i++)//先找到该中文形式对应的所有序号
{
if(strcmp(s[i].ch,ch)==0)
{
eng[d++]=i;
}
}
printf("\n中文形式 %-12s",s[eng[i]].ch);
for(int k=0;k<d;k++)
{
printf("\n英文形式 %-12s",s[eng[k]].en);
}
printf("\n继续中文查询请选1,英文查询请选2,返回上一级请选0:");
for(int j=0;j<d;j++)//将数组eng[]置零
{
eng[j]=0;
}
d=0;
scanf("%d",&choose);
if(choose==0)
return;
flag=0;
break;
}
case 2:
{
printf("\n请输入你要查询的单词英文形式:");
scanf("%s",ch);
while(ifChinese(s[i].en)==1)//输入中包含中文字符
{
printf("输入错误!请重新输入!\n");
scanf("%s",s[i].en);
}
for(i=0;i<num;i++)//先找到该中文形式对应的序号
if(strcmp(s[i].en,ch)==0)
{
printf("\n英文形式 中文形式 ");
printf("\n %-12s%12s",s[i].en,s[i].ch);
printf("\n继续中文查询请选1,英文查询请选2,返回上一级请选0:");
scanf("%d",&choose);
if(choose==0)
return;
}
flag=0;
break;
}
default:
break;
}
}
if(!flag)
printf("\n没有这个单词!");
}
//做错的测试单词的重复记忆
void againrem(int *a,int &d)
{
printf("现在开始出错单词的重复记忆!\n");
for(int i=0;i<d;i++)
{
printf("中文: [%s]",s[a[i]].ch);
printf("英文: [%s]",s[a[i]].en);
printf("\n");
a[i]=0;//将对应位置序列数置零.
}
}
//中译英测试
void zytest(int no)
{ users[no].c=users[no].d=0;
int ifwrong=0;//1表示错误过,0表示一遍即正确测试通过
char b1[20];//输入英语单词答案的数组
int cuo[MAX_NUM]={0}; //记录测试错误单词的序号的数组
int z;
int t=0;//记录cuo数组的下标变化的变量
int choose=1;
int i;
while(choose)
{
i = rand()%num;//调用随机函数,随机取中文词
printf("\n【%s】请输入英文单词:",s[i].ch);//针对显示随机选择的中文词
scanf("%s",b1);//对于选择的单词的中文意思,写自己的答案
for(z=0;strcmp(b1,s[i].en)!=0;z=z)
{
ifwrong=1;
printf("\n输入错误!!请重新输入:");
scanf("%s",b1);
users[no].c=users[no].c+1;
}
if(ifwrong)
{
cuo[t++]=i;
ifwrong=0;
}
printf("\n恭喜你,回答正确,加10分!\n\n");
users[no].d=users[no].d+1;
printf("\n进行错误单词复习请选2,继续测试请选1,返回上一级请选0:");
scanf("%d",&choose);
if(choose==0||choose==2)
{
if(choose==2)//选择了单词复习
{
againrem(cuo,users[no].d);
t=0;
}
return;
}
}
}
//英译中测试
void yztest(int no)
{
users[no].c=users[no].d=0;
int ifwrong=0;//1表示错误过,0表示一遍即正确测试通过
char b1[20];//输入英语单词答案的数组
int cuo[MAX_NUM]={0}; //记录测试错误单词的序号的数组
int z,x=41;
int t=0;//记录cuo数组的下标变化的变量
int choose=1;
int i;
i = rand()%num;//随机选择测试词对应的序号
while(choose)
{
printf("【%s】请输入中文意思:",s[i].en);
scanf("%s",b1);
for(z=0;strcmp(b1,s[i].ch)!=0;z=z)
{
ifwrong=1;
printf("输入错误!!请重新输入:");
scanf("%s",b1);
users[no].c=users[no].c+1;
}
if(ifwrong)
{
cuo[t++]=i;
ifwrong=0;
}
printf("\n恭喜你,回答正确,加10分!\n\n");
users[no].d=users[no].d+1;
printf("\n继续测试请选1,返回上一级请选0:");
scanf("%d",&choose);
if(choose==0||choose==2)
{
if(choose==2)//单词复习
{
againrem(cuo,users[no].d);
t=0;
}
return;
}
}
}
//单个用户的成绩查询
void list(int no)//no为当前结构体数组序号
{
printf("用户:%d的得分情况如下: \n",no);
printf("\n 本次测试共计输入错误:%d次 **每次扣10分**\n",users[no].c);
printf(" 本次测试共计输入正确:%d次 **每次加10分**\n",users[no].d);
printf(" 本次测试总得分为:%d分\n\n",10*users[no].d-10*users[no].c);
mans[no-1].score=10*users[no].d-10*users[no].c;
mans[no-1].no=no;
// printf("用户%d 总得分为:%d分\n\n",mans[no-1].no,mans[no-1].score);
}
//成绩排行榜
void paihang(int no)//no是用户总个数
{
//进行排序
for(int j=0;j<no;j++)
{
for(int k=1;k<no-j;k++)
{
if(mans[k-1].score>mans[k].score)
{
temp=mans[k-1];
mans[k-1]=mans[k];
mans[k]=temp;
}
}
}
for(int i=no-1;i>=0;i--)//按得分从高到低,依次输出用户情况
{
printf("用户: %d 得分为: %d\n",mans[i].no,mans[i].score);
}
}
//词典维护
void maintain()
{
int choose;//维护功能选择
printf(" ------------------\n");
printf(" 1.增加单词\n");
printf(" 2.修改单词\n");
printf(" 3.删除单词\n");
printf(" 4.查询单词\n");
printf(" 5.退出本菜单\n");
printf(" ------------------\n");
while(1)
{
printf(" \n请输入维护功能编号:");
scanf("%d",&choose);
switch(choose)
{
case 1:
add();writefile();break;
case 2:
modify();writefile();break;
case 3:
del();writefile();break;
case 4:
search();break;
case 5: return;
default: printf("\n请在1-5之间选择");
}
}
}
int a[MAX_MAN]={0};//定义的数组
int t=0;
int flag=1;// 判断是否为重复的用户ID的变量
//用户界面
void menu()
{
int item;
int no;//当前用户的ID编号
printf("请输入当前使用小助手的用户编号为: \n");
scanf("%d",&no);//输入相应的用户编号
for(int i=0;i<MAX_MAN;i++)
{
if(a[i]==0)
continue;
else if(a[i]==no)
{
flag=0;//现在的用户是以前出现过的。
break;
}
}
if(flag)//用户ID非重复!
a[t++]=no;
printf("*********************************************************\n");
printf("# #\n");
printf("# 英语单词小助手 #\n");
printf("# #\n");
printf("# 版本 : v1.0 #\n");
printf("# #\n");
printf(" *********************************************************\n");
printf("# #\n");
printf("# 0.词库维护 1.单词预览 #\n");
printf("# #\n");
printf("# 2.单词背诵(中英) 3.单词背诵(英中) #\n");
printf("# #\n");
printf("# 4.查询成绩 5.帮助 #\n");
printf("# #\n");
printf("# 6.查看成绩排行 7.退出单词小助手 #\n");
printf("# #\n");
printf(" **********************************************************\n");
printf("\n");
printf(" 请选择您需要的操作序号(0-7)按回车确认:");
int sum;
scanf("%d",&item);
printf("\n");
readfile();
switch(item)
{
case 0:
maintain();break;
case 1:
show();break;
case 2:
{
zytest(no);
break;
}
case 3:
{
yztest(no);
break;
}
case 4:
{
list(no);break;
}
case 5:
help();break;
case 6:
{ printf("用户总数为:%d\n",t);
paihang(t);break;
}
case 7:
select =0;break;
default:
printf("请在0-7之间选择\n");
}
flag=1;
}
int main()
{
while(select)
{
menu();
}
system("pause");
return 0;
}
调试及测试
调试:
测试截图:
- 词库处理(包含相应的数据错误输入处理,例如输入的英文单词中包含了中文字符)
增加单词
修改单词
删除单词
单词预览
进行单词测试,并且查询成绩
帮助:
测试中出错单词的重复记忆:
查看成绩排行
经验归纳
总结:
这次的上机实验,我选择了第二个题目,对一个单词小助手程序进行功能完善与提高。
针对做错单词的重复记忆,在进行单词测试时,用一个int型数组记录相应的错误单词的在词库中的序号,同时用一个变量记录错误单词个数。在选择错误单词的重复记忆功能之后,用将上面保存错误单词的数组拿出来进行单词的重复记忆。
对于中文查询功能的完善,即显示同一中文意思,多个英文单词。为实现这个功能,在进行词库的单词添加时,添加中文相同,英文不同的单词时,有几个英文,就添加几次,即让每一个英文词都有一个对应的单词序号(即使它们的英文词对应的中文相同),这样,在相应的查询时,对于词库中每个与输入的中文相同的单词,同样用一个int数组记录它们的序号,接下来在一个循环中输出这些序号对应的英文词即可得到相应的一个中文词对应多个意思相同的英文词的结果
对于提高要求中的数据验证,在添加和查询单词等功能中,使用了字符判断的方法,对于输入字符的每一个字符,都进行判断是否为不符合的字符,一旦判断为非法字符,直接进行错误处理并重新输入。如在输入中文时,输入中包含了英文字符,即为非法输入了。
而对于相应的排名功能,我在原来的基础上,添加了一个包含用户ID号和用户得分的用户结构体。在使用单词小助手时,会首先进行用户选择,对于每个用户的测试成绩,疾苦在上面定义的结构体数组中,成绩排行即将分数降序排序并输出。
这次的上机对于结构体的使用与理解在以前的基础上有所加深与提高,但是程序仍有一些不足,希望自己在以后的实验中能够改进。