1.题目回顾:
实现单词小助手,要求完成以下任务:
1.改写程序为良好程序风格(文档注释,函数注释,语句注释)。
2.将单词测试中的功能完善,可针对做错的单词重复记忆。
3.查询单词的功能添加英文词查询,中文查询的功能完善(考虑如何显示同样中文意义,不同的英文单词)
提高要求:
可将程序中的不足(如数据验证,排名功能)等根据自己的能力与理解完成。
2.题目分析
本次作业是实现一个单词小助手,并实现添加英文词查询,中文查询,数据验证,排名,以及做错的单词重复记忆的功能。
3.关键算法构造
程序流程图:
冒泡排序算法流程图:
4.程序实现
程序源代码(请写入必要的注释)。
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include<time.h>
#define MAX_CHAR 20 // 最大字符
#define MAX_NUM 200 // 单词的最大个数
#define MAX_NUM_PEOPLE 20//排名功能最大人数
struct word
//单词的结构体
{
char en[MAX_CHAR]; // 英文形式
char ch[MAX_CHAR]; //中文形式
} s[MAX_NUM]; //单词数组
struct sort
//排名功能中人的结构体
{
int d = 0;//保存答对次数
int c = 0;//保存答错次数
int score;//最后得分
char name[MAX_CHAR];//用户的名字
}p[MAX_NUM_PEOPLE];//用户数组
int num; //单词个数
int num_sort=0;//用户名个数
int select = 1;//select 为是否退出系统的标记
//帮助
void help()
{
printf("\n本系统主要实现英语单词学习的功能。用户可对词典文件中的单词进行预览,增删改查。");
printf("\n同时还可进行中英、英中测试。本系统还提供了测试成绩的显示功能。");
}
//从文件中读取单词的信息
void readfile()
{
//文件读取
FILE *fp;
int i = 0;
fp = fopen(“data.txt”, “r”);//以读的方式打开文件
if (!fp)//判断文件是否为空,为空则输出错误提示信息
{
printf("\n打开文件data.txt失败!");
}
//读取信息
while (fscanf(fp, “%s %s “, s[i].en, s[i].ch) == 2)
{
//验证数据正确性
if ((s[i].en[0] >= ‘a’&&s[i].en[0] <= ‘z’) || (s[i].en[0] >= ‘A’&&s[i].en[0] <= ‘Z’))//若读到的英文第一个字母不属于英文26字母,则数据错误
{
i++;
}
else
{
printf(“data error!读入的数据有误!\n”);//输出错误提示信息
i++;
}
}
num = i;//单词数量重新标记
if (0 == i)
printf(”\n文件为空,请选择词典维护增加词条!”);
else
printf("\n");
fclose(fp);//关闭文件
}
//用户排名信息读取
void read_sort_file() {
FILE *fp;
int i = 0;
fp = fopen(“sort.txt”, “r”);//以读的方式打开文件
if (!fp)//判断文件是否为空,为空则输出错误提示信息
{
printf("\n打开文件data.txt失败!");
}
//数据读取
while (fscanf(fp, “%s %d “, p[i].name,&p[i].score) == 2)
{
i++;
}
num_sort = i;//用户数量重新标记
if (0 == i)
printf(”\n文件为空!”);
else
printf("\n");
fclose(fp);//关闭文件
}
//输出单词信息到文件中
void writefile()
{
FILE *fp;
int i = 0;
fp = fopen(“data.txt”, “w”);//以写的方式打开文件
if (!fp)//判断文件是否为空,为空则输出错误提示信息
{
printf("\n打开文件data.txt失败!");
}
//输出信息
for (i = 0; i<num; i++)
{
fprintf(fp, "\n%s %s ", s[i].en, s[i].ch);
}
printf("\n");
fclose(fp);//关闭文件
}
//输出用户信息到文件中
void write_sort_file()
{
FILE *fp;
int i = 0;
fp = fopen(“sort.txt”, “w”);//以写的方式打开文件
if (!fp)//判断文件是否为空,为空则输出错误提示信息
{
printf("\n打开文件data.txt失败!");
}
//输出信息
for (i = 0; i<num_sort; i++)
{
fprintf(fp, "\n%s %d ", p[i].name,p[i].score);
}
printf("\n");
fclose(fp);//关闭文件
}
//用户得分高低排名
void rank()
{
//采用冒泡排序方法进行排序
for (int i = 0; i < num_sort - 1; i++) {
for (int j = 0; j <num_sort - 1 - i; j++) {
if (p[j].score > p[j + 1].score) {
int tmp = p[j + 1].score;
p[j + 1].score = p[j].score;
p[j].score = tmp;
char nam[MAX_CHAR];
strcpy(nam, p[j + 1].name);
strcpy(p[j + 1].name, p[j].name);
strcpy(p[j].name,nam);
}
}
}
//输出排名信息
for (int i = 0; i < num_sort; i++)
{
printf("%s %d\n", p[i].name, p[i].score);
}
}
void sort()/按字典排序/
{
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);
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);
num++;
printf("\n您输入的信息为: 英文: %s 中文: %s “, s[i].en, s[i].ch);
sort();
}
//删除单词信息
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);
printf("\n请输入此单词正确的的中文形式:");
scanf("%s", s[i].ch);
printf("\n继续修改请选1,返回上一级请选0:");
scanf("%d", &choose);//用户输入选择
if (choose == 0) return;//选0结束函数调用
}
flag = 0;//存在要查询的单词则使标记变为0
}
if (!flag) printf("\n没有这个单词!");
}
//单词预览
void show()
{
int i = 0;
printf(“单词: 英文 中文 “);
//循环输出单词信息
for (i = 0; i<num; i++)
printf(”\n %-12s%-12s”, s[i].en, s[i].ch);
}
//按中文形式查询单词
void search_ch()
{
int i = 0, choose = 0, flag = 1;
char ch[MAX_CHAR]; //中文形式
while (choose || flag)
{
printf("\n请输入你要查询的单词中文形式:");
scanf("%s", ch);
for (i = 0; i<num; i++)//先找到该中文形式对应的序号
if (strcmp(s[i].ch, ch) == 0)
{
//输出对应序号的单词信息
printf("\n英文形式 中文形式 “);
printf(”\n %-12s%12s", s[i].en, s[i].ch);
}
printf("\n继续查询请选1,返回上一级请选0:");
scanf("%d", &choose);//用户输入选择
if (choose == 0) return;//结束函数调用
flag = 0;//存在要查询的单词则使标记变为0
}
if (!flag) printf("\n没有这个单词!");
}
//按英文形式查询单词
void search_en()
{
int i = 0, choose = 0, flag = 1;
char en[MAX_CHAR]; //英文形式
while (choose || flag)
{
printf("\n请输入你要查询的单词英文形式:");
scanf("%s", en);
for (i = 0; i<num; i++)//先找到该英文形式对应的序号
if (strcmp(s[i].en, en) == 0)
{
//输出对应序号的单词信息
printf("\n英文形式 中文形式 “);
printf(”\n %-12s%12s", s[i].en, s[i].ch);
printf("\n继续查询请选1,返回上一级请选0:");
scanf("%d", &choose);//用户输入选择
if (choose == 0) return;//结束函数调用
}
flag = 0;//存在要查询的单词则使标记变为0
}
if (!flag) printf("\n没有这个单词!");
}
//输出本次用户的单词背诵情况信息
void list()
{
printf("\n 共计输入错误:%d次 每次扣10分\n", p[num_sort].c);
printf(" 共计输入正确:%d次 每次加10分\n", p[num_sort].d);
printf(" 你的总得分为:%d分\n\n", 10 * p[num_sort].d - 10 * p[num_sort].c);
}
//中译英测试
void zytest()
{
//输入用户名
printf(“请输入您的姓名:\n”);
scanf("%s", p[num_sort].name);
srand(time(0));//设置随机种子,使每次打开程序单词背诵顺序改变
char b1[20];//保存用户输入的英文单词
int z;
int choose = 1;
int i;
int count = 3;
int j = 0;
while (choose)
{
i = rand() % num;//生成要背诵的单词序号
while (j!=0)//背诵错误的单词进行重复记忆
{
i = j;
count–;//默认进行三次重新记忆,每重新记完一次标记减一
printf("\n【%s】请输入英文单词:", s[i].ch);
scanf("%s", b1);
//和当前背诵单词信息进行比较
for (z = 0; strcmp(b1, s[i].en) != 0; z = z)
{
printf("\n输入错误!!请重新输入:"); scanf("%s", b1);
}
printf("\n恭喜你,回答正确!\n\n");
if (count == 0) {
break;//三次记忆完后,退出重复记忆模块
}
}
i = rand() % num;
printf("\n【%s】请输入英文单词:", s[i].ch);
scanf("%s", b1);
//和当前背诵单词信息进行比较
for (z = 0; strcmp(b1, s[i].en) != 0; z = z)
{
j = i;
printf("\n输入错误!!请重新输入:"); scanf("%s", b1); p[num_sort].c = p[num_sort].c + 1;//回答错误答错标记加一
}
printf("\n恭喜你,回答正确,加10分!\n\n"); p[num_sort].d = p[num_sort].d + 1;//回答正确答错标记加一
printf("\n继续测试请选1,返回上一级请选0:");
scanf("%d", &choose);
if (choose == 0) {//选0结束背诵并输出背诵的情况信息
list();
p[num_sort].score = 10 * p[num_sort].d - 10 * p[num_sort].c;
num_sort++; printf("\n %d",num_sort);
return;
}
}
}
//英译中测试
void yztest()
{
printf(“请输入您的姓名:\n”);
scanf("%s", p[num_sort].name);
srand(time(0));//生成要背诵的单词序号
char b1[20];
int z, x = 41;
int choose = 1;
int i;
int count = 3;
int j = 0;
while (choose)
{
i = rand() % num;
while (j != 0) //背诵错误的单词进行重复记忆
{
i = j;
count–;//默认进行三次重新记忆,每重新记完一次标记减一
printf("【%s】请输入中文意思:", s[i].en);
scanf("%s", b1);
//和当前背诵单词信息进行比较
for (z = 0; strcmp(b1, s[i].ch) != 0; z = z)
{
printf(“输入错误!!请重新输入:”); scanf("%s", b1);
}
printf("\n恭喜你,回答正确!\n\n");
if (count == 0) {
break;//三次记忆完后,退出重复记忆模块
}
}
i = rand() % num;
printf("【%s】请输入中文意思:", s[i].en);
scanf("%s", b1);
//和当前背诵单词信息进行比较
for (z = 0; strcmp(b1, s[i].ch) != 0; z = z)
{
j = i;
printf(“输入错误!!请重新输入:”); scanf("%s", b1); p[num_sort].c = p[num_sort].c + 1;//回答错误答错标记加一
}
printf("\n恭喜你,回答正确,加10分!\n\n"); p[num_sort].d = p[num_sort].d + 1;//回答正确答错标记加一
printf("\n继续测试请选1,返回上一级请选0:");
scanf("%d", &choose);
if (choose == 0) {//选0结束背诵并输出背诵的情况信息
list();
p[num_sort].score = 10 * p[num_sort].d - 10 * p[num_sort].c;
num_sort++;
return;
}
}
}
//成绩列表
//词典维护
void maintain()
{
int choose;//维护功能选择
printf(" ------------------\n");
printf(" 1.增加单词\n");
printf(" 2.修改单词\n");
printf(" 3.删除单词\n");
printf(" 4.按中文单词\n");
printf(" 5.按英文单词\n");
printf(" 6.退出本菜单\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_ch(); break;
case 5://按英文单词查询
search_en(); break;
case 6://退出本模块
return;
default: printf("\n请在1-5之间选择");
}
}
}
//用户界面
void menu()
{
int item;
//printf("\n");
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.退出系统 #\n");
printf("# #\n");
printf(" **********************************************************\n");
printf("\n");
printf(" 请选择您需要的操作序号(0-5)按回车确认:");
scanf("%d", &item);//用户输入选择
printf("\n");
switch (item)
{
case 0:
maintain(); system(“pause”); system(“cls”); break;
case 1:
show(); system(“pause”); system(“cls”); break;
case 2:
zytest(); system(“pause”); system(“cls”); break;
case 3:
yztest(); system(“pause”); system(“cls”); break;
case 4:
rank(); system(“pause”); system(“cls”); break;
case 5:
help(); system(“pause”); system(“cls”); break;
case 6:
select = 0; break;
default:
printf(“请在0-6之间选择\n”);
}
}
int main()
{
//读取单词及用户信息
readfile();
read_sort_file();
while (select)
{
menu();
}
write_sort_file();//输出用户信息到文件中
//system(“pause”);
return 0;
}
5.调试、测试及运行结果
程序运行主界面:
一开始输出的用户排名并没有做到真正的排名:
将代码进行修改:
修改前:
修改后:
修改后输出:
结果正确!
读取文件的时候发现新增加的信息无法添加到结构体中,经检查发现是因为将读取文件的函数放置在了menu函数中,这样每次回到主菜单就会又调用一遍读取函数,这显然是不行的:
修改前:
修改后:
将文件读取函数放置于main函数中,menu函数前,这样就只需读取一次即可,不会重复进行读取导致数据无法刷新到结构体中。
单词查询功能:
背诵功能:
单词预览功能:
帮助功能:
增加单词功能:
6.经验归纳
单词小助手是一款能锻炼具体综合运用能力的程序,文件的读取,文件的输出,冒泡排序的运用,结构体的设计,宏定义的设计,数据的遍历输出,这些都是非常重要的需要掌握的能力,其中,结构体让数据不再松散,而是一个完整的结构,便于操作的同时也增加了数据的可维护性、可读性,用户以及单词的设计都用到了结构体,冒泡排序是一种经典的,很常用的算法,在输出用户排名信息时就用到了这种算法,将用户得分的高低由小到大进行排序,之后进行输出。