【C语言】通讯录系统实现 (保姆级教程,附源码)

news2024/11/25 13:51:18

目录

1、通讯录系统介绍

2、代码分装

3、代码实现步骤

3.1、制作菜单menu函数以及游戏运行逻辑流程

3.2、封装人的信息PeoInfo以及通讯录Contact结构体类型

3.3、初始化通讯录InitContact函数

3.4、增加联系人AddContact函数

3.5、显示所有联系人ShowContact函数

3.6、删除联系人DelContact函数以及判断是否存在FindByName函数

3.7、查找指定联系人SearchContact函数

3.8、修改指定联系人ModifyContact函数

3.9、以年龄排序联系人SortContact函数

4、使用动态规划优化通讯录 

5、通讯录系统完整代码


1、通讯录系统介绍

实现一个通讯录:

  1. 可以保存100个人的信息(后续优化成动态开辟)
  2. 增加人的信息
  3. 删除指定联系人的信息
  4. 查询指定联系人的信息 
  5. 修改指定联系人的信息
  6. 排序通讯录的信息
  7. 显示所有联系人的信息

其中,人的信息包括:名字、年龄、性别、电话 、地址

2、代码分装

源文件:

test.c: 测试通讯录的基本功能

game.c: 实现通讯录的相关函数

头文件:

game.h: 相关函数和类型的声明,整个代码要引用的头文件以及宏定义

3、代码实现步骤

3.1、制作菜单menu函数以及游戏运行逻辑流程

  • 首先在 test.c 中定义一个menu函数打印菜单,提示玩家进行选择。
  • scanf接收玩家输入并用switch判断,针对判断进行相应操作,输入错误时提示选择错误,重新选择。而为了能够让用户重新选择以及完成一个功能操作时再继续下一个功能操作,需要使用do while语句将它们包含起来。

使用枚举一一列举菜单选择的可能取值,便于后续使用时能够见名知意,增加代码可读性。 

【test.c】 

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

enum Option  //枚举常量
{
	EXIT,
	ADD,
	DEL,
	SEARCH,
	MODIFY,
	SHOW,
	SORT
};

int main()
{
	int input = 0;
	do
	{
		menu();
		printf("请输入你的选择:>");
		scanf("%d", &input);
		switch (input)
		{
		case ADD:
			break;
		case DEL:
			break;
		case SEARCH:
			break;
		case MODIFY:
			break;
		case SHOW:
			break;
		case SORT:
			break;
		case EXIT:
			printf("退出通讯录\n");
			break;
		default:
			printf("选择错误,重新选择\n");
			break;
		}
	} while (input);
	return 0;
}

3.2、封装人的信息PeoInfo以及通讯录Contact结构体类型

创建结构体类型PeoInfo用于描述人的信息,然后再创建一个Contact结构体包含PeoInfo和个数,这样一个通讯录结构体类型便完成了 。

为了方便后续代码的修改,这里将所有常量都用 #define 定义了变量。

【contact.h】

#define NAME_MAX 20
#define SEX_MAX 5
#define TELE_MAX 12
#define ADDR_MAX 30

#define MAX 100


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

typedef struct Contact
{
	PeoInfo data[MAX];
	int sz; //记录的是当前通讯录中存放的人的信息个数
}Contact;

3.3、初始化通讯录InitContact函数

【contact.h】

//初始化通讯录
void InitContact(Contact* pc);

【contact.c】 

assert断言,对传入的指针进行判断,防止对空指针进行操作。

使用 memset函数 初始化结构体中的数据。针对memset函数,如果不了解其原理,可以前往往期博客进行学习了解:

一篇博客学会系列(1) —— C语言中所有字符串函数以及内存函数的使用和注意事项_Hacynn的博客-CSDN博客icon-default.png?t=N7T8https://blog.csdn.net/zzzzzhxxx/article/details/133243791?spm=1001.2014.3001.5501

void InitContact(Contact* pc)
{
	assert(pc);
	pc->sz = 0;
	memset(pc->data, 0, sizeof(pc->data));
}

【test.c】 

int main()
{
	int input = 0;
    Contact con; //通讯录
	InitContact(&con);//初始化通讯录
	do
	{
		menu();
		printf("请输入你的选择:>");
		scanf("%d", &input);
		switch (input)
		{
		case ADD:
			break;
		case DEL:
			break;
		case SEARCH:
			break;
		case MODIFY:
			break;
		case SHOW:
			break;
		case SORT:
			break;
		case EXIT:
			printf("退出通讯录\n");
			break;
		default:
			printf("选择错误,重新选择\n");
			break;
		}
	} while (input);
	return 0;
}

3.4、增加联系人AddContact函数

【contact.h】

//增加联系人
void AddContact(Contact* pc);

【contact.c】

assert断言,对传入的指针进行判断,防止对空指针进行操作。 

需要判断当sz不等于MAX时再继续进行添加操作,防止溢出。

此处需要注意的是,人的信息中只有age是整型,其他的name、sex、tele、addr都为字符数组,scanf在接收age的时候需要取出age的地址,即 &(pc->data[pc->sz].age)。

void AddContact(Contact* pc)
{
	assert(pc);
	if (pc->sz == MAX)
	{
		printf("通讯录已满,无法增加\n");
		return;
	}
	
    //增加信息
	printf("请输入名字:");
	scanf("%s", pc->data[pc->sz].name);
	printf("请输入年龄:");
	scanf("%d", &(pc->data[pc->sz].age));
	printf("请输入性别:");
	scanf("%s", pc->data[pc->sz].sex);
	printf("请输入电话:");
	scanf("%s", pc->data[pc->sz].tele);
	printf("请输入地址:");
	scanf("%s", pc->data[pc->sz].addr);

	pc->sz++;
	printf("增加成功\n");

}

为了查看增加功能是否正确,我们需要显示通讯录信息,因此接下来我们实现一个函数 ShowContact 用于显示所有联系人的信息。

3.5、显示所有联系人ShowContact函数

【contact.h】

虽然显示操作不需要修改通讯录中的内容,但是出于效率和空间的考虑,还是选择传址,然后使用const修饰。

//显示所有联系人
void ShowContact(const Contact* pc);

【contact.c】

注意11行和14行的不同。

因为11行打印的标题行都是字符串,所以都是用了%s,而14行的信息行中年龄是整型的 ,因此需要使用%d打印,需要注意这里的不同。

void ShowContact(const Contact* pc)
{
	assert(pc);
	if (pc->sz == 0)
	{
		printf("通讯录为空,无需打印\n");
		return;
	}
	int i = 0;

	printf("%-20s%-5s%-5s%-12s%-30s\n", "名字", "年龄", "性别", "电话", "地址");  //标题行
	for ( i = 0; i < pc->sz; i++)
	{
		printf("%-20s%-5d%-5s%-12s%-30s\n",
			pc->data[i].name, pc->data[i].age, pc->data[i].sex, pc->data[i].tele, pc->data[i].addr);
	}
}

【test.c】

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

enum Option
{
	EXIT,
	ADD,
	DEL,
	SEARCH,
	MODIFY,
	SHOW,
	SORT
};

int main()
{
	int input = 0;
	Contact con; //通讯录
	InitContact(&con);//初始化通讯录
	do
	{
		menu();
		printf("请输入你的选择:>");
		scanf("%d", &input);
		switch (input)
		{
		case ADD:
			AddContact(&con);
			break;
		case DEL:
			break;
		case SEARCH:
			break;
		case MODIFY:
			break;
		case SHOW:
			ShowContact(&con);
			break;
		case SORT:
			break;
		case EXIT:
			printf("退出通讯录\n");
			break;
		default:
			printf("选择错误,重新选择\n");
			break;
		}
	} while (input);
	return 0;
}

 下面试着添加联系人并打印通讯录:

 

3.6、删除联系人DelContact函数以及判断是否存在FindByName函数

【contact.h】

//删除联系人
void DelContact(Contact* pc);

【contact.c】

  • 因为通过名字判断此人是否存在的FindByName函数这个功能在其他操作上也需要使用到,所以最好将它封装成一个函数,减少代码冗余并且提高写代码效率。
  • 当FindByName函数在通讯录中找到此人时返回此人在data数组中的下标,找不到是返回-1。
  • 又因为FindByName函数只在contact.c中被使用,因此可以加上static关键字修饰。
static int FindByName(Contact* pc, char name[])
{
	assert(pc);
	int i = 0;
	for ( i = 0; i < pc->sz; i++)
	{
		if (strcmp(pc->data[i].name, name) == 0)  //两个字符串比较用strcmp
			return i;
	}
	return -1;
}

void DelContact(Contact* pc)
{
	char name[NAME_MAX];
	assert(pc);
	if (pc->sz == 0)
	{
		printf("通讯录为空,无法删除\n");
		return;
	}
	printf("请输入要删除人的名字:");
	scanf("%s", name);
	//查找名字为name的人
	int ret = FindByName(pc, name);
	if (ret == -1)
	{
		printf("要删除的人不存在\n");
		return;
	}
	//删除这个人
	int i = 0;
	for (i = ret; i < pc->sz - 1; i++)    //注意此处的sz - 1 
	{
		pc->data[i] = pc->data[i + 1];
	}

	pc->sz--;
	printf("删除成功\n");
}

【删除操作图解】 

这里以0~6的下标作为例子,假如ret返回的下标时1。

只需要将ret后面的所有内容向前平移一位,就可以覆盖掉要ret指向的内容,然后再对sz--,这样变相地完成了对信息的删除。等将来又有新联系人加入时,因为sz--了所以写入信息时会覆盖掉下标为6中的内容。

此时使用该函数尝试删除一下联系人,结果是可以的。

3.7、查找指定联系人SearchContact函数

【contact.h】

//查找指定联系人
void SearchContact(Contact* pc);

【contact.c】

依然是调用FindByName函数进行判断,有此人则返回下标,没有此人则返回-1。

找到之后直接打印就行。

void SearchContact(Contact* pc)
{
	char name[NAME_MAX];
	assert(pc);
	printf("请输入要查找人的名字:");
	scanf("%s", name);

	int ret = FindByName(pc, name);
	if (ret == -1)
	{
		printf("要查找的人不存在\n");
		return;
	}
	//显示查查找到的信息

	printf("%-20s%-5s%-5s%-12s%-30s\n", "名字", "年龄", "性别", "电话", "地址");
	printf("%-20s%-5d%-5s%-12s%-30s\n",
		pc->data[ret].name, pc->data[ret].age, pc->data[ret].sex, pc->data[ret].tele, pc->data[ret].addr);


}

3.8、修改指定联系人ModifyContact函数

【contact.h】

//修改指定联系人
void ModifyContact(Contact* pc);

【contact.c】

依然是调用FindByName函数进行判断,有此人则返回下标,没有此人则返回-1。

找到之后直接将该下标下的所有信息都重新接收并覆盖,就完成了修改操作。

void ModifyContact(Contact* pc)
{
	char name[NAME_MAX];
	assert(pc);
	printf("请输入要修改人的名字:");
	scanf("%s", name);

	int ret = FindByName(pc, name);
	if (ret == -1)
	{
		printf("要修改的人不存在\n");
		return;
	}
	//修改
	printf("请输入名字:");
	scanf("%s", pc->data[ret].name);
	printf("请输入年龄:");
	scanf("%d", &(pc->data[ret].age));
	printf("请输入性别:");
	scanf("%s", pc->data[ret].sex);
	printf("请输入电话:");
	scanf("%s", pc->data[ret].tele);
	printf("请输入地址:");
	scanf("%s", pc->data[ret].addr);
}

3.9、以年龄排序联系人SortContact函数

【contact.h】

//排序联系人
void SortContact(Contact* pc);

【contact.c】

qsort可以对任意数据进行排序,因此使用qsort以年龄为关键字进行排序。

关于 qsort函数 我在往期的博客中有进行详细讲解,这里由于篇幅原因,就不过多赘述,如果不懂或者想要更深入了解的话,可以前往:【C语言】指针的进阶(二)—— 回调函数的讲解以及qsort函数的使用方式_Hacynn的博客-CSDN博客icon-default.png?t=N7T8https://blog.csdn.net/zzzzzhxxx/article/details/132941465?spm=1001.2014.3001.5501

int cmp_age(const void* e1, const void* e2)
{
	return ((PeoInfo*)e1)->age - ((PeoInfo*)e2)->age;
}

void SortContact(Contact* pc)
{
	assert(pc);
	if (pc->sz == 0)
	{
		printf("通讯录为空,无需排序\n");
		return;
	}
	qsort(pc, pc->sz, sizeof(PeoInfo), cmp_age);
	printf("排序成功\n");
}

到这里通讯录的实现就基本完成了,但是有些读者可以注意到,这个通讯录还存在一些问题:

  1. 录入的信息,等程序结束后就不存在了,这是因为数据存放在内存中的。为了解决这个问题,需要使用到文件存储的知识。
  2. 通讯录的大小是固定的100个元素,只能最多存放100个人。当信息太少时,就会导致空间剩余过大浪费空间,而当信息太多时空间又太小了无法进行存入,而解决这个问题需要使用到动态内存管理的知识。下面就来优化一下通讯录。

4、使用动态规划优化通讯录 

规定:

  1. 通讯录刚开始时可以存放3个人的信息。#define DEFAULT_SZ 3
  2. 当空间放满时,自动增加容量,每次增加2个信息的空间。#define DEFAULT_INC 2

定义通讯录Contact结构体:

因为数组空间是固定的,因此这里改成了指针,后续初始化时对data指针进行calloc动态开辟空间,并且增加用于记录当前最大容量的变量capacity

静态版本
//typedef struct Contact
//{
//	PeoInfo data[MAX];
//	int sz; //记录的是当前通讯录中存放的人的信息个数
//}Contact;

//动态版本
typedef struct Contact
{
	PeoInfo* data;
	int sz; //记录的是当前通讯录中存放的人的信息个数
    int capacity; //记录的时通讯录当前的最大容量
}Contact;

初始化通讯录InitContact函数: 

此时就可以使用calloc对data指针进行动态开辟空间,如果开辟失败则用perror打印错误信息。

对于perror函数的使用以及注意事项,在往期博客中有进行详细讲解,这就不过多赘述,感兴趣的可以前往:一篇博客学会系列(1) —— C语言中所有字符串函数以及内存函数的使用和注意事项_Hacynn的博客-CSDN博客icon-default.png?t=N7T8https://blog.csdn.net/zzzzzhxxx/article/details/133243791?spm=1001.2014.3001.5501

静态版本
//void InitContact(Contact* pc)
//{
//	assert(pc);
//	pc->sz = 0;
//	memset(pc->data, 0, sizeof(pc->data));
//}

//动态版本
void InitContact(Contact* pc)
{
	assert(pc);
	pc->sz = 0;
	pc->capacity = DEFAULT_SZ;  //#define DEFAULT_SZ 3
	pc->data = (PeoInfo*)calloc(pc->capacity, sizeof(PeoInfo));
	if (pc->data == NULL)
	{
		perror("InitContact->calloc");
		return;
	}
}

 增加联系人AddContact函数:

因为此时使用了动态规划,所以不会存在通讯录满了无法增加的情况,此时if语句改为判断是否已满,如果已满则使用realloc增容。此时需要用另一个指针ptr接收realloc的空间,判断ptr指向的空间是否开辟成功,成功时再将ptr赋值给pc->data,防止数据丢失。

静态版本
//void AddContact(Contact* pc)
//{
//	assert(pc);
//	if (pc->sz == MAX)
//	{
//		printf("通讯录已满,无法增加\n");
//		return;
//	}
//	
//	printf("请输入名字:");
//	scanf("%s", pc->data[pc->sz].name);
//	printf("请输入年龄:");
//	scanf("%d", &(pc->data[pc->sz].age));
//	printf("请输入性别:");
//	scanf("%s", pc->data[pc->sz].sex);
//	printf("请输入电话:");
//	scanf("%s", pc->data[pc->sz].tele);
//	printf("请输入地址:");
//	scanf("%s", pc->data[pc->sz].addr);
//
//	pc->sz++;
//	printf("增加成功\n");
//
//}

//动态版本
void AddContact(Contact* pc)
{
	assert(pc);
	if (pc->sz == pc->capacity)
	{
		PeoInfo* ptr = (PeoInfo*)realloc(pc->data, (pc->capacity + DEFAULT_INC) * sizeof(PeoInfo));
		if (ptr != NULL)
		{
			pc->data = ptr;
			pc->capacity += DEFAULT_INC;  //#define DEFAULT_INC 2
            printf("增容成功\n");
		}
		else
		{
			perror("AddContact->realloc");
			return;
		}
	}

	printf("请输入名字:");
	scanf("%s", pc->data[pc->sz].name);
	printf("请输入年龄:");
	scanf("%d", &(pc->data[pc->sz].age));
	printf("请输入性别:");
	scanf("%s", pc->data[pc->sz].sex);
	printf("请输入电话:");
	scanf("%s", pc->data[pc->sz].tele);
	printf("请输入地址:");
	scanf("%s", pc->data[pc->sz].addr);

	pc->sz++;
	printf("增加成功\n");

}

在EXIT退出通讯录时候记得对动态开辟的空间进行free操作:

定义一个DestroyContact函数用于free掉动态开辟的空间。

【contact.h】

//销毁通讯录
void DestroyContact(Contact* pc);

【contact.c】

void DestroyContact(Contact* pc)
{
	free(pc->data);
	pc->data = NULL;
	pc->sz = 0;
	pc->capacity = 0;
}

5、通讯录系统完整代码

 源码已经上传至gitee中,有需要可以前往领取:Contact/Contact · Nadez/Study_c - 码云 - 开源中国 (gitee.com)

 

如果觉得作者写的不错,求给博主一个大大的点赞支持一下,你们的支持是我更新的最大动力!

如果觉得作者写的不错,求给博主一个大大的点赞支持一下,你们的支持是我更新的最大动力!

如果觉得作者写的不错,求给博主一个大大的点赞支持一下,你们的支持是我更新的最大动力!

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

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

相关文章

对比两个数组中 每个对应位置的元素大小 返回每个对比结果组成的列表 numpy.fmin()

【小白从小学Python、C、Java】 【计算机等级考试500强双证书】 【Python-数据分析】 对比两个数组中 每个对应位置的元素大小 返回每个对比结果组成的列表 numpy.fmin() [太阳]选择题 请问代码中最后输出正确的是&#xff1f; import numpy as np a np.array([1, 3, 6, 8]) …

面试必考精华版Leetcode1372. 二叉树中的最长交错路径

题目&#xff1a; 代码&#xff08;首刷看解析)&#xff1a; class Solution { public:int maxAns;//dir 0 left,1 rightvoid dfs(TreeNode* root,bool dir,int len){maxAnsmax(maxAns,len);if(!dir){if(root->left) dfs(root->left,1,len1);if(root->right) dfs(roo…

给奶牛做直播之四

一、前言 给奶牛做直播之三 我们讲了怎么搭建RTMP直播服务器&#xff0c;前几天在折腾Android直播推拉流一直没个结果&#xff0c;顺手整理了一下Android如何加载SO动态库&#xff0c;本想顺着这条路把JNI、NDK、JSBridge、Python调用SO这些一起整理出来 &#xff0c;这样搞就…

叶工好容6-自定义与扩展

本篇主要介绍扩展的本质以及CRD与Operator之间的区别&#xff0c;帮助大家理解相关的概念以及知道要进行扩展需要做哪些工作。 CRD&#xff08;CustomerResourceDefinition&#xff09; 自定义资源定义,代表某种自定义的配置或者独立运行的服务。 用户只定义了CRD没有任何意…

28296-2012 含镍生铁 思维导图

声明 本文是学习GB-T 28296-2012 含镍生铁. 而整理的学习笔记,分享出来希望更多人受益,如果存在侵权请及时联系我们 1 范围 本标准规定了含镍生铁的技术要求、试验方法、检验规则以及包装、储运、标志和质量证明书。 本标准适用于炼钢、铸造或合金材料中作为镍元素添加剂的…

C++实现集群聊天服务器

C实现集群聊天服务器 JSON Json是一种轻量级的数据交换模式&#xff08;也叫做数据序列化方式&#xff09;。Json采用完全独立于编程语言的文本格式来存储和表示数据。见解和清晰的层次结构使得Json称为理想的数据交换语言。易于阅读和编写。同时也易于支持机器解析和生成&am…

28384-2012 平台式平型网版印刷机 阅读笔记

声明 本文是学习GB-T 28384-2012 平台式平型网版印刷机. 而整理的学习笔记,分享出来希望更多人受益,如果存在侵权请及时联系我们 1 范围 本标准规定了平台式平型网版印刷机的术语和定义、型式与基本参数、要求、试验方法、检验规则、 标志、包装、运输与贮存。 本标准适用…

babel.config.js配置文件详解

文章目录 一、前言三、babel 详解四、拓展阅读 一、前言 项目开发阶段&#xff0c;使用可选链操作符 ?. 出现以下编译报错问题&#xff1a; 分析&#xff1a;由于可选链操作符 ?. 是ES2020&#xff08;即ES11&#xff09;中推出的新语法&#xff0c;允许我们不需要校验当前属…

【软考】系统集成项目管理工程师(五)项目立项管理【5分】

一、 项目建议书 1、定义 项目建议书又称为立项申请&#xff1b;建设单位向上级主管部门提交项目申请时所必须的文件&#xff0c;是对拟建项目提出的框架性的总体设想&#xff1b;是项目发展周期的初始阶段&#xff0c;是国家或上级主管部门选择项目的依据&#xff0c;也是可行…

取消excel表格中的隐藏行

Excel工作表中的行列隐藏了数据&#xff0c;如何取消隐藏行列呢&#xff1f;今天分享几个方法给大家 方法一&#xff1a; 选中隐藏的区域&#xff0c;点击右键&#xff0c;选择【取消隐藏】就可以了 方法二&#xff1a; 如果工作表中有多个地方有隐藏的话&#xff0c;还是建…

【python基础】复杂数据类型-列表类型(元组)

1.初识元组 列表非常适合用于存储在程序运行期间可能变化的数据集。列表是可以修改的。 然而,有时候需要创建一系列不可修改的元素,元组可以满足这种需求 python将不能修改的值称为不可变的,而不可变的列表被称为元组。 元组看起来犹如列表,但使用圆括号而不是方括号来标识…

苹果文件传到mac电脑用什么软件?

在数字化时代&#xff0c;文件传输已经成为我们日常生活中不可或缺的一部分。然而&#xff0c;苹果用户在将手机文件传输到电脑时&#xff0c;往往会面临一些困扰。曾经的“文件传输助手”并不能完全满足用户的需求。于是&#xff0c;很多人开始寻找更便捷的解决方案。在本文中…

Nginx 代理WebSocket

## √ map $http_upgrade $connection_upgrade {default upgrade; close; }## √ upstream websocket {server 127.0.0.1:9999 weight10 max_fails2 fail_timeout30s; }server {listen 8020;gzip on;gzip_min_length 1k;gzip_comp_level 9;gzip_types text/plain application/…

集合-set系列集合

系列文章目录 1.集合-Collection-CSDN博客​​​​​​ 2.集合-List集合-CSDN博客 3.集合-ArrayList源码分析(面试)_喜欢吃animal milk的博客-CSDN博客 4.数据结构-哈希表_喜欢吃animal milk的博客-CSDN博客 5.集合-set系列集合-CSDN博客 文章目录 目录 系列文章目录 文章目录…

JS defineProperty详解

defineProperty Object.defineProperty():方法会在对象上直接定义个新的属性&#xff0c;或者修改现有的属性&#xff0c;并返回此对象 let obj {} //与我们使用 obj.name zhangsna 效果一样 但是用defineProperty定义的属性无法改变 或者删除 Object.defineProperty(obj,n…

【面试经典150 | 数组】加油站

文章目录 写在前面Tag题目来源题目解读解题方法方法一&#xff1a;暴力枚举方法二&#xff1a;一次遍历 写在最后 写在前面 本专栏专注于分析与讲解【面试经典150】算法&#xff0c;两到三天更新一篇文章&#xff0c;欢迎催更…… 专栏内容以分析题目为主&#xff0c;并附带一些…

单元测试框架-Pytest(简单学习)

单元测试框架-Pytest Pytest是基于Python语言的单元测试框架&#xff0c;也是一个命令行的工具&#xff0c;比 unittest 测试框架更灵活。具有以下特点&#xff1a; 入门简单&#xff0c;易上手&#xff0c;官方文档丰富而且使用广泛&#xff0c;有大量的参数例子。 unittest…

2.索引操作

1. 创建索引 创建索引就等于创建数据库&#xff0c;ES使用put操作创建索引&#xff0c;我们创建一个students的索引&#xff0c;只需要发生put请求&#xff1a;http://127.0.0.1:9200/students 2. 查看索引 2.1 查看所有索引&#xff1a; 使用http://127.0.0.1:9200/_cat/ind…

抓包习讯云院校数据通过PHP解析导入数据库

前言 最近&#xff0c;打卡APP需要这个数据&#xff0c;通过抓包后发现这个数据是固定的&#xff0c;获取很简单&#xff0c;但是数据太多&#xff0c;手动导入不显示&#xff0c;于是分析了json格式后果断通过脚本完成 【推荐】 《【MQTT】Esp32数据上传采集&#xff1a;最…

搭建后台框架

一、引入依赖 项目的包层级关系如下 依赖引入 <?xml version"1.0" encoding"UTF-8"?> <project xmlns"http://maven.apache.org/POM/4.0.0"xmlns:xsi"http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation&quo…