当前位置: 首页 > 文档资料 > C 语言程序设计 >

电子词典

优质
小牛编辑
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);
}