C小项目——电子词典

C语言项目——查字典


宗旨:技术的学习是有限的,分享的精神是无限的。


【项目需求描述】

一、单词查询

给定文本文件“dict.txt”,该文件用于存储词库。词库为--双语词典,每个单词和其解释的格式固定,如下所示:

#单词

Trans:解释1@解释2@…解释n

每个新单词由“#”开头,解释之间使用“@”隔开。一个词可能有多个解释,解释均存储在一行里,行首固定以“Trans开头。下面是一个典型的例子:

#abyssinian

Trans:a. 阿比西尼亚的@n. 阿比西尼亚人;依索比亚人

该词有两个解释,一个是“a. 阿比西尼亚的;另一个是“n. 阿比西尼亚人;依索比亚人

要求编写程序将词库文件读取到内存中,接受用户输入的单词,在字典中查找单词,并且将解释输出到屏幕上。用户可以反复输入,直到用户输入“exit”字典程序退出。

程序执行格式如下所示:

./app –text

-text表示使用文本词库进行单词查找。

二、建立索引,并且使用索引进行单词查询

要求建立二进制索引,索引格式如下图所示。将文本文件“dict.txt”文件转换为上图所示索引文件“dict.dat”,使用索引文件实现单词查找。程序执行格式如下:

./app –index

-index表示使用文本词库dict.txt建立二进制索引词库dict.dat

./app –bin

-bin表示使用二进制索引词库进行单词查找。

//================================================================================================================

一、文本文件单词查询

1、单词结构:

#单词

Trans:解释1@解释2@…解释n

dict.txt文件中,单词占一行,以“#”开头;解释以Trans:开头,内容以“@”分隔。结构我采用链表。具体结构定义如下:

// 单词链表 ---- 单词名称,翻译的个数,单词翻译的结果

typedef struct dict

{

  char word[TARGET_WORD_MAX_SIZE]; // 要输入的单词,如"#superstar"

  uint8_t mean_count;  // 单词解释的个数,如既可以做名词也可以做动词,

  char trans[TARGET_WORD_MEANING_COUNT][TARGET_WORD_MAX_TRANSLATION]; // 翻译结果,用@分开strtok分割函数)

  struct dict *next;

} word_t, *dict_t;

2、接口定义

2.1、文件中单词的总数:要建立单链表,就要知道单链表的长度,因此,要知道文件中单词的总个数,定义如下接口:

uint32_t ListCount(FILE *fp); // 词典里面单词的个数,即是要创建链表的长度

2.2、创建单链表:从文件中一项一项读出单词及其解释,填充到单词结构体中,创建单链表就是分配内存并连接节点的过程,定义接口如下(count是单词的总数):

dict_t CreateList(dict_t head, FILE *fp, uint32_t count); // 创建单链表,返回首节点。分配内存。

2.3、查找单词:从链表中匹配要查找的单词,找到了就输出单词解释,定义接口如下:

void SearchList(dict_t head, uint32_t count); // 查找输入的单词

2.4、释放内存:创建链表分配的内存在结束时释放,定义接口如下:

void DestroyList(dict_t head); // 释放内存


二、建立索引文件dict.data

1、索引结构

如上图所示,包含如下内容:索引头单词个数(4字节),单词1的单词长度(4字节),单词1的内容(单词长度个字节),单词1的解释个数(4字节),解释1的长度(4字节),解释1的内容(解释1的长度),解释2的长度(4字节),解释2的内容(解释2的长度)...按照这个格式将dict.txt文件的内容写到dict.dat的索引文件中。结构和上面文本查询的结构一样。

2、接口定义

  将链表的节点按上面的格式一个一个写到索引文件dict.dat中,用fwrite函数写,定义接口如下:

// 链表头结点head,文件名,链表长度

void WriteIndexFile(dict_t head, const char *filename, uint32_t count);


三、索引文件查找单词

上面建立了索引文件,并按协议的格式将文本文件的内容写到了索引文件中,通过索引查找单词就是从索引文件读出要查找的单词,用fread函数读,接口定义如下:

void ReadIndexFile(dict_t head, const char *filename, uint32_t *count);


具体实现:

#ifndef _TARGET_H_
#define _TARGET_H_#include <stdlib.h>
#include <stdio.h>
#include <string.h>typedef unsigned char uint8_t;
typedef unsigned int  uint32_t;#define TARGET_TEXT_NAME            "./dict.txt"
#define TARGET_INDEX_NAME           "./dict.dat"
#define TARGET_WORD_MAX_SIZE        60
#define TARGET_WORD_MEANING_COUNT   20
#define TARGET_WORD_MAX_TRANSLATION 100
#define TARGET_WORD_BUFFER          1024// 单词链表 ---- 单词名称,单词有几种翻译,单词翻译的结果
typedef struct dict
{char word[TARGET_WORD_MAX_SIZE]; // 要输入的单词,如"#superstar"uint8_t mean_count;  // 单词解释的个数,如既可以做名词也可以做动词,用@分开char trans[TARGET_WORD_MEANING_COUNT][TARGET_WORD_MAX_TRANSLATION]; // 翻译结果struct dict *next;
} word_t, *dict_t;uint32_t ListCount(FILE *fp); // 词典里面单词的个数,即是要创建链表的长度
dict_t CreateList(dict_t head, FILE *fp, uint32_t count); // 创建单链表,返回首节点。分配内存。
void SearchList(dict_t head, uint32_t count); // 查找输入的单词
void DestroyList(dict_t head); // 释放内存void WriteIndexFile(dict_t head, const char *filename, uint32_t count);
void ReadIndexFile(dict_t head, const char *filename, uint32_t *count);void Process(int argc, char **argv); // 主进程,main函数主要调用接口#endif /* _TARGET_H_ */

main.c

#include "target.h"int 
main(int argc, char **argv)
{if(argc < 2){fprintf(stderr, "input params is too few!\n");return 1;}Process(argc, argv);return 0;
}

process.c:

#include "target.h"static const char params[][15] = {"-text", "-index", "-bin", "-test1 -f", "-test2 -f"};void
Process(int argc, char **argv)
{FILE *fp;dict_t head;uint32_t count;if((fp = fopen(TARGET_TEXT_NAME, "r")) == NULL){fprintf(stderr, "open file failure!\n");exit(1);}count = ListCount(fp);printf("count: %d\n", count);printf("open sucess!\n");if((strcmp(argv[1], params[0])) == 0){head = CreateList(head, fp, count);SearchList(head, count);fclose(fp);DestroyList(head);}if((strcmp(argv[1], params[1])) == 0){head = CreateList(head, fp, count);fclose(fp);WriteIndexFile(head, TARGET_INDEX_NAME, count);DestroyList(head);}if(strcmp(argv[1], params[2]) == 0){head = CreateList(head, fp, count);ReadIndexFile(head, TARGET_INDEX_NAME, &count);SearchList(head, count);fclose(fp);DestroyList(head);}
}

find_word_from_text.c

#include "target.h"static char file_exist;uint32_t
ListCount(FILE *fp) // 单词的个数即是链表的长度
{uint32_t count = 0;char buffer[100];while(fgets(buffer, sizeof(buffer), fp)){if('#' == buffer[0]){++count;}}rewind(fp); // 这一步一定要做,使文件指针指向文件头return count;
}dict_t
CreateList(dict_t head, FILE *fp, uint32_t count)  // 创建链表,返回头结点
{dict_t new, pointer;char buf[TARGET_WORD_BUFFER];uint8_t word_size, trans_size, mean_count = 1, *str;uint32_t i, j = 0;head = (dict_t)malloc(sizeof(word_t));  //分配节点空间if(NULL == head){fprintf(stderr, "malloc failure!\n");exit(1);}printf("head success!\n");if(count > 0){memset(buf, 0, sizeof(buf));fgets(buf, sizeof(buf), fp);word_size = strlen(buf);buf[word_size - 1] = '\0';strcpy(head->word, buf);memset(buf, 0, sizeof(buf));fgets(buf, sizeof(buf), fp);trans_size = strlen(buf);buf[trans_size - 1] = '\0';str = strtok(buf, "@");strcpy(head->trans[j++], str + 6);while(str = strtok(NULL, "@")){strcpy(head->trans[j++], str);++mean_count;}head->mean_count = mean_count;head->next = NULL; // 到这里为止填充了首节点,并将首节点的下一个节点指向空pointer = head;for(i = 0; i < count - 1; ++i) // 将后面(count-1)个依次链接到首节点后面{mean_count = 1;new = (dict_t)malloc(sizeof(word_t)); //分配节点空间memset(buf, 0, sizeof(buf));fgets(buf, sizeof(buf), fp);word_size = strlen(buf);buf[word_size - 1] = '\0';strcpy(new->word, buf);memset(buf, 0, sizeof(buf));fgets(buf, sizeof(buf), fp);trans_size = strlen(buf);buf[trans_size - 1] = '\0';for(j = 0; j < count;){str = strtok(buf, "@");strcpy(new->trans[j++], str + 6);while(str = strtok(NULL, "@")){strcpy(new->trans[j++], str);++mean_count;}}new->mean_count = mean_count;new->next = NULL;pointer->next = new;pointer = new;}}rewind(fp);return head;
}void
PrintList(dict_t head)
{dict_t pointer;pointer = head;while(pointer != NULL){printf("pointer->word = %s, pointer->mean_count = %d\n", pointer->word, pointer->mean_count);pointer = pointer->next;}
}void
SearchList(dict_t head, uint32_t count) // 从链表中查找单词
{dict_t pointer;char str[TARGET_WORD_MAX_SIZE];uint32_t i;while(1){file_exist = 0;pointer = head;printf("Please input a word:");fgets(str, TARGET_WORD_MAX_SIZE, stdin);str[strlen(str) - 1] = '\0';if(strcmp(str, "exit") == 0){exit(1);}while(pointer != NULL){if((strcmp(pointer->word, str)) == 0){for(i = 0; i < pointer->mean_count; ++i){file_exist = 1;fprintf(stdout, "Trans%d: %s\n", i + 1, pointer->trans[i]);}break;}pointer = pointer->next;}if(file_exist == 0){
    // 这里判断了该单词不存在,可以选择添加,也可以选择退出;
/*printf("no find!\n");printf("Do you want to add a new word?:(Y/N)\n");scanf("%c", &new_word);if(new_word == 'Y' || new_word == 'y'){AddWordToText(head, TARGET_CUSTOM_TEXT);}*/exit(1);}}
}void
DestroyList(dict_t head) 
{dict_t pointer;while(pointer != NULL){pointer = head;head = head->next;free(pointer);}
}

find_word_from_index.c

#include "target.h"void
WriteIndexFile(dict_t head, const char *filename, uint32_t count) // 建立索引,按协议格式写入文件
{FILE *stream;uint32_t i, word_size, trans_size, mean_count;uint8_t j;dict_t pointer = head;if((stream = fopen(filename, "wb")) == NULL){fprintf(stderr, "Cannot open output file.\n");exit(1);}fwrite(&count, 4, 1, stream);while(pointer != NULL){word_size = strlen(pointer->word);mean_count =  pointer->mean_count;fwrite(&word_size, 4, 1, stream);fwrite(pointer->word, 1, word_size, stream);fwrite(&mean_count, 4, 1, stream);for(j = 0; j < mean_count; ++j){trans_size = strlen(pointer->trans[j]);fwrite(&trans_size, 4, 1, stream);fwrite(pointer->trans[j], 1, trans_size, stream);}pointer = pointer->next;}fclose(stream);
}void
ReadIndexFile(dict_t head, const char *filename, uint32_t *count) // 从文件中读出单词内容
{FILE *stream;uint8_t i;uint32_t word_size, trans_size, mean_count;dict_t pointer = head;printf("enter...\n");if((stream = fopen(filename, "rb")) == NULL){fprintf(stderr, "Cannot open output file.\n");exit(1);}// printf("read file success!...\n");fread(count, 4, 1, stream);printf("count = %d\n", *count);while(pointer != NULL){fread(&word_size, 4, 1, stream);// printf("word_size = %d\n", word_size);fread(pointer->word, 1, word_size, stream);pointer->word[word_size] = '\0';fread(&pointer->mean_count, 4, 1, stream);//printf("pointer->word = %s\n", pointer->word);//printf("pointer->mean_count = %d\n", pointer->mean_count);for(i = 0; i < pointer->mean_count; ++i){memset(pointer->trans[i], 0, sizeof(pointer->trans[i]));fread(&trans_size, 4, 1, stream);fread(pointer->trans[i], 1, trans_size, stream);pointer->trans[i][trans_size] = '\0';printf("trans_size = %d\n", trans_size);printf("pointer->trans = %s\n", pointer->trans[i]);}pointer = pointer->next;}//fclose(stream);printf("read over!\n");
}

先用gcc编译生成可执行文件app,再分别执行文本查询,索引建立和索引查询。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/467003.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

线性表的顺序存储的基本操作

插入&#xff1a; #include<stdio.h> #define N 100 typedef struct s {int elem[N];int last; }Seqlist; int Locate(Seqlist l,int e)//查找 {int i0;while(i<l.last&&l.elem[i]!e)i;if(i<l.last)return i1;elsereturn 0; } int DelList(Seqlist *l,int …

canvas生成二维码(2)

不同的插件实现相同的效果&#xff0c;用起来更简洁一些&#xff0c;引用插件qrcode.js 创建一个新的QRCode对象&#xff0c;利用动漫节点和data数据进行复制&#xff0c;实现生成图片img的二维码&#xff1a; 详细见下方代码&#xff1a; <!DOCTYPE html PUBLIC "-//W…

UART/I2C/SPI/1-wire四大通信接口的神解释

1、 裘千丈轻功水上漂之UART射雕英雄传中的裘千丈说&#xff0c;UART就是我的轻功水上漂过河。想从河上过&#xff08;通信&#xff09;&#xff0c;提前布暗桩&#xff0c;行走时步伐按桩距固定&#xff08;波特率提前确定&#xff09;&#xff0c;步幅太大或太小都会落水。为…

动漫迷看的一点动漫

个人看过的动漫 (注&#xff1a;排名不分先后) 宗旨&#xff1a;技术的学习是有限的&#xff0c;分享的精神是无限的。 1、魔法科高中的劣等生&#xff1a;国立魔法大学附属第一高校——通称“魔法科高校”&#xff0c;是由成绩优秀的“一科生”&#xff0c;和作为一科生替补的…

last_kmsg和ram console

相关文章Android 7.1使用脚本保存LOGCAT和KMSG日志到文件首先&#xff0c;在kernel里面通过printk吐log的时候会是下面的一个过程&#xff1a;printk会将信息格式化到kernel log buffer里面去。然后将这些格式化信息送到console去&#xff0c;在我们的系统里面有两个console&am…

字符串类

1.String类 常用方法&#xff1a; 参考&#xff1a;http://wenku.baidu.com/link?urltz-3Dpwj-JSJQdG6vSo0J1L1G9oJS4eQJjYgogieIzgjdNNLmj-U9EpWhOnVthz4egAKv0SNmLkqzNz2WsiZ2EmPGMu2UXhB6yy-E4yvMQ3 NB&#xff1a; 这里的”s1s2“是地址相等,而是s1.equals(s2)是内容相等…

github网页

GitHub主页创建仓库想必大家都有自己的Github账号吧&#xff0c;没有的可以到GitHub官网注册账号&#xff0c;注册完后&#xff0c;我们来下一步&#xff0c;在我们的GitHub上面右上角的New repository来创建一个仓库。 仓库名必须遵守相应格式&#xff1a;your_username.githu…

企业应该如何选型ERP?

企业应该如何选型ERP呢?!其实说起这个话题, 是源于我们公司所在的镇里,镇长带着两个企业的企业家,到我们公司指名让我给他们讲讲. 俗称:取经我是乐意的,因为做了这么久的顾问了,感觉不像是顾问了,倒成了传教士了. 总喜欢说上两句.然后把自已的观点或看法,希望传给别人,然后影…

有用的Copy-On-write,写时复制

写时复制和写时拷贝是一个意思写时复制是一种策略&#xff0c;并不是Linux独有的&#xff0c;如果你正在设计某个系统架构&#xff0c;也可以参考这种思想。写时复制的英文解释如下Copy-on-write (sometimes referred to as "COW") is an optimization strategy used…

lambda应用

def test(a, b, func):result func(a, b)print(result)test(10, 15, lambda x, y: x y) #codingutf-8 #python2需要加上codingutf-8def test(a, b, func):result func(a, b)return result #python2中的方式 #func_new input("请输入一个匿名函数:")#python3中的方…

51单片机学习

单片机学习 宗旨&#xff1a;技术的学习是有限的&#xff0c;分享的精神是无限的。 学习使用单片机就是理解单片机硬件结构&#xff0c;在汇编或C语言中学会各种功能的初始化设置&#xff0c;以及实现各种功能的程序编制。 第一步&#xff1a;数字I/O的使用 使用按钮输入信…

数据库操作,内外联查询,分组查询,嵌套查询,交叉查询,多表查询,语句小结...

为了大家更容易理解我举出的SQL语句&#xff0c;本文假定已经建立了一个学生成绩管理数据库&#xff0c;全文均以学生成绩的管理为例来描述。 1.在查询结果中显示列名&#xff1a; a.用as关键字&#xff1a;select name as 姓名 from students order by age b.直接表示&#x…

雷军:如果程序人生的话,这条路太漫长

这篇文章是在雷总个人博客看到的&#xff0c;里面聊到了他作为程序员的一些经历、初衷以及思考。写的不错&#xff0c;便转来给大家看看。-- 如果程序人生的话&#xff0c;这条路太漫长我并非天生喜欢写程序&#xff0c;上高中时也没有想过程序员的生活。我学电脑非常偶然&…

跨年操作--new Date()

//时间在2017/12/31 17&#xff1a;00 --- 2018/1/1 06:00区间&#xff0c;提示用户无法操作公告。 //time.js (function(){ var date new Date(); //当前年份 var year date.getFullYear(); //当前月份 var month date.getMonth()1; //当前日 var day date.getDate(); //当…

List接口

List接口是collection接口的子接口&#xff0c;对collection进行了简单的扩充&#xff0c;添加了利用索引&#xff08;“位置序”&#xff09;作为参数或者返回类型的方法。List中存放的对象都有一个整数型的型号&#xff0c;记录该对象在容器中的位置&#xff0c;可以根据序号…

51单片机——硬件基础

单片机——硬件基础知识 宗旨&#xff1a;技术的学习是有限的&#xff0c;分享的精神是无限的。 1、单片机内部资源 STC89C52&#xff1a;8KFLASH、512字节RAM、32个IO口、3个定时器、1个UART、8个中断源 &#xff08;1&#xff09;Flash&#xff08;硬盘&#xff09;——程…

线程静态的几个特点

很多编码规范上都指出不要使用线程静态&#xff08;ThreadStatic&#xff09;&#xff0c;这主要是为了防止在使用的时候出现意外。当有的时候这个线程静态确实会带来一些好处&#xff0c;如何取舍就要看具体情况了。首先&#xff0c;明确一点线程静态与标准静态之间的区别。线…

马上工作了,想问下要注意哪些问题?

这是一位读者在知识星球提问的&#xff0c;涉及的内容很多&#xff0c;但是这些问题&#xff0c;我觉得很多人都需要注意&#xff0c;分享出来让大家看&#xff0c;也希望留言说下自己的看法。1一、 offer情况 1. 已签三方 2. 公司是国内靠前的芯片原厂&#xff0c;深圳&#x…

CSS绘图

1. 自适应的椭圆 背景知识&#xff1a;border-radius属性的基本用法 使用border-radius制作一个圆很简单&#xff0c;只要给任何正方形元素设置固定宽高及一半长度以上的border-radius&#xff0c;就可以得到圆形 1234background: #fb3;width: 200px;height: 200px;border-radi…

JFrame和Frame的区别

在AMT组件中分为两大类&#xff0c;这两类的基类分别是Component和MenuComponent&#xff0c;其中&#xff0c;MenuComponent是所有与菜单相关组件的父类&#xff0c;Component则是除菜单外其他AMT组件的父类&#xff0c;它表示一个能以图形化方式显示出来&#xff0c;并可与用…