c语言通讯录max——数据的持久化处理(详解)

news2024/12/22 22:22:13

用文件操作升级通讯录

    • 前言
    • 1.实现逻辑
    • 2.用哪种文件存储数据
    • 2. `save_contact`函数设计
    • 3. `load_contact` 函数设计
    • 5.代码总览
      • contact.h
      • contact.c
      • text.c

前言

在有关通讯录的上一篇博客中,作者用柔性数组实现了动态改变通讯录占用空间的功能,但是在最后还是留下了一个问题,那就是由于通讯录中的内容是存放在内存中的,在程序结束之后就会全部消失,所以这个通讯录还是没有使用价值。

我们的想法是既然是通讯录就应该把里面的内容记录下来,只有当我们自己选择删除数据的时候,数据才无法找回。

这就涉及到了数据持久化的问题,我们一般数据持久化的方法有,把数据存放在磁盘文件、存放到数据库等方式。
本篇博客将使用文件将数据直接存放在电脑的硬盘上,做到了数据的持久化

由于使用了c语言文件操作的相关内容,如果有对文件操作不熟悉的小伙伴,建议先看看博主有关文件操作的博客,这样效果更好!

链接 : c语言文件操作

另外,由于该次通讯录的改进只改变一部分操作,大体实现不变,因此不再次细讲普通通讯录的实现细节,如果想具体看实现细节的可以看博主之前的博客:

简单通讯录链接: 简单通讯录实现(C语言)—在添加联系人的时候完成了排序工作,并且用二分查找方式寻找联系人
动态通讯录链接:动态通讯录实现——运用了柔性数组,并且加入了增容和缩容处理

好了,前言到此为止,现在进入正题,通讯录max实现!

1.实现逻辑

首先,我们考虑以下怎么将数据添加到文件中,这里我想到了两种办法:

  • 每次添加或删除联系人同时更改文件内的内容
  • (借用文件缓冲区的思路)在程序退出执行时再将内存中创建的通讯录内的内容全部写入文件中。

这里作者选择了第二种方法,有两个原因。

  1. 第一个方式需要频繁的进行文件操作,而第二个方式只需要进行一次文件操作即可。
  2. 第二种方式的实现更加简单(doge)

那么,整体逻辑就出来了,每次启动将文件中的内容全部输入程序运行时创建的通讯录中,程序结束时再将修改后的通讯录写入文件中。

这里作者设计了两个函数,
a. save_contact函数在退出通讯录的时候把信息到保存到文件中
b. load_contact函数在通讯录打开的时候,可以把文件中的信息加载到通讯录中。


2.用哪种文件存储数据

在开始之前还有一个问题是应该使用文本文件还是二进制文件来存储数据?

我们来分析一下两者的优缺点:

文本文件

  • 优点: 能够看懂存放通讯录信息的文件内的内容
  • 缺点:信息传输过程繁琐,要取出文件内的信息需要依次取出最小成员信息。

二进制文件:

  • 优点: 能够一次取出所需大小的空间,信息传输过程简洁,只需要使用一次freadfwrite即可
  • 缺点: 看不懂文件内的内容,想要知道联系人的具体信息必须启动程序选择展示功能才能看到。

如下:
a

那么我们应该使用哪种文件来存放信息呢?
这里我选择了二进制文件来存放信息,虽然文本文件能看到通讯录里的相关内容,但是排版也不会像程序运行时显示的那样清晰,所以作用不大,并且使用二进制文件实现更加简单。


2. save_contact函数设计

save_contact函数的功能是在程序结束时将此次对通讯录的修改保存到文件中,该函数要实现一下几步。

  1. 首先我们就需要打开你要存放通讯录信息的文件

这里用"w"模式(写模式)打开文件,对上一次的文件进行覆盖,这样就不会出现数据重复的现象

  1. 将通讯录中的内容一个个写入文件中(使用fwrite函数)
  2. 关闭文件(为了刷新文件缓冲区,将数据真正存放到文件中)

如果不明白文件缓冲区是什么的小伙伴可以看博主的上一篇博客:
链接: C语言文件操作
在最后一部分讲到了文件缓冲区的概念和为什么要刷新缓冲区。

这就是save_contact函数的整体内容啦!现在来看看具体实现代码:

void save_contact(contact* pc)
{
	FILE* pf = fopen("contact.txt", "wb");
	//判断文件是否成功打开
	if (pf)
	{
		int i = 0;
		//将通讯录中的联系人信息逐个写入文件中
		for (i = 0; i < pc->sz; ++i)
		{
			fwrite(pc->people + i,sizeof(per_info),1 , pf);
		}
		//关闭文件,保存数据
		fclose(pf);
		//将pf置为空防止野指针的滥用
		pf = NULL;
		printf("保存通讯录成功!\n");
	}
	else
	{
		perror("save_contact::fopen");
		exit(errno);
	}
}

3. load_contact 函数设计

以同样的方法我们来看看load_contact的实现思路。
如果是对于简单通讯录实现加载函数则比较简单,就是把文件内的联系人名称依次读取到通讯录即可,但是如果是动态通讯录就稍微复杂一点了。

每次读取了一个联系人之后都要检查此时的联系人数量有没有达到通讯录的最大容量,如果达到,就需要进行增容处理。

上次在设计动态通讯录的时候我们为增容设计了一个函数ins_capcity,我们现在就可以利用它。

具体代码:

void load_contact(contact** pc)
{
	per_info tmp = { 0 };
	FILE* pf = fopen("contact.txt", "rb");
	int i = 0;
	//判断文件是否正常打开
	if(pf)
	{
		//先将信息读取到中间变量tmp中
		while (fread(&tmp, sizeof(per_info), 1, pf))
		{
			//如果达到最大容量,则需增容
			if ((*pc)->sz == (*pc)->max_ele)
			{
				(*pc) = ins_capcity(*pc);
				(*pc)->max_ele += INS_ELE;
				//printf("增容成功!\n");
			}
			//将信息放入通讯录中
			(*pc)->people[i] = tmp;
			++i;
			++(*pc)->sz;
		}
		//关闭文件
		fclose(pf);
		pf = NULL;
	}
	else
	{
		perror("load_contact::fopen");
		exit(errno);
	}

}

到此,使用文件操作对信息的持久化处理就到此圆满结束了,如果大家有一些不懂的地方或者觉得作者的实现方法还有漏洞的地方可以在评论区提出,作者都会一一回复的哦!如果觉得不错,还请大家点个小小的赞喽哈哈!
阿尼亚!


5.代码总览

contact.h

#pragma once
#define _CRT_SECURE_NO_WARNINGS 1
#define PEOPLE_MAX 100
#define SEX_MAX 5
#define TELE_MAX 12
#define NAME_MAX 20
#define ADDR_MAX 25
#define INIT_CAPCITY 3
#define INS_ELE 2

#include<stdio.h>
#include<string.h>
#include<assert.h>
#include<stdlib.h>
#include<windows.h>
#include<errno.h>

typedef enum option
{
	EXIT,
	ADD,
	DEL,
	MODIFY,
	SEARCH,
	SHOW,
	EMPTY
}option;

typedef struct per_info
{
	int age;
	char sex[SEX_MAX];
	char tele[TELE_MAX];
	char name[NAME_MAX];
	char addr[ADDR_MAX];
}per_info;

/*静态版本*/
//typedef struct contact
//{
//	per_info people[PEOPLE_MAX];
//	int sz;
//}contact;

/*动态版本*/
typedef struct contact
{
	int sz;
	int max_ele;
	per_info people[];
}contact;

//使用传址调用能够减少空间的使用

//初始化通讯录
void init_contact(contact** pc);

//添加联系人
void add_person(contact** pc);

//显示联系人
void show_person(const contact* pc);

//搜索联系人
void search_person(const contact*pc);

//删除联系人
void del_person(contact** pc);

//修改联系人
void mod_person(contact* pc);

//清空联系人
void empty_person(contact** pc);

//销毁通讯录
void destory_contact(contact* pc);

//保存通讯录
void save_contact(contact* pc);

//加载联系人
void load_contact(contact** pc);

contact.c

#include"contact.h"

/*静态版本*/
//void init_contact(contact* pc)
//{
//	//pc不能是空指针
//	assert(pc);
//	memset(pc->people, 0, sizeof(pc->people));
//	pc->sz = 0;
//}

/*动态版本+柔性数组*/
void init_contact(contact** pc)
{
	//pc不能是空指针
	assert(pc);
	contact* ret = (contact*)calloc(1, sizeof(contact) + INIT_CAPCITY * sizeof(per_info));
	if (ret)
	{
		*pc = ret;
		(*pc)->max_ele = INIT_CAPCITY;
	}
	else
	{
		perror("init_contact::calloc");
	}
	load_contact(pc);
}

int cmp(const void* a, const void* b)
{
	return strcmp(((per_info*)a)->name, ((per_info*)b)->name);
}

/*静态版本*/
//void add_person(contact* pc)
//{
//	assert(pc);
//	printf("请输入联系人的姓名:>");
//	scanf("%s", pc->people[pc->sz].name);
//	printf("请输入联系人的性别:>");
//	scanf("%s", pc->people[pc->sz].sex);
//	printf("请输入联系人的年龄:>");
//	scanf("%d", &(pc->people[pc->sz].age));
//	printf("请输入联系人的地址:>");
//	scanf("%s", pc->people[pc->sz].addr);
//	printf("请输入联系人的电话:>");
//	scanf("%s", pc->people[pc->sz].tele);
//	++pc->sz;
//	qsort(pc->people, pc->sz, sizeof(pc->people[0]), cmp);
//	printf("添加成功!\n");
//	Sleep(1000);
//	system("cls");
//}

contact* ins_capcity(contact* pc)
{
	contact* ret = (contact*)realloc(pc, (pc->max_ele + INS_ELE) * sizeof(per_info) + sizeof(contact));
	if (ret)
		return ret;
	else
		perror("ins_capcity::realloc");
}

/*动态版本+柔性数组*/
void add_person(contact** pc)
{
	assert(pc);
	if ((*pc)->sz == (*pc)->max_ele)
	{
		*pc = ins_capcity(*pc);
		(*pc)->max_ele += INS_ELE;
		printf("增容成功!\n");
	}
	printf("请输入联系人的姓名:>");
	scanf("%s", (*pc)->people[(*pc)->sz].name);
	printf("请输入联系人的性别:>");
	scanf("%s", (*pc)->people[(*pc)->sz].sex);
	printf("请输入联系人的年龄:>");
	scanf("%d", &((*pc)->people[(*pc)->sz].age));
	printf("请输入联系人的地址:>");
	scanf("%s", (*pc)->people[(*pc)->sz].addr);
	printf("请输入联系人的电话:>");
	scanf("%s", (*pc)->people[(*pc)->sz].tele);
	++(*pc)->sz;
	qsort((*pc)->people, (*pc)->sz, sizeof((*pc)->people[0]), cmp);
	printf("添加成功!\n");
	Sleep(1000);
	system("cls");
}

void show_person(const contact* pc)
{
	system("cls");
	assert(pc);
	printf("%-20s\t%-4s\t%-5s\t%-12s\t%-25s\n", "姓名", "年龄", "性别", "电话", "地址");
	for (int i = 0; i < pc->sz; ++i)
	{
		printf("%-20s\t%-4d\t%-5s\t%-12s\t%-25s\n", pc->people[i].name,
			pc->people[i].age,
			pc->people[i].sex,
			pc->people[i].tele,
			pc->people[i].addr);
	}
	printf("\n\n");
}

int find_by_name(const contact* pc, char* name)
{
	int left = 0;
	int right = pc->sz - 1;
	while (left <= right)
	{
		int mid = (left + right) / 2;
		if (strcmp(pc->people[mid].name, name) > 0)
			right = mid - 1;
		else if (strcmp(pc->people[mid].name, name) < 0)
			left = mid + 1;
		else
			return mid;
	}
	return -1;
}

void search_person(const contact* pc)
{
	assert(pc);
	char name[NAME_MAX] = { 0 };
	printf("请输入你要查找联系人的姓名:>");
	scanf("%s", name);
	int pos = find_by_name(pc, name);
	if (-1 == pos)
	{
		printf("找不到该联系人\n");
		return;
	}
	printf("%-20s\t%-4s\t%-5s\t%-12s\t%-25s\n", "姓名", "年龄", "性别", "电话", "地址");
		printf("%-20s\t%-4d\t%-5s\t%-12s\t%-25s\n", pc->people[pos].name,
			pc->people[pos].age,
			pc->people[pos].sex,
			pc->people[pos].tele,
			pc->people[pos].addr);
}

void del_person(contact** pc)
{
	assert(pc);
	if ((*pc)->max_ele - (*pc)->sz == INS_ELE)
	{
		contact* ret = (contact*)realloc(*pc, sizeof(contact) + sizeof(per_info) * ((*pc)->max_ele - INS_ELE));
		if (ret)
		{
			*pc = ret;
			(*pc)->max_ele -= 1;
			//printf("缩容成功!\n");
		}
		else
			perror("del_person::realloc");
	}
	printf("请输入你要删除的联系人:>");
	char name[NAME_MAX] = { 0 };
	scanf("%s", name);
	int pos = find_by_name(*pc, name);
	if (-1 == pos)
	{
		printf("你要删除的联系人不存在.\n");
		return;
	}
	for (int i = pos; i < (*pc)->sz - 1; ++i)
	{
		(*pc)->people[i] = (*pc)->people[i + 1];
	}
	--(*pc)->sz;
	printf("删除成功!\n");
	Sleep(1000);
	system("cls");
}

void mod_person(contact* pc)
{
	printf("请输入你要修改的联系人的名字:>");
	char name[NAME_MAX] = { 0 };
	scanf("%s", name);
	int pos = find_by_name(pc, name);
	if (-1 == pos)
	{
		printf("找不到要修改的联系人。\n");
		return;
	}
	printf("请输入联系人的姓名:>");
	scanf("%s", pc->people[pos].name);
	printf("请输入联系人的性别:>");
	scanf("%s", pc->people[pos].sex);
	printf("请输入联系人的年龄:>");
	scanf("%d", &(pc->people[pos].age));
	printf("请输入联系人的地址:>");
	scanf("%s", pc->people[pos].addr);
	printf("请输入联系人的电话:>");
	scanf("%s", pc->people[pos].tele);
	qsort(pc->people, pc->sz, sizeof(pc->people[0]), cmp);
	printf("修改成功!\n");
	Sleep(1000);
	system("cls");
}

/*静态版本*/
//void empty_person(contact* pc)
//{
//	assert(pc);
//	if (!pc->sz)
//	{
//		printf("无联系人,无需清空。\n");
//		Sleep(1000);
//		system("cls");
//		return;
//	}
//	memset(pc, 0, sizeof(contact));
//	printf("清空联系人成功!\n");
//	Sleep(1000);
//	system("cls");
//}

/*动态版本*/
void empty_person(contact** pc)
{
	assert(pc);
	contact* ret = realloc(*pc, INIT_CAPCITY * sizeof(per_info) + sizeof(contact));
	if (ret)
	{
		*pc = ret;
	}
	else
		perror("empry_person::realloc");
	memset(*pc, 0, INIT_CAPCITY * sizeof(per_info) + sizeof(contact));
	(*pc)->max_ele = INIT_CAPCITY;
	printf("清空联系人成功\n");
	Sleep(1000);
	system("cls");
}

void destory_contact(contact* pc)
{
	pc->sz = 0;
	free(pc);
	pc = NULL;
}

void save_contact(contact* pc)
{
	FILE* pf = fopen("contact.txt", "wb");
	if (pf)
	{
		int i = 0;
		for (i = 0; i < pc->sz; ++i)
		{
			fwrite(pc->people + i,sizeof(per_info),1 , pf);
		}
		fclose(pf);
		pf = NULL;
		printf("保存通讯录成功!\n");
	}
	else
	{
		perror("save_contact::fopen");
		exit(errno);
	}
}

void load_contact(contact** pc)
{
	per_info tmp = { 0 };
	FILE* pf = fopen("contact.txt", "rb");
	int i = 0;
	if(pf)
	{
		while (fread(&tmp, sizeof(per_info), 1, pf))
		{
			if ((*pc)->sz == (*pc)->max_ele)
			{
				(*pc) = ins_capcity(*pc);
				(*pc)->max_ele += INS_ELE;
				printf("增容成功!\n");
			}
			(*pc)->people[i] = tmp;
			++i;
			++(*pc)->sz;
		}
		fclose(pf);
		pf = NULL;
	}
	else
	{
		perror("load_contact::fopen");
		exit(errno);
	}

}

text.c

#include"contact.h"

void menu(void)
{
	printf("****************************\n");
	printf("****  1.add    2.del    ****\n");
	printf("****  3.modify 4.search ****\n");
	printf("****  5.show   6.empty  ****\n");
	printf("****       0.exit       ****\n");
	printf("****************************\n");
}


int main()
{
	int input = 0;
	//创建通讯录
	contact* record;
	//为使得初始化更灵活,用函数封装
	init_contact(&record);
	do
	{
		menu();
		printf("请选择你需要做的操作:>");
		scanf("%d", &input);
		while (getchar() != '\n')
			continue;
		system("cls");
		switch (input)
		{
		case ADD:
			add_person(&record);
			break;
		case DEL:
			del_person(&record);
			break;
		case MODIFY:
			mod_person(record);
			break;
		case SEARCH:
			search_person(record);
			break;
		case SHOW:
			show_person(record);
			break;
		case EMPTY:
			empty_person(&record);
			break;
		case 0:
			save_contact(record);
			destory_contact(record);
			printf("退出通讯录\n");
			break;
		default:
			printf("输入错误,请重新输入。\n");
			break;
		}
	} while (input);
	return 0;
}

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

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

相关文章

【Go基础】Http编程

文章目录1. http协议1.1 请求方法1.2 URL1.3 协议版本1.4 请求头1.5 请求正文1.6 http response1.7 https2. go语言http标准库3. http router4. 请求校验5. http中间件6. GIN6.1 路由6.2 参数获取6.3 利用postman提交http请求6.4 生成response6.5 参数检验6.6 中间件6.7 会话7.…

互联网分层模型

互联网的逻辑实现被分为好几层。每一层都有自己的功能&#xff0c;就像建筑物一样&#xff0c;每一层都靠下一层支持。用户接触到的只是最上面的那一层&#xff0c;根本不会感觉到下面的几层。要理解互联网就需要自下而上理解每一层的实现的功能。如上图所示&#xff0c;互联网…

55.Isaac教程--Livox 激光雷达

Livox 激光雷达 ISAAC教程合集地址文章目录Livox 激光雷达支持的硬件和固件在桌面上设置和运行示例应用程序在机器人上设置和运行示例应用程序查看正在运行的应用程序将来Livox 激光雷达 Isaac SDK 支持使用 Livox LIDAR&#xff0c;包括兼容的驱动程序和示例应用程序。 支持的…

Android马甲包的那些事儿

制作Android马甲包最简单的方式就是使用 productFlavors 机制。本文就是在productFlavors机制的基础上制作的马甲包&#xff0c;每个马甲只需要在build.gradle文件中配置一下包名、各种key、签名文件配置启动页、logo、app名等资源配置服务器域名、微信分享回调Activity等代码此…

Windows上tensorflow的GPU死活引用不了(tensorflow 2.11无法调用GPU)

tensorflow对于gpu的支持只到2.10&#xff0c;如果你装了最新的tf(2.11)&#xff0c;需要先卸载2.11。 安装代码&#xff1a; pip install tensorflow2.10 -i https://pypi.tuna.tsinghua.edu.cn/simple/解决过程&#xff1a; 查看CUDA与cuDNN配套版本&#xff1a; https:/…

解决ModuleNotFoundError: No module named ‘pygame‘问题

一、问题描述在开发环境运行Python的源码游戏时&#xff0c;游戏不能正常运行&#xff0c;且提示&#xff08;ModuleNotFoundError: No module named pygame【没有发现模块错误&#xff1a;没有发现名为pygame的模块】&#xff09;如下图所示&#xff1a;二、问题分析通过查看提…

OpenCV实战——基于均值漂移算法检测图像内容

OpenCV实战——基于均值漂移算法检测图像内容0. 前言1. 均值漂移算法2. 检测图像内容3. 完整代码相关链接0. 前言 直方图反投影的结果是一个概率图&#xff0c;表示在特定图像位置找到给定图像内容的概率。假设我们现在知道一个物体在图像中的大概位置&#xff1b;概率图可用于…

在 Navicat Monitor for MySQL/MariaDB 中配置实例

Navicat Monitor for MySQL/MariaDB 是一个无代理的远程服务器监控工具&#xff0c;它包含的功能可以使监控数据库&#xff08;DB&#xff09;实例发挥最大效用和更轻松。此外&#xff0c;基于服务器的架构使其可以通过网页浏览器从任何地方访问&#xff0c;从而为你提供无障碍…

DaVinci 项目设置:图像缩放调整

项目设置/图像缩放调整Project Settings/Image Scaling图像缩放调整 Image Scaling选项卡可用于设置片段在输入、输出时的缩放及相应的插值算法。图像缩放调整Image Scaling主要用于选择缩放处理的插值方法&#xff0c;也可用于载入输入、输出缩放调整的预设。缩放过滤器Resize…

特别提醒|2023年考PMP需关注的5大问题

目前知道的是2023年考试时间为3月、5月、8月、11月&#xff0c;但是3月不给新报名&#xff0c;需要报名的话&#xff0c;就是报5月的考试了。当然有的伙伴会有一些小问题&#xff0c;这里给大家整理了一些基本的问题给大家回答一下&#xff0c;大家如果还有其他的问题可以评论提…

[Flink] 容错机制与状态一致性机制

文章目录1.状态一致性1.1 状态一致性分类2.一致性检查点 checkpoint3.端到端&#xff08;end-to-end&#xff09;状态一致性4. 端到端的精确一次&#xff08;exactly-once&#xff09;保证4.1 幂等写入4.2 事务写入5.FlinkKafka 端到端状态一致性的保证5.1 Exactly-once 两阶段…

常见智力题汇总(建议收藏)

&#x1f680;write in front&#x1f680; &#x1f4dc;所属专栏&#xff1a; 智力题 &#x1f6f0;️博客主页&#xff1a;睿睿的博客主页 &#x1f6f0;️代码仓库&#xff1a;&#x1f389;VS2022_C语言仓库 &#x1f3a1;您的点赞、关注、收藏、评论&#xff0c;是对我最…

Web 前端开发技术 —— JavaScript

Web 前端开发技术 —— JavaScript 总结 JavaScript 内容&#xff01; 文章目录Web 前端开发技术 —— JavaScript一、js 的引用方式与执行顺序1、引用方式在标签中直接写 js 代码复用 js 代码通过 import 方式2、执行顺序3、html、css、js 三者之间的关系二、变量与运算符变量…

C++之函数重载

文章目录前言一、函数重载二、如何支持函数重载&#xff08;C支持函数重载的原理--名字修饰(name Mangling)&#xff09;三、参数有什么区别才能构成函数重载1.参数个数不同2.参数类型不同3.参数顺序不同四、返回值类型不同是否可以构成函数重载总结前言 我们知道在使用C语言进…

jmh的一些作用

目录说明说明 jmh可以用来java基准测试&#xff0c;性能测试用这个测比较标准&#xff0c;可以设置预热、迭代次数&#xff0c;对某块代码精准测试&#xff0c;耗时时间单位有毫秒、纳秒等。 就先说到这\color{#008B8B}{ 就先说到这}就先说到这 在下Apollo\color{#008B8B}{在下…

AcWing 323. 战略游戏(树形DP + 状态机DP)

AcWing 323. 战略游戏&#xff08;树形DP 状态机DP&#xff09;一、问题二、分析1、思路分析2、状态表示3、状态转移4、循环设计5、初末状态三、代码一、问题 二、分析 1、思路分析 这道题最后问的其实就是&#xff0c;在一棵树中&#xff0c;每个边至少选择一个端点的条件下…

【FLASH存储器系列十五】NAND Flash究竟能不能随机读写到某个字节的数据?

网上有很多文章写道&#xff0c;nand flash的读写操作是以page为单位&#xff0c;还有文章说些nand flash时必须按page0、page1、page2…的顺序写&#xff0c;必须先写完前面的page才能写后面的page。难道nandflash就不能随机读到某个字节吗&#xff1f;只能一次性读一页&#…

区区几行代码,就能全面实现 Python 自动探索性数据分析

探索性数据分析是数据科学模型开发和数据集研究的重要组成部分之一。在拿到一个新数据集时首先就需要花费大量时间进行EDA来研究数据集中内在的信息。自动化的EDA Python包可以用几行Python代码执行EDA。 在本文中整理了10个可以自动执行EDA并生成有关数据的见解的Python包&am…

C语言——二分查找与猜数字游戏

文章目录二分查找二分查找的思想二分查找的条件二分查找的实现过程代码举例猜数字游戏游戏说明猜数字游戏思想代码实现打印菜单打印主函数打印游戏函数整体代码演示二分查找 题目&#xff1a; 在一个有序数组中查找具体的某个数字n。 首先我们先定义一个110的数组 &#xff0c;…

immersive-translate(沉浸式双语网页翻译扩展),解决谷歌翻译无法使用问题

前言 谷歌停止了大陆的谷歌翻译服务&#xff0c;所以找到了immersive-translate 插件解决翻译问题。当然 最直接就是 换个浏览器比如 Edge\Firefox等等。 主要特性 智能识别网页主内容区&#xff0c;区别于同类插件翻译网页所有的区域&#xff0c;这可以极大增强译文的阅读…