本程模拟面对英语单词有背诵和查询需求的用户。用户在实际学习过程中可能会遇到学习单词时实体单词书体积大不方便的情况,这时就可以使用便携PC设备来运行此程序方便学习。在本程序中,设计设计了自动背单词的部分。每次给用户输出10个单词,用户自己进行背诵并且立即进行测试,在测试中本程序会记录用户对单词的掌握程度,并且形成熟练度等级。
在用户遇到新的单词时可以根据跟程序内部提供的词库实现查单词的功能。通过文件实现单词的读取,提供给用户。用户也可以直接访问词库,从而方便用户的使用。
本程序使用读取文件至链表和结构体数组实现具体的功能,并且把程序进行分模块进行设计,方便后期对程序的升级和改造。
本程序包括三部分,第一部分是将txt文件读取至程序链表内,第二部分实现了把txt文件按照结构体数据块的形式读取至程序内的结构体数组。第三部分是直接对txt文件的增删改操作。
在第一部分可以实现储存单词和词义的操作,并且把单词和词义的数据直接以链表的形式保存在程序中,在后期的一些具体功能可以直接根据链表的数据来实现。链表的建立方便了后期的更改,方便实现后期对程序的改造升级。
第二部分程序要实现把储存有结构体数据快的文件内容读取到内存中,并且根据序号实现对应的单词熟练度的显示。完成了单词具体内容的读取和储存以及对单词熟练度按照文件的方式的读取,方便了用户后期重复使用。
第三部分程序是直接更改储存有单词熟练度的文件,每次运行本程序的背单词部分的功能时都会改变单词的熟练。这是需要不停的更改文件的内容,在更改文件时是按照二进制的文件形式保存,用户不能轻易自己更改。
本系统实现了多个功能的设计,用户不但可以查单词还可以背单词以及进行自己的小测试,实现了多功能的设计特点。
单词以及单词熟练度的数据储存在文件里,从而让用户下次再打开程序时可以直接使用。而储存单词的文件使用了txt文件,并且txt文件内的单词和翻译按照非常统一对齐的方式储存,从而更方便的修改单词文件。而储存单词熟练度的文件和单词文件是两个分开的文件,熟练度通过二进制数据块的形式保存在文件中,用户无法直接获得和删改,方便了使用管理。
在后期使用过程中发现,用户自己增加词库时还要打开txt文件才能修改词库,后期可以改进实现通过单词系统直接向文件内增加单词。并且使用链表可能过分使用了内存资源,可以通过其他储存方式来实现单词储存。后期改进可以升级成使用数据库来储存单词,也可以使用网络来储存单词数据。
**
**
i下面是完整代码:
#include
#include
//
#include //负责malloc函数来调用内存
#include //实现退出函数
#include//输出随机数
//
#define total 5000 //定义了可以可以存放的单词总数量为5000个
#define file_path_1 "A:\\word\\word.txt" //使用宏定义定义两个文件的路径,方便更改
#define file_path_2 "A:\\word\\word_number.txt"
//
struct mation
{
int test;//储存是否考过 考过是1,没考过是0
int pfy;// 熟练等级 0没背过,1没背会,2考试未通过,3考试通过
}stu[total],array_stu;
//
struct word
{
int n; //单词的序号
char ci[100];
char yi[200];
struct word *next; //下一个节点
};
//
int number; //表示和n相对应
int all_number;//代表了链表的长度,但是在函数中难以体现 Z是单词的总数
//
//
int a_0[5000]; //熟练度为0的单词
int a_1[5000];
int a_2[5000];
int a_3[5000];
//
typedef struct word str;
struct word*head;
//
void end_struct(); //对结构体数组修改后进行重新覆盖保存
/*
*功 能:格式化输出单词
*过 程:每个单词的长度都不相同,因此按照每个单词固定20个空格的位置
输出单词后输出剩下的空格来让输出的单词和翻译对其格式
*输 入:单词的数组
*输 出:无
*/
void print_word(char a_word[]) //以20个单位长度为一个显示单元来显示单词
{
int l;
int longs=strlen(a_word);
if(longs<20)
{
l=20-longs;
printf("%s",a_word);
while(l>0)
{
l--;
printf(" "); //20剪掉单词的长度得到要输出的空格的数量
}
}
}
/*
*功 能:产生在一定范围内的随机数
*过 程:主要使用rand函数产生随机数
*输 入:整数
*输 出:无
*/
int random(int x)
{
srand(time(NULL)); //初始化随机数
x=rand()%x; //产生随机数
return(x);
}
/*
*功 能:把储存单词和词义的链表按照输入的序号输出到屏幕上
*过 程:遍历链表,根输入序号输出单词
*输 入:储存单词和翻译数据的链表首地址 ,要显示的单词序号
*输 出:无
*/
void find_xuhao(str*head,int i)//按照序号查找链表里面的单词是
{
str*p;
//
if(head==NULL)
{
printf("链表 \n");
}
//
p=head;
//
while(head!=NULL&&p!=NULL) //循环整个链表,知道找到匹配的序号
{
if (i == p->n) //判断序号
{
printf("\t%d.单词:",p->n);
print_word(p->ci); //按照格式化输出
printf("解释:%s\n",p->yi);
}
p = p -> next; //循环节目
}
}
//////////////////////////////////////////////////////////////////////
/*
*功 能:测试用户的单词掌握程度,每次测试5个
*过 程:首先遍历结构体数组,把里面所有元素清零,然后通过函数把空数组存入文件
*输 入:储存单词和翻译数据的链表首地址
*输 出:无
*/
void find_number(str*head)
{
//
int x,i=10,k; //i代表了单词的总数
//
while(1)
{
i++; //为了让每次random输出的随机数都不一样所以让i++来维持为此输入的数据不同
if(i>16)
break;
//
x=random(i);
//为了方式一次输出的所有数字都不一样,如果一样就多循环一次
if (k == x)//K相当于一个开关,起到了控制的作用
i--;
else
find_xuhao(head,x); //每生成一个随机数就数次一次
//
k=x;
}
}
//////////////////////////////////////////////////////////////////////
/*
*功 能:测试用户的单词掌握程度,每次测试5个
*过 程:首先遍历结构体数组,把里面所有元素清零,然后通过函数把空数组存入文件
*输 入:储存单词和翻译数据的链表首地址
*输 出:无
*/
void function_3 (str*head)
{
int i,j=0,k=0;
char a_word[20];
str*p;
str*now;
now = head;
//
if (head == NULL)
{
printf("链表 \n");
}
//
p = head;
//
printf("\n\n\n ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n");
printf(" \n");
printf(" 随机输出五个单词,考察背过的单词,答错两次将降低单词熟练度 \n\n");
while (1) //使用随机函数通过循环五次产生五个单词进行测试
{
printf(" \n按空格开始继续测验!!按0退出 \n");
int x = getch(); //产生随机数
if (x == ' ')
{
system("cls");
//
for (i=0;i<5000;i++) //在所有结构体数组里面进行循环
{
//
if (stu[i].pfy == 2) //熟练度为2等级的单词才会进行测试
{
//
if (k >= 5) //限定while循环只能循环五次
{
k = 0;
break;
}
k++;
//
while (head!=NULL&&p!=NULL) //如果循环到链表的结尾也退出
{
if (i == p->n) //根据结构体数组的序号和链表的序号进行匹配找到要要找到的的那次
{
printf("\t第%d个 拼写如下单词\n\n",p->n);
printf(" \t\t解释:%s",p->yi);
printf("\t->>> :") ;
//
scanf("%s",&a_word); //从键盘得到单词
//
j = strcmp (a_word,p->ci); //比较两个单词数组的值是否相同
//
if (j == 0) //正确情况
{
printf("正确");
stu[i].pfy =3; //提高一次熟练等级
printf("\n\n");
}
else //错误的情况
{
printf("错误");
printf("\n\t\t\t正确答案:");
print_word(p->ci); //打印出单词
printf("\n\n");
stu[i].pfy =2; //降低一次熟练等级
}
end_struct(); //对结构体数组修改后进行重新覆盖保存
}
p = p->next; //循环链表
}
p = head = now; //把链表的头重新找回来
}
}
}
else if (x=='0') return; //如果测试准备是得到的是0不是空格就会停止测试并退出
else printf(" 重新输入 \n\n");
}
}
//
///*************************************************************************第二部分功能
/*
*功 能:把所有的单词的熟练度都清除,把文件里面的熟练度也清除
*过 程:首先遍历结构体数组,把里面所有元素清零,然后通过函数把空数组存入文件
*输 入:无
*输 出:无
*/
void function_2_3()///把结构体数组的所有元素都化为0
{
int i;
for(i=0;in)
{
printf("\t第%d个 拼写如下单词\n\n",p->n);
printf(" \t\t解释:%s",p->yi);
printf("\t->>> :") ;
scanf("%s",&a_word);
//
j=strcmp(a_word,p->ci); //比较两个变量得到是否是正确的
if(j==0)
{
printf("正确");
stu[k].pfy =2; //提高一次熟练等级
printf("\n\n");
//
}
else
{
printf("错误");
printf("\n\t\t\t正确答案:");
print_word(p->ci); //按照特定格式输出一个单词
printf("\n\n");
stu[k].pfy =1; //降低一次熟练等级
}
end_struct(); //对结构体数组修改后进行重新覆盖保存
}
p=p->next; //进行链表的循环
}
p=head=now; //把链表的头重新找回来
}
}
//void shuchujiegouti(); ///把程序里面的结构体输出出来,,,在main函数附近
/*
*功 能:找到单词熟练度在1到0的单词进行背单词训练
*过 程:遍历列表,找到1和0熟练度的单词,把这是个单词的序号储存在数组里,并且传递个训练函数进行检测是否会被单词的过程
*输 入:储存单词和翻译的链表头结构体指针
*输 出:无
*/
void function_2_1(str*head) //搜索结构体数组里面的pfy元素,得到熟练度为0的a_0【】数组
{
int i,j=0;
int ten_words[10]; //存放十个单词的序号
//
for(i=1;i<5000;i++)
{
if(stu[i].pfy ==0||stu[i].pfy ==1)
{
printf("第%d个",j+1);
find_xuhao(head,i);
stu[i].pfy =1; //找到这个单词以后就让这个单词的熟练度变为1
ten_words[j]=i; //让找到的单词序号存放到数组里面
j++; //循环增加数组的位置
if(j>=10)
{
j=0;
i=0;
end_struct(); //对结构体数组修改后进行重新覆盖保存
function_2_1_test(head,ten_words ) ; //把刚刚抽到的十个单词进行测验
return;
}
}
}
}
//
/*
*功 能:在屏幕上输出第二部部分的功能界面
*过 程:调用了三个函数来实现过程
*输 入:储存单词和翻译的链表头结构体指针
*输 出:第二部分功能的界面
*/
void function_2(str*head)
{
while(1)
{
printf("\n\n\n ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n");
printf(" \n");
printf(" 1:开始背单词 \n\n"); //按找筛选和顺序输出十个单词加之检测
printf(" 2:最近背过的单词\n\n");
printf(" 3:清空所有背单词历史以及单词的熟练度\n\n");
printf("\n\t\t···按空格键返回 : \n");
//
int x=getch();
//
switch (x)
{
case '1':system("cls");function_2_1(head);break;
case '2':system("cls");function_2_2(head); break;
case '3':system("cls");function_2_3();break;
case ' ':system("cls");end_struct();return; //对结构体数组修改后进行重新覆盖保存
default:system("cls");printf("\n输入错误,请重新输入!"); break;
}
}
}
//
/*
*功 能:按照从键盘上输入的单词找到链表里面的单词
*过 程:遍历链表,同时使用 print_word 函数进行格式化输出单词,保证输出时规范整齐
*输 入:储存单词和翻译的链表头结构体指针
*输 出:把所有单词和翻译以及单词的数量输出到屏幕上
*/
void find_word(str*head)
{
str*p; //建立一个新的指针
char a_word[20]; //存放来自键盘后输入的单词数组
int sign; //判断标志,判断两个数组是否相同
//
system("cls");
if (head == NULL) //找之前先要判断是不是一个空链表
{
printf("是空链表\n");
}
//
p = head;
//
printf("\n\n\n ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n");
printf("\n\t\t···输入单词查找:");
//
scanf("%s",&a_word);
//
printf("\n\t\t···要找到是%s\n",a_word);
//
while (head!=NULL&&p!=NULL) //遍历链表
{
sign=strcmp(a_word,p->ci); //通过此函数比较两个单词是否完全相同
//
if(sign == 0) //如果单词相同
{
printf("\n\t%d.单词:",p->n);
print_word(p->ci); //通过这个函数按照一定格式在屏幕上打印出单词
printf("解释:%s\n",p->yi);
break; //找到单词后就退出循环
}
p = p->next;
}
printf ("\n\t\t···本词库内无( %s)\n\n",a_word );
}
/*
*功 能:把所有单词输出到屏幕上
*过 程:遍历链表,同时使用 print_word 函数进行格式化输出单词,保证输出时规范整齐
*输 入:储存单词和翻译的链表头结构体指针
*输 出:把所有单词和翻译以及单词的数量输出到屏幕上
*/
void print(str*head)//对链表数据的读取,可以用来向文件内输入
{
str*p;
if(head==NULL)
{
printf("是空链表\n");
}
printf("\n\t\t···链表内容如下\n");
p=head;
if(head!=NULL)
printf("\t\t···单词链表的单词数量:%d\n",all_number);
while(head!=NULL&&p!=NULL)
{
printf("%d.单词:",p->n);
print_word(p->ci);
printf("解释:%s\n",p->yi);
p=p->next;
//
}
}
/*
*功 能:第一部分查单词界面功能
*过 程:集合了两个小功能,具体功能通过其他函数显示,这里只显示界面
*输 入:储存单词词义和翻译的链表
*输 出:显示在屏幕上的界面
*/
void function_1(str*head)
{
while(1)
{
//
printf("\n\n\n ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n");
printf(" \n\n");
printf(" 1:输入单词查找词义 \n\n");
printf(" 2:输出数据库内所有单词\n");
printf("\n\t\t···按空格键返回 : \n");
//
int x=getch(); //使用此函数直接得到键盘上得到的值
//
switch (x)
{
case '1': find_word(head);break;
case '2': system("cls");print(head);break;
case ' ': system("cls");return;
default:system("cls");printf("\n输入错误,请重新输入!"); break;
}
}
}
//
//
//
//**********************下面这些函数用来构造结构体链表来存储单词的拼写*****************************************
/*
*功 能:建立存放单词和翻译的链表
*过 程:此函数内有两个过程,一个是建立函数的头,一个处理除了头以外的数据
*输 入:存放单词和翻译的数组以及全局变量的链表的头指针
*输 出:改变后的指向链表的结构体指针
*/
str*creat(str*head,char a_word[20],char a_Translation[100])
{
str*p,*tail; //在链表建立过程中使用到的用来循环的变量
//
str*replace_head; //建立替代链表头的指针
replace_head=head;
//
static int selectable_2;//用来再两个while循环之间进行跳跃循环的选择标志,
// //定义为static变量意义为每次建立一个节点都会调用一次此函数,防止该变量在退出函数后失效
//
if(selectable_2 == 0)//建立链表的头节点,根据selectable_2判断标志只执行一次这个while循环
{
printf("\t\t···开始建立链表的首位置\n");
head=NULL;//删除动作
head=p=tail=(str*)malloc(sizeof(str));//给新head赋给新的内存空间。
head->next=NULL;
tail->next=p; //建立了一个正向单链表
tail=p;
while (1)
{
printf("\t\t···加载完成\n");
// scanf("%d",&i);
if (selectable_2==1)
break;
p = (str*) malloc (sizeof(str)); //为欣节点开辟一个内存地址
//
strcpy (p->yi,a_Translation); //把储存翻译的数组通过函数直接复制到节点里面的数组内
strcpy (p->ci,a_word); //把储存单词的数组通过函数直接复制到节点里面的数组内
p->n = number; //记录单词的序号
//
all_number =all_number+1; //记录单词的总量,是一个全局静态变量
//
if (all_number==1) head=p;
else tail->next = p;
tail = p;
selectable_2 = 1;
}
//
tail->next=NULL;
selectable_2 = 1;
printf("\t\t···新链表首位置完成\n");
return (head);
}
//
if (selectable_2 == 1) //建立好链表的头以后再调用此函数只会执行下面的语句 向已有的链表中输入内容
{
p = (str*) malloc(sizeof(str));
//
strcpy (p->yi,a_Translation); ////把储存翻译的数组通过函数直接复制到节点里面的数组内
strcpy (p->ci,a_word);
p->n = number;
//
all_number = all_number+1;
p->next = NULL;
while (replace_head ->next != NULL)//找到链表的尾部
replace_head = replace_head->next;
replace_head -> next = p;//把尾部添加信息
//
return (head);
}
//
}
//
/*
*功 能:把文件内的数据写进程序内存链表中
*过 程:通过读取word。txt文件,打开的文件是绝对路径!方便程序以后进行个别更改
*输 入:指向链表的结构体指针
*输 出:改变后的指向链表的结构体指针
*/
str*Extract_words(str*head) //打开文件,word。txt然后向链表内传输
{
FILE*fp; //建立一个指向文件的文件指针
int i//作为存放单词和翻译的过程中用来循环的变量
,selectable//用来再两个while循环之间进行跳跃循环的选择标志
,k; //用来循环初始化数组
long file_place_1,file_place_2; //建立指向读取过程中记录读取地址的变量
char one_byte,//存放最去过程中的一个字节
filename[50]={file_path_1}; //文件绝对路径
char a_word[20],a_Translation[100];
//
if((fp=fopen(filename,"r"))==NULL) //在打开文件的过程前,首先对文件的路径和文件内容进行判断
{
printf("源文件打开错误");
}
fseek(fp,file_place_1,1); //用来将位置指针移动到任意位置
//把位置指针移动到离文件开头100个字节处:
printf("\t\t···开始加载文档\n");
//读取单词和翻译的过程通过直接判断读取过程中的每一个字节来进行判断的
//单词和翻译通过空格和回车的方式进行隔开:回车-单词-空格-翻译-回车-单词-空格···
//使用两个分别处理单词和翻译的录入过程,以一组单词和翻译的形式存进链表的一个节目
while(1)
{
selectable=0; //每在链表里存进一组单词和翻译都把选择恢复到触发储存单词的选择标志上
i=0; //每在链表里存进一组单词和翻译都把数组的位置循环变量清零
file_place_1=ftell(fp); //循环过程中不停的读取当前读取到的位置
//
for(k=0;k<20;k++) //每在链表里存进一组单词和翻译就把存放单词和翻译的数组清零
a_word[k]=0;
for(k=0;k<100;k++)
a_Translation[k]=0;
//
if(file_place_1!=0) //file_place_1只在第一次循环中正常使用,在之后都是用file_place_2来存放文件位置
fseek(fp,file_place_2,0);
else fseek(fp,file_place_1,0); //这里存在bug,正常用一个file_place变量就可以,只能循环一次,因此第二次以后都用另一个变量来循环
//
while((one_byte=fgetc(fp))!=EOF) //判断文件书否已经读取到结尾
{
if(one_byte=='\n') //如果一开始时是回车就会触发单词的储存循环
selectable=1;
if(one_byte==' '&&selectable==1) //在这个循环里如果没有遇到空格就会一直执行
{
//printf("%s\n",a);///////////从此处进入另一个函数,这个函数要储存在结构体内,是一个入口
//代表一个单词的输入成功 ,单词数量增加一
break;
}
if(selectable==1&&one_byte!='\n')
{
a_word[i]=one_byte; //读取单词的过程,单词数组的一个元素就是一个字节就是一个字母
i++; //在循环的过程中不停的让数组的位置向前移动
}
//
//
}
file_place_2=ftell(fp); //读取当前文件位置,退出上面的while循环以后直接进入
// //下面的while无法直接判断该从哪开始循环,因此需要判断
i=0;
selectable=0;
//
while((one_byte=fgetc(fp))!=EOF) //读取翻译的过程
{
if(one_byte==' ')
selectable=1;
if(one_byte=='\n'&&selectable==1)
{
//printf("%s\n",b);///////////从此处进入另一个函数,这个函数要储存在结构体内,是一个入口
break;
}
if(selectable==1&&one_byte!=' ')
{
a_Translation[i]=one_byte;
i++;
}
}
number++;
// printf("%s\n",a);///////////从此处进入另一个函数,这个函数要储存在结构体内,是一个入口
// printf("%s\n",b);///////////从此处进入另一个函数,这个函数要储存在结构体内,是一个入口
head=creat(head,a_word,a_Translation); //每读取完一组单词个翻译就会把得到的单词共和翻译慈
//储存到链表的一个节点内
if((one_byte=fgetc(fp))==EOF) //判断是否已经读取到文件的末尾
break;
}
fclose(fp); //关闭文件,保证安全
return(head);
}
//
//
///**********************下面这些函数用来构造结构体数组来存储单词的数据*****************************************
/*
*功 能:用来进行测试程序内的单词熟练度是否已经正确加载
*过 程:只遍历机构提数组的前60个元素输出到屏幕上
*输 入:无
*输 出:无
*/
void shuchujiegouti()///把程序里面的结构体输出出来
{
int i;
printf("\n把程序里面的结构体输出出来\n ");
for(i=0;i<60;i++)
{
printf("\n(test): %d ,(fly): %d \n",stu[i].test ,stu[i].pfy );
}
}
/*
*功 能:获得单词熟练度的统计
*实 现:通过遍历数组,把每个单词的熟练度都进行比较,
并且对不同熟练度的单词进行计数,最后得到不同的熟练度的总和
*输 入:无
*输 出:无
*/
void fenlei() ///把得到的机构体数组进一步进行细化,分类
{
int i,j,k,l,m;
//
for(i=0;i<5000;i++)
{
if(stu[i].pfy==0)
{a_0[j]=i;j++;}
if(stu[i].pfy==1)
{a_1[l]=i;l++;}
if(stu[i].pfy==2)
{a_2[k]=i;k++;}
if(stu[i].pfy==3)
{a_3[m]=i;k++;}
//
//
}
//
}
/*
*功 能:这是一个用来测的函数,在程序运行的过程并没哟用到这个函数
测试把文件读取到结构体数组内并且把结构体数组打印到屏幕上
目的是为了测试文件的读取和数组的匹配
*输 入:无
*输 出:无
*/
void duwenjianjieguoti() //把文件里面的结构体全读出来
{
FILE *pp;
int i;
//
printf("开始读文件\n");
//
pp=fopen(file_path_2,"rb");
while(fread(&array_stu,sizeof(array_stu),1,pp))
{
printf("\n(test)zzzzzz: %d ,(fly): %d \n",array_stu.test ,array_stu.pfy );
i++;
if(i>50)
break;
//
}
fclose(pp);
}
/*
*功 能:在一开始建立程序的时候从文件里面读取单词的熟练度,并且
以结构体数组的方式进行储存
//
*/
void begin_struct() //结构体数组的初始化
{
FILE *pp;
int i,j,k;
for(i=0;i
下面是按照模块化多个.h文件进行设计的程序源码以及程序需要用到的单词库:
百度网盘链接
提取码为 : fljs
链接:https://pan.baidu.com/s/1pDPyjLGcsM3G8TbF2PpmZg
提取码:fljs