C语言综合练习5:快译通下

news2024/11/16 21:38:15

1 词典文件介绍

前面建立的词典,只有两个单词,现在我们要建立一个上万个单词的词典,所有单词及其翻译都在一个名为dict.txt的文件(词典文件)中
在这里插入图片描述
每个单词有两行,其中一行是单词原文,下一行是对应的翻译

这个文件共有20多万行,也就是说,共有10多万个单词,但看一下文件的末尾,可以发现后面的单词是中文,对应的翻译是英文,也就是说,这个文件即包含了英译中,也包含了中译英。
在这里插入图片描述

2 打开文件的函数与结构体定义

因为需要多次打开文件,因此可以将其封装成函数

# define FILE_PATH "./dict.txt"
FILE* open(char * file_path)
{
	FILE* fp = fopen(file_path, "r");
	if (!fp)
	{
		perror("open");
		exit(0);
	}
	return fp;
}

这个函数过于简单,因此不进行测试。

我们这次要建立的词典,既能英译中,也能中译英,那么就需要修改结构体定义

typedef struct _dict
{
	char *key;
	char *content;

}Dict;

3 词典文件的行数统计

dict.txt的行数决定了需要有多大的空间存储词典,这里词典文件有222204行,我们可以使用宏定义来写死行数

#define LINE_NUM 222204

但如果哪天在dict.txt文件中增加了两个单词,就必须修改代码了。
我们希望能够程序能够自动地获得文件的行数,那么这里可以写一个函数实现

int line_number()
{
	FILE* fp = open(FILE_PATH);
	int i = 0;
	char temp[128];
	while (1)
	{
		fgets(temp, sizeof(temp), fp);
		if (feof(fp))
		{
			fclose(fp);
			return i;
		}
		i++;
	}	
}

这个函数看起来没问题,但实际上是存在bug的,feof不建议与fgets配合使用,因为在读完最后一行的时候(dict.txt的最后一行没有换行符),feof认为读取结束,此时函数返回,最后一行没能统计到。当feoffgetc配合使用时,fgetc只有读取失败返回-1之后,feof才认为文件读取结束,而feoffgets配合时,只需要最后一行读完,feof就认为文件读取结束,无需等到读取失败。

如果把i++移动到if语句前面,也是不行的,因为当文件是一个空文件时,i++也会执行。

可以按以下方式修改

int line_number()
{
	FILE* fp = open(FILE_PATH);
	int i = 0;
	char temp[128];
	char* p;
	while (1)
	{
		p = fgets(temp, sizeof(temp), fp);
		if (!p)
		{
			fclose(fp);
			return i;
		}
		i++;
	}	
}

当读到最后一行的时候,p仍然不为NULL,这样后面的i++还是能够正常执行的,但下一次循环时,读取失败,p为NULL,此时执行if语句中的内容。下面是该函数的测试程序

#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
int main()
{
	int lines = line_number();
	printf("%d\n", lines);
	return 0;
} 

输出:

222690

这里的行数和我们用notepad++中看到的行数不一致,我一直没找到原因,因为行数太多,又不能通过打断点调试找到原因,直到我后面对比了视频配套的代码才找到原因。在函数line_number中char temp[128];,也就是temp的长度只有128个字节,通常情况下是够用的,但某些单词或者翻译极度的长,128字节仍然不够用,导致一行被读两次。

将128改成256,就能正常计算行数了,代码如下:

int line_number()
{
	FILE* fp = open(FILE_PATH);
	int i = 0;
	char temp[256];
	char* p = NULL;
	while (1)
	{
		p = fgets(temp, sizeof(temp), fp);
		if (NULL == p)
		{
			fclose(fp);
			return i;
		}
		i++;
	}
}

输出:
在这里插入图片描述

4 词典的初始化

所谓初始化,就是将词典文件中的单词和翻译都写进内存

Dict* dict_init() {
	FILE* fp = open(FILE_PATH);
	int lines = line_number();
	Dict* dict = (Dict *)malloc(sizeof(Dict) * lines);

	char temp[256];
	int len = 0;

	for (int i = 0; i < lines/2; i++)
	{
		fgets(temp, sizeof(temp), fp);
		len = strlen(temp);
		dict[i].key = (char*)malloc(len + 1);
		strcpy(dict[i].key, temp);

		fgets(temp, sizeof(temp), fp);
		len = strlen(temp);
		dict[i].content = (char*)malloc(len + 1);
		strcpy(dict[i].content, temp);
	}
	fclose(fp);
	return dict;
}

测试程序尝试输出5个单词及其翻译,代码如下:

#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
int main()
{
	/*int lines = line_number();
	printf("%d\n", lines);*/

	typedef struct _dict {
		char* key;
		char* content;
	} Dict;

	Dict * dict = dict_init();
	for (int i = 0; i < 5; i++)
	{
		printf("%s\t%s\n", dict[i].key, dict[i].content);
	}

	return 0;
} 

这里暂时不考虑内存泄漏的问题。
输出:
在这里插入图片描述
显然,输出的单词和字符,有很多字符不是我们想要的

下面来改进一下
在这里插入图片描述
因为单词的每行都是以#号开头,翻译都是以Trans:开头,并且单词和翻译,后面有可能跟了空格、换行等无效字符,因此需要对读到的信息进行处理

char* filter_buf(char *buf)
{
	int n = strlen(buf) - 1;
	while (buf[n] == ' ' || buf[n] == '\n' || buf[n] == '\r' || buf[n] == '\t')
		n--;
	buf[n + 1] = 0;
	char* new_buf;
	if ('#' == buf[0])			//单词
		new_buf = buf + 1;
	else						//翻译
		new_buf = buf + 6;

	return new_buf;
}

测试程序如下:

#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<string.h>
int main()
{
	char str[256];
	char* new_str = NULL;

	strcpy(str, "#abcde \t\r\n");
	new_str = filter_buf(str);
	printf("%s  len=%d\n", new_str, strlen(new_str));

	strcpy(str, "Trans:n. 算盘");
	new_str = filter_buf(str);
	printf("%s  len=%d\n", new_str, strlen(new_str));
	return 0;
} 

输出

abcde  len=5
n. 算盘  len=7

因为汉字占两个字节,因此第二次输出的时候strlen(new_str)是7

filter_buf函数插入到词典初始化函数中

Dict* dict_init() {
	FILE* fp = open(FILE_PATH);
	int lines = line_number();
	Dict* dict = (Dict *)malloc(sizeof(Dict) * lines);

	char temp[256];
	char* str;
	int len = 0;

	for (int i = 0; i < lines/2; i++)
	{
		fgets(temp, sizeof(temp), fp);
		str = filter_buf(temp);
		len = strlen(str);
		dict[i].key = (char*)malloc(len + 1);
		strcpy(dict[i].key, str);

		fgets(temp, sizeof(temp), fp);
		str = filter_buf(temp);
		len = strlen(str);
		dict[i].content = (char*)malloc(len + 1);
		strcpy(dict[i].content, str);
	}
	fclose(fp);
	return dict;
}

测试程序如下:

#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
int main()
{
	/*int lines = line_number();
	printf("%d\n", lines);*/

	typedef struct _dict {
		char* key;
		char* content;
	} Dict;

	Dict * dict = dict_init();
	for (int i = 0; i < 5; i++)
	{
		printf("%s\t%s\n", dict[i].key, dict[i].content);
	}
	return 0;
} 

输出如下:
在这里插入图片描述
能输出这样的,说明初始化成功

5 搜索

搜索程序可以和简易版的相同,但因为结构体成员发生了改变,因此这里需要稍微改一下名字,代码如下:

void search(Dict* dict, char* key, int n)
{
	for (int i = 0; i < n; i++)
	{
		if (strcmp(dict[i].key, key) == 0)
		{
			printf("OK!The content word is:%s", dict[i].content);
			printf("\n");
			return;
		}
	}
	printf("There is no %s\n", key);
}

测试程序如下:

#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<string.h>
int main()
{
	typedef struct _dict {
		char* key;
		char* content;
	} Dict;

	Dict * dict = dict_init();
	char str[256];
	for (int i = 0; i < 2; i++)		//这里循环只执行两次
	{
		printf("Please enter a word:");
		fgets(str, strlen(str), stdin);
		str[strlen(str) - 1] = 0;
		search(dict, str, line_number() / 2);
	}

	return 0;
} 

输出
在这里插入图片描述
可以看到,搜索也是没问题的

6 翻译

将刚刚搜索的测试程序稍加改动,就得到了翻译的函数;

void translate() {
	Dict* dict = dict_init();
	int ret = 0;
	char key[256];
	while (1)
	{
		printf("Please Enter the world you want to search:");
		fgets(key, sizeof(key), stdin);
		key[strlen(key) - 1] = 0;
		printf("%s\n", key);
		search(dict, key, line_number() / 2);
	}
}

测试程序如下:

#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<string.h>
int main()
{

	/*typedef struct _dict {
		char* key;
		char* content;
	} Dict;

	Dict * dict = dict_init();

	char str[256];
	for (int i = 0; i < 2; i++)
	{
		printf("Please enter a word:");
		fgets(str, strlen(str), stdin);
		str[strlen(str) - 1] = 0;
		search(dict, str, line_number() / 2);
	}*/

	translate();
	return 0;
} 

输出如下:
在这里插入图片描述
至此,快译通制作完毕。

7 完整程序

#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<string.h>

typedef struct _dict {
	char * key;
	char * content;
} Dict;

# define FILE_PATH "./dict.txt"
FILE* open(char * file_path)
{
	FILE* fp = fopen(file_path, "r");
	if (!fp)
	{
		perror("open");
		exit(0);
	}
	return fp;
}

int line_number()
{
	FILE* fp = open(FILE_PATH);
	//FILE* fp = open("test_line.txt");
	int i = 0;
	char temp[256];
	char* p = NULL;
	while (1)
	{
		p = fgets(temp, sizeof(temp), fp);
		if (NULL == p)
		{
			//printf("%d\n", strlen(temp));
			fclose(fp);
			return i;
		}
		i++;
	}
}

char* filter_buf(char *buf)
{
	int n = strlen(buf) - 1;
	while (buf[n] == ' ' || buf[n] == '\n' || buf[n] == '\r' || buf[n] == '\t')
		n--;
	buf[n + 1] = 0;
	char* new_buf;
	if ('#' == buf[0])			//单词
		new_buf = buf + 1;
	else						//翻译
		new_buf = buf + 6;

	return new_buf;
}

Dict* dict_init() {
	FILE* fp = open(FILE_PATH);
	int lines = line_number();
	Dict* dict = (Dict *)malloc(sizeof(Dict) * lines);

	char temp[256];
	char* str;
	int len = 0;

	for (int i = 0; i < lines/2; i++)
	{
		fgets(temp, sizeof(temp), fp);
		str = filter_buf(temp);
		len = strlen(str);
		dict[i].key = (char*)malloc(len + 1);
		strcpy(dict[i].key, str);

		fgets(temp, sizeof(temp), fp);
		str = filter_buf(temp);
		len = strlen(str);
		dict[i].content = (char*)malloc(len + 1);
		strcpy(dict[i].content, str);
	}
	fclose(fp);
	return dict;
}

void search(Dict* dict, char* key, int n)
{
	for (int i = 0; i < n; i++)
	{
		if (strcmp(dict[i].key, key) == 0)
		{
			printf("OK!The content word is:%s", dict[i].content);
			printf("\n");
			return;
		}
	}
	printf("There is no %s\n", key);
}

void translate() {
	Dict* dict = dict_init();
	char key[256];
	
	while (1)
	{
		printf("Please Enter the world you want to search:");
		fgets(key, sizeof(key), stdin);

		key[strlen(key) - 1] = 0;
		printf("%s\n", key);
		search(dict, key, line_number() / 2);
	}
}

测试程序

#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<string.h>
int main()
{
	translate();
	return 0;
} 

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

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

相关文章

Redis中的事务和乐观锁实现

redis事务相关命令&#xff1a; 开启事务&#xff1a;multi 关闭事务&#xff1a;discard 提交事务&#xff1a;exec 正常执行事务情况&#xff1a; 127.0.0.1:6379> multi OK 127.0.0.1:6379> set name zhangsan QUEUED 127.0.0.1:6379> set age 20 QUEUED 127.0.0.1…

AJAX这一篇就够啦~

AJAX这一篇就够啦~AJAX1、AJAX概述1.1 AJAX简介1.2 XML简介1.3 AJAX的特点2、HTTP相关2.1 HTTP概述2.2 请求报文2.3 响应报文2.4 常见的响应状态码2.5 不同类型的请求及其作用2.6 一般http请求 与 ajax请求3、原生AJAX的使用3.1 准备工作3.2 核心对象3.3 GET请求3.4 POST请求3.…

新岁序开,和Jina AI共同码梦! (奖品攻略大揭秘)

Jina AI 北京、深圳、柏林、湾区的小伙伴给您拜年啦&#xff01; Jina AI 开源社区致力于促进 多模态 AI 技术 的应用落地以及传播&#xff0c;一直以来&#xff0c;我们都为拥有这样一个全球化、多元化和高速发展的社区而感到自豪和感激&#xff01;正值新年之际&#xff0c;我…

从C和C++内存管理来谈谈JVM的垃圾回收算法设计-下

从C和C内存管理来谈谈JVM的垃圾回收算法设计-下引言基本概念对象GC ROOTS垃圾回收常见算法标记清除优缺点引用计数优缺点部分标记清除算法优缺点复制算法优缺点多空间复制算法标记整理(标记压缩)优缺点分代设计HotSpot具体实现跨代引用并发可行性经典垃圾回收器Serial新生代垃圾…

Binding常用辅助属性、多重绑定、优先级绑定

Binding常用辅助属性、多重绑定、优先级绑定 Binding常用辅助属性 StringFormat <Window.Resources><sys:Int32 x:Key"myInt">200</sys:Int32><sys:Single x:Key"mySingle">100.123456</sys:Single> </Window.Resourc…

Linux 中断控制器(五):中断号映射

中断号分为硬件中断号(HW ID)和软件中断号(IRQ number)。 这里有两个中断控制器,处理完毕进入 CPU。外设和中断控制器连接在一起,外设给中断控制器的是硬件中断号,如果中断控制器有级联,那么硬件中断号在不同的中断控制器中可能会重复。但是到了 CPU 以后,我们需要对不…

C语言:分支语句和循环语句

往期文章 C语言&#xff1a;初识C语言 目录往期文章前言1. 什么是语句2. 分支语句&#xff08;选择结构&#xff09;2.1 if语句2.2 switch语句3. 循环语句3.1 while循环3.2 for循环3.3 do while 循环3.4 goto语句后记前言 趁热打铁啊。写完该系列第一篇博客我就来劲了&#x…

TicTacToe: 基于时序差分TD(0)算法的agent实现以及完整python实现框架

目录 1. 前言 2. TD(0) 3. 实现要点解读 3.1 Class Env 3.2 Class State 3.3 Class Agent 3.3.1 class TD0Agent(Agent) 3.3.2 class MinimaxAgent 3.3.3 class RandomAgent(Agent) 3.3.4 class HumanPlayer(Agent) 3.4 棋盘和玩家的表示 4. Utility Function 4.1…

Redis02之使用java代码操作Redis

目录 1、可视化管理工具redis-desktop-manager安装与配置 ​编辑 2、Java访问redis 注1&#xff1a;不需要记得API的方法&#xff0c;只需要查redis命令 3、web3.0设置 1、可视化管理工具redis-desktop-manager安装与配置 1.1 双击redis-desktop-manager-0.8.8.384.exe即可…

【LeetCode】2293. 极大极小游戏

2293. 极大极小游戏 题目描述 给你一个下标从 0 开始的整数数组 nums &#xff0c;其长度是 2 的幂。 对 nums 执行下述算法&#xff1a; 设 n 等于 nums 的长度&#xff0c;如果 n 1 &#xff0c;终止 算法过程。否则&#xff0c;创建 一个新的整数数组 newNums &#xf…

自动驾驶轨迹生成-贝塞尔(Bézier)曲线

引言 最近刚看完贝塞尔曲线&#xff0c;工作就遇到了相应的需求&#xff0c;所以写一下过程。主要讲的是自动驾驶中&#xff0c;车换道时用到贝塞尔曲线&#xff0c;当然其他的很多领域也会有&#xff0c;例如图形学等。 在车遇到障碍物或者是前车速度较慢的时候&#xff0c;…

【编译原理核心知识点总结】第三章、正则文法、NFA、DFA

阅读规范&#xff1a; 本文以重点为主&#xff0c;零碎知识点/相对不够重要的为辅助阅读内容&#xff0c;以脚注形式给出&#xff0c;点击脚注即可快速跳转。助解题目通常是为了帮助理解给出的题目&#xff0c;考试不考&#xff0c;若已理解可直接跳过。文中提到的课本是陈火旺…

SpringBoot 并发编程学习历程(绝对的干货)

如果一个项目总用单线程来跑&#xff0c;难免会遇到一些性能问题&#xff0c;所以再开发中&#xff0c;我们应该尽量适量的使用多线程&#xff08;在保证线程安全的情况下&#xff09;。 本教程大概目录&#xff1a; 1.模拟单线程情节 2.用Callable实现 并发编程 3.用DeferedR…

高并发系统设计 --基于bitmap的用户签到

业务需求分析 一般像微博&#xff0c;各种社交软件&#xff0c;游戏等APP&#xff0c;都会有一个签到功能&#xff0c;连续签到多少天&#xff0c;送什么东西&#xff0c;比如&#xff1a; 签到1天送10积分&#xff0c;连续签到2天送20积分&#xff0c;3天送30积分&#xff0…

Qt之QDrag的使用(含源码+注释)

一、效果示例图 提示&#xff1a;主控件&#xff08;CDragTest界面&#xff0c;UI中中包含CWidget界面&#xff09;&#xff1b;子控件&#xff08;CWidget界面&#xff0c;在CDragTest界面添加&#xff09; 提示&#xff1a;源码中拖拽数据设置的文本不同&#xff0c;是博主准…

【ONE·C || 分支循环】

总言 C语言&#xff1a;分支循环。 文章目录总言1、分支语句1.1、if语句1.1.1、基本格式1.1.2、逻辑真假与悬空else1.1.3、练习1.2、switch语句1.2.1、基本格式&#xff1a;break、case、default1.2.2、练习&#xff1a;switch语句嵌套2、循环语句2.1、while循环2.1.1、基本格式…

uniapp实现界面可任意拖动小图标

uniapp实现界面可任意拖动小图标一、问题&#xff1a;二、解决步骤2.1 根据uni-app官方提供的案例&#xff0c;创建组件2.2 在需要的界面引入组件使用额外注意一、问题&#xff1a; 例如购物车小图标可任意拖动 二、解决步骤 2.1 根据uni-app官方提供的案例&#xff0c;创建…

Kubernetes教程(二)---集群网络之 Flannel 核心原理

来自&#xff1a;指月 https://www.lixueduan.com 原文&#xff1a;https://www.lixueduan.com/posts/kubernetes/02-cluster-network/ 本文主要记录了 Kubernetes 集群网络方案之 Flannel 核心原理详解&#xff0c;包括其隧道方案中的两种&#xff1a;UDP 实现和 VXLAN 实现…

Mysql之增删改查

这里的增删改查主要是对应表中的数据&#xff0c;不像前一篇那个列类型&#xff0c;耳机具体的哪一条数据 Insert 其实我们前面都用过好多次了 比如下面那个 可以 关于那个表名后面加不加&#xff08;列类型&#xff09;&#xff0c;下面有解释 INSERT INTO shanpin VALUES…

关于yolov8一些训练的情况

U神出品了最新的yolov8&#xff0c;从公开的参数量来看确实很优秀&#xff01;&#xff01;&#xff01;&#xff01;比如下图得一些指标&#xff1a; 可以看到s模型640得map已经达到了44.9&#xff0c;v8n得map也已经达到了37.3&#xff0c;很强了&#xff0c;但是实际上是怎么…