电子词典
优质
小牛编辑
145浏览
2023-12-01
项目分析
功能描述
- 英译汉和汉译英的单词查询功能
- 收藏功能
- 显示收藏词语功能
- 显示查询信息功能
项目实现
项目设计
数据结构设计
词典词条数据结构
#aardvark
Trans:n. 土猪
#aardwolf
Trans:n. 土狼
#aasvogel
Trans:n. 秃鹰之一种
#abaci
Trans:n. 算盘
#aback
Trans:ad. 向后地;朝后地
变量声明 | 功能描述 |
---|---|
char * key; | 存储单词字符串的首地址 |
char * content; | 存储相应的翻译字符串的首地址 |
单词查找记录数据结构
变量声明 | 功能描述 |
---|---|
char * key; | 单词指针 |
int count; | 单词查询次数 |
int mark_flag; | 标记该单词是否已经被收藏 |
struct Dict // 词典词条数据结构体
{
char * key; // 单词字符串的首地址
char * content;// 相应的翻译字符串的首地址
};
struct Record // 单词查找记录
{
char * key; // 单词指针
int count; // 单词查询次数
int mark_flag; // 标记该单词是否已经被收藏
};
函数设计
函数声明 | 功能描述 |
---|---|
open_record() | 加载记录词条文件 |
open_dict() | 加载词典词条文件 |
release_record() | 释放记录词条数组所占的内存空间 |
release_dict() | 释放词典词条数组所占的内存空间 |
search_record() | 根据关键字key,在记录词条数组中查找对应数据 |
search_dict() | 根据关键字key,在词典词条数组中查找对应数据 |
list_collect() | 打印收藏词条数组中的单词及其对应的翻译 |
flush_record() | 将记录词条数组中的数据保存到记录词条文件中 |
预处理实现
dict.h
#ifndef __DICT_H__ // 检查宏__DICT_H__是否已被定义过,避免重复定义
#define __DICT_H__
#define MAX_DICT 111111 // 词典词条数组最大长度
#define MAX_RECORD 4000 // 记录词条数组最大长度
#define DICT_FILE "dict.txt" // 词典词条文件名
#define RECORD_FILE "record.txt"// 记录词条文件名
#define NEED_COLLECT 5 // 提示是否需要收藏时单词的查询次数
struct Dict // 词典词条数据结构体
{
char * key; // 单词字符串的首地址
char * content;// 相应的翻译字符串的首地址
};
struct Record // 单词查找记录
{
char * key; // 单词指针
int count; // 单词查询次数
int mark_flag; // 标记该单词是否已经被收藏
};
int open_record(struct Record ** p, const char * record_file);
int open_dict(struct Dict ** p, const char * dict_file);
void release_record(struct Record ** p, int count);
void release_dict(struct Dict ** p, int count);
struct Record * search_record(struct Record * pRecordList, int count,
const char * key);
struct Dict * search_dict(struct Dict * pDictList, int count, const char * key);
void list_collect(struct Record * pRecordList, int recordCount,
struct Dict * pDictList, int dictCount);
int flush_record(const struct Record * pRecordList, int count,
const char * record_file);
#endif
功能函数实现
dict.c
#define _CRT_SECURE_NO_WARNINGS // 屏蔽所有的提示不安全的信息
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "dict.h"
// 加载记录词条文件
int open_record(struct Record ** p, const char * record_file)
{
// 申请内存空间
struct Record * pRecordList = (struct Record *)calloc(MAX_RECORD,
sizeof(struct Record));
*p = pRecordList;
FILE * fp = fopen(record_file, "r"); // 打开记录文件
if (fp == NULL)
{
return 0; // 打开文件失败,函数返回
}
int recordCount = 0;
fscanf(fp, "%d", &recordCount); // 读取记录文件里记录的数据数量
char buf[1024];
size_t bufLen;
int number;
int flag;
int i = 0; // 数组下标
while (!feof(fp)) // 循环读取文件,直到文件末尾
{
memset(buf, 0, sizeof(buf)); // 初始化buf数组
number = 0;
flag = 0;
fscanf(fp, "%s %d %d", buf, &number, &flag);
bufLen = strlen(buf); // 获取字符串的长度
if (bufLen > 0)
{
// 根据字符串长度分配内存
pRecordList[i].key = (char *)calloc(bufLen + 1, 1);
strcpy(pRecordList[i].key, buf);// 将字符串的内容复制到key中
pRecordList[i].count = number;
pRecordList[i].mark_flag = flag;
i++; // 数组下标移动到下一个元素的位置
}
}
fclose(fp); // 关闭文件
// 比较记录文件里记录的数据数量和pRecordList数组的长度是否一致
if (recordCount != i)
{
printf("record file error\n");
}
return i; // 返回pRecordList数组长度
}
// 加载词典词条文件
int open_dict(struct Dict ** p, const char * dict_file)
{
FILE * fp = fopen(dict_file, "r");// 以只读方式打开词典词条文件
if (fp == NULL)
{
return 0; // 打开文件失败,函数返回
}
struct Dict * pDictList = (struct Dict *)calloc(MAX_DICT, sizeof(struct Dict));
char buf[1024];
size_t bufLen;
int i = 0; // 数组下标
while (!feof(fp)) // 循环读取文件,直到文件末尾
{
memset(buf, 0, sizeof(buf));// 初始化buf数组
fgets(buf, sizeof(buf), fp);// 读取文件一行
bufLen = strlen(buf); // 获取字符串的长度
if (bufLen > 0)
{
// 将字符串末尾的回车符删除
if (buf[bufLen - 1] == '\n')
{
buf[bufLen - 1] = '\0';
bufLen -= 1;
}
// 根据字符串长度分配内存
pDictList[i].key = (char *)calloc(bufLen + 1, 1);
strcpy(pDictList[i].key, &buf[1]);// 将字符串的内容复制到key中
}
memset(buf, 0, sizeof(buf));// 初始化buf数组
fgets(buf, sizeof(buf), fp);// 读取文件一行
bufLen = strlen(buf); // 获取字符串的长度
if (bufLen > 0)
{
// 将字符串末尾的回车符删除
if (buf[bufLen - 1] == '\n')
{
buf[bufLen - 1] = '\0';
bufLen -= 1;
}
// 根据字符串长度分配内存
pDictList[i].content = (char *)calloc(bufLen + 1, 1);
strcpy(pDictList[i].content, &buf[6]);// 将字符串的内容复制到content中
}
i++; // 数组下标移动到下一个元素的位置
}
fclose(fp); // 关闭字典文件
*p = pDictList;
return i; // 返回pDictList数组长度
}
// 释放记录词条数组所占的内存空间
void release_record(struct Record ** p, int count)
{
struct Record * pRecordList = *p;
if (pRecordList == NULL)
{
return;
}
for (int i = 0; i < count; i++)// 循环释放key成员内存
{
if (pRecordList[i].key) // 如果成员变量key指向一块内存空间,就将其释放
free(pRecordList[i].key);
}
free(pRecordList); // 释放内存
*p = NULL;
}
// 释放词典词条数组所占的内存空间
void release_dict(struct Dict ** p, int count)
{
struct Dict * pDictList = *p;
if (pDictList == NULL)
{
return;
}
for (int i = 0; i < count; i++)// 循环释放key与content成员内存
{
if (pDictList[i].key) // 如果成员变量key指向一块内存空间,就将其释放
free(pDictList[i].key);
if (pDictList[i].content) // 如果成员变量content指向一块内存空间,就将其释放
free(pDictList[i].content);
}
free(pDictList); // 释放内存
*p = NULL;
}
// 根据关键字key,在记录词条数组中查找对应数据
struct Record * search_record(struct Record * pRecordList, int count,
const char * key)
{
for (int i = 0; i < count; i++)// 遍历记录词条数组,查询对应的记录词条数据
{
if (pRecordList[i].key == NULL)// 如果指针变量key未指向任何内存空间,则跳过
{
continue;
}
if (strcmp(pRecordList[i].key, key) == 0)
{
return &pRecordList[i];// 找到符合条件记录,返回该数组元素的地址
}
}
return NULL; // 没有找到符合条件的记录,返回NULL
}
// 根据关键字key,在词典词条数组中查找对应数据
struct Dict * search_dict(struct Dict * pDictList, int count, const char * key)
{
for (int i = 0; i < count; i++)// 遍历词典词条数组,查询对应的词典词条数据
{
// 如果指针变量key和content未指向任何内存空间,则跳过
if (pDictList[i].key == NULL || pDictList[i].content == NULL)
{
continue;
}
if (strcmp(pDictList[i].key, key) == 0)
{
return &pDictList[i]; //找到符合条件记录,返回该数组元素的地址
}
}
return NULL; // 没有找到符合条件的记录,返回NULL
}
// 打印收藏词条数组中的单词及其对应的翻译
void list_collect(struct Record * pRecordList, int recordCount,
struct Dict * pDictList, int dictCount)
{
printf("/******************************/\n");
printf("/** 已收藏的单词 **/\n");
printf("/******************************/\n");
for (int i = 0; i < recordCount; ++i) // 遍历数组
{
if (pRecordList[i].mark_flag) // 如果收藏词条数组元素被标记为已收藏
{
// 查询对应的翻译
struct Dict * pDict = search_dict(pDictList, dictCount,
pRecordList[i].key);
if (pDict != NULL)
{
// 打印收藏的单词及其对应翻译
printf("%s:\n", pDict->key);
printf("%s\n", pDict->content);
printf("Press any key to continue\n");
fflush(stdin); // 清空输入流
getchar();
}
}
}
printf("OVER! BYE\n");
}
// 将记录词条数组中的数据保存到记录词条文件中
int flush_record(const struct Record * pRecordList, int count,
const char * record_file)
{
FILE * fp = fopen(record_file, "w");// 以只写方式打开记录词条文件
if (fp == NULL)
{
printf("file not found\n");
return -1; // 文件打开失败,返回-1
}
int i = 0;
fprintf(fp, "%d\n", count); // 第一行存储该文档有多少条记录
while (i < count) // 分别写入每一行的每一条记录
{
fprintf(fp, "%s %d %d\n", pRecordList[i].key, pRecordList[i].count,
pRecordList[i].mark_flag);
++i;
}
fclose(fp); // 关闭文件
return 0;
}
主函数实现
main.c
#define _CRT_SECURE_NO_WARNINGS // 关闭安全性检查
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "dict.h"
void main()
{
struct Dict * pDictList = NULL; // 定义词典词条数组指针变量
struct Dict * pDict = NULL; // 定义词典词条指针变量
struct Record * pRecordList = NULL;// 定义记录词条数组指针变量
struct Record * pRecord = NULL; // 定义记录词条指针变量
// 打开记录文件和词典文件
char key[1024] = { 0 };
printf("请输入词典文件名:\n");
scanf("%s", key);
printf("正在加载词典数据\n");
int dictCount = open_dict(&pDictList, key);
if (dictCount == 0) // 词典词条文件打开失败
{
release_dict(&pDictList, 0); // 释放词典词条数组占用的内存空间
exit(0); // 打开文件失败,程序退出
}
printf("正在加载记录数据\n");
// 打开记录词条文件,获取记录词条数量
int recordCount = open_record(&pRecordList, RECORD_FILE);
int flag = 0; // 标识变量,用于标识是否添加了新的记录数据
// 死循环,使程序一直运行,防止退出
while (1)
{
// 初始化数组key和content
memset(key, 0, sizeof(key));
pDict = NULL;
printf("\n");
printf("请输入单词或命令:\n");
scanf("%s", key); // 从键盘获取用户的输入
// 如果输入“$exit”就跳出循环
if (strncmp(key, "$exit", 5) == 0)
{
break;
}
// 如果输入“$review”打印收藏的单词并重新开始循环
if (strncmp(key, "$review", 7) == 0)
{
list_collect(pRecordList, recordCount, pDictList, dictCount);
continue;
}
// 根据用户的输入,在字典中检索
pDict = search_dict(pDictList, dictCount, key);
if (pDict != NULL) // 找到对应的词典数据
{
printf("%s\n", pDict->content);
// 在记录列表中查找单词
pRecord = search_record(pRecordList, recordCount, key);
if (pRecord == NULL) // 返回不为空说明该单词在记录列表中
{
pRecord = &pRecordList[recordCount];// 记录词条数组添加新元素
// 将指针变量key指向新申请的内存空间
pRecord->key = (char *)calloc(strlen(key) + 1, 1);
strncpy(pRecord->key, key, strlen(key));// 复制单词到内存空间
recordCount++; // 记录词条数组的元素数量+1
pRecord->count = 0; // 该单词已被查询0次
pRecord->mark_flag = 0;// 该单词还未被收藏
}
pRecord->count++;
flag = 1; // 标识记录词条数组已被改动
printf("you have searched \"%s\" %d times\n", key, pRecord->count);
// 单词未被收藏
if (pRecord->mark_flag == 0)
{
if (pRecord->count > NEED_COLLECT) // 单词已被查询指定次数
{
printf("---- I think you should collect this word. -----\n");
}
else // 单词未被查询指定次数
{
printf("---- Are you want to collect this word? ----\n");
}
printf("input Y(y) to collect\n");
fflush(stdin); // 清空输入流,防止回车符被getchar()函数获取
char c = getchar(); // 获取用户输入的字符
// 如果用户输入“y”或“Y”,将单词设置为已收藏
if (c == 'y' || c == 'Y')
{
pRecord->mark_flag = 1; // 设置单词为已收藏
printf("该单词已被成功收藏\n");
}
}
}
else // 未找到对应的翻译
{
printf("not found\n");
}
}
if (flag) // 如果记录词条数据已被改动,将记录词条数组写入记录词条文件中
{
flush_record(pRecordList, recordCount, RECORD_FILE); // 写入文件
}
printf("正在释放记录数据\n");
release_record(&pRecordList, recordCount);
printf("正在释放词典数据\n");
release_dict(&pDictList, dictCount);
}