【C语言】实现通讯录管理系统

news2024/11/17 0:02:27

大家好,我是苏貝,本篇博客带大家实现通讯录,如果你觉得我写的还不错的话,可以给我一个赞👍吗,感谢❤️
在这里插入图片描述


目录

  • 一. 前言
  • 二. 通讯录的实现
    • 2.1 写出基本框架
    • 2.2 制作menu菜单
    • 2.3 创建联系人和通讯录结构体
    • 2.4 定义通讯录并初始化
    • 2.5 使用枚举常量优化代码
    • 2.6 增加联系人信息
    • 2.7 删除联系人信息
    • 2.8 查找联系人信息
    • 2.9 修改联系人信息
    • 2.10 打印所有联系人信息
    • 2.11 以名字排序所有联系人
  • 三. 模块化代码实现
    • 3.1 test.c
    • 3.2 contact.h
    • 3.3 contact.c
    • 3.4 结果演示
  • 四. 存在的问题

一. 前言

本文将使用C语言来实现通讯录管理系统,该通讯录包括若干联系人,和每个联系人的姓名、年龄、性别、电话、地址。此通讯录的功能包括:增加联系人信息,删除联系人信息,查找联系人信息,修改联系人信息,显示所有联系人信息,根据名字顺序给所有联系人信息排序

二. 通讯录的实现

首先,我们建立1个contact.h文件,即一个头文件,用来声明。建立1个test.c文件,用来测试代码。再建立1个contact.c文件,用来写实现上述6个功能的代码

2.1 写出基本框架

下面的代码就是通讯录的基本框架,很多程序的基本框架和下面代码相似,用do-while循环来决定实现什么功能。变量input作为循环的判断条件,如果选择0,则退出循环,选择1~6之间的数则执行对应的功能,选择其它数则提示输入错误,再进入循环

int main()
{
	int input = 0;
	do
	{
		menu();
		printf("请选择:");
		scanf("%d", input);
		switch (input)
		{
		case 1:
			break;
		case 2:
			break;
		case 3:
			break;
		case 4:
			break;
		case 5:
			break;
		case 6:
			break;
		case 0:
			printf("退出程序\n");
			break;
		default:
			printf("选择错误,请重新输入\n");
			break;
		}
	} while (input);
	return 0;
}

2.2 制作menu菜单

基本框架中有menu菜单,那让我们来了解一下如何写menu菜单,即一个名为menu的函数。菜单界面就像餐厅里服务员递给你的菜单,根据菜单里的内容进行选择。选择1~6,实现特定功能;选择0,退出程序

void menu()
{
	printf("-----------------------------------\n");
	printf("***********************************\n");
	printf("******  1.Add       2.Del    ******\n");
	printf("******  3.Select    4.Modify ******\n");
	printf("******  5.Show      6.Sort   ******\n");
	printf("******  0.exit               ******\n");
	printf("***********************************\n");
	printf("-----------------------------------\n");
}

2.3 创建联系人和通讯录结构体

因为联系人信息包括姓名、年龄、性别、电话、地址,而且它们的类型和所占大小不同,所以我们想到构建一个联系人结构体,为了书写分别,我们将struct PeoInfo重命名为PeoInfo。

typedef struct PeoInfo
{
	char name[20];
	int age;
	char gender[5];
	char tele[12];
	char addr[30];
}PeoInfo;

现在我们将上面字符数组都确定了最大元素个数,那如果有一天我们发现有一个人的地址不止30个字节怎么办呢?我们接下来的代码里面也可能有addr[30],所以以后修改起来不太方便。因此,不妨我们用define定义一些标识符常量,之后敲代码时需要用到字符大小就写标识符常量而非一个数字,这样可以方便以后修改数组的大小

#define NAME_MAX 20
#define GENDER_MAX 5
#define TELE_MAX 30
#define ADDR_MAX 30

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

如果我们想存储若干个联系人的信息,那我们就要定义一个数组,数组有若干个元素,元素的类型是PeoInfo,很自然的,我们用define定义的标识符常量来表示数组的最大元素个数。通讯录除了要有所有联系人信息外,也应该可以告诉我们有多少个联系人,所以通讯录里要有2个东西,一个是若干联系人信息,一个是联系人的个数,它们的类型不同,所以用结构体表示通讯录

#define MAX 1000
typedef struct Contact
{
	PeoInfo data[MAX];
	int sz;
}Contact;

2.3 的都是声明语句,所以都放在contact.h文件中


2.4 定义通讯录并初始化

通讯录的定义简简单单,不用多说

	Contact con;

我们来想想如何将它初始化。(如果不初始化,那么con里面的内容都是随机值)
在test.c文件中调用初始化函数,在contact.h中声明初始化函数,在contact.c文件中定义函数。结构体传参时最好是传址而非传值,且初始化需要改变结构体的内容,所以只能传址

	InitContact(&con);

初始化就是将变量con的元素sz的值赋值为0,并且data数组里面的元素也都是0。sz不用多说,将data数组里面的元素全变为0,只需应用我们之前介绍过的memset函数了解memset函数

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

2.5 使用枚举常量优化代码

如果不让你看菜单,你能知道上面基本框架的switch语句中的case 1~6分别是什么意思吗?如果你和我一样不太记得的话,那我们可以使用枚举常量来帮助我们识别。枚举常量如果我们自己不去主动赋值的话,它们的值会从0开始,依次+1,所以EXIT的值为0,ADD的值为1……

enum Option
{
	EXIT,//0
	ADD,
	DEL,
	SELECT,
	MODIFY,
	SHOW,
	SORT
};

所以switch语句中的case语句后面的值可以用带提示的枚举常量代替

switch (input)
		{
		case ADD:
			break;
		case DEL:
			break;
		case SELECT:
			break;
		case MODIFY:
			break;
		case SHOW:
			break;
		case SORT:
			break;
		case EXIT:
			printf("退出程序\n");
			break;
		default:
			printf("选择错误,请重新选择\n");
			break;
		}

2.6 增加联系人信息

在test.c文件中调用函数

case ADD:
			AddContact(&con);
			break;

在contact.c文件中定义函数。先判断通讯录是否满了,若没满则输入联系人信息,最好一定要记得sz++。注意:输入年龄的scanf语句中,记得要&

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].gender);
	printf("请输入电话:");
	scanf("%s", pc->data[pc->sz].tele);
	printf("请输入地址:");
	scanf("%s", pc->data[pc->sz].addr);

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

2.7 删除联系人信息

在test.c文件中调用函数

case DEL:
			DelContact(&con);
			break;

在contact.c文件中定义函数。先判断通讯录是否为空,不为空时,输入要删除的人的姓名,在通过for循环搜索是否有该姓名的联系人,因为除了删除联系人信息功能需要搜索以外,查找和修改联系人信息也需要通过for循环搜索是否有该姓名的联系人,所以不妨将其封装成一个函数。若没有找到这个姓名的联系人,返回-1,否则返回该姓名的下标。
找到该姓名的联系人以后做删除操作,删除操作只需要让下标后面的元素依次向前进一位,覆盖掉下标的位置即可。所以循环的结束条件是i < pc->sz - 1,不要搞错。覆盖时只需要pc->data[i] = pc->data[i + 1];因为如果结构体的类型完全相同,那就可以整体赋值。最后sz–。可能有人注意到了,这个删除操作不能删除最后一个元素,是的,但没有关系,因为我们的sz–了,所以之后的遍历中不会再遍历原本的最后一个元素

int FindOfName(char* name, Contact* pc)
{
	assert(name && pc);
	int i = 0;
	for (i = 0; i < pc->sz; i++)
	{
		if (0 == strcmp(name, (pc->data[i].name)))
			return i;
	}
	return -1;
}

void DelContact(Contact* pc)
{
	assert(pc);
	char name[NAME_MAX] = { 0 };
	if (pc->sz == 0)
	{
		printf("通讯录为空,删除失败\n");
		return;
	}
	printf("请输入要删除的人的名字:");
	scanf("%s", name);
	int ret = FindOfName(name, pc);
	if (ret == -1)
	{
		printf("找不到要删除的人\n");
		return;
	}
	int i = 0;
	for (i = ret; i < pc->sz - 1; i++)
	{
		pc->data[i] = pc->data[i + 1];
	}
	pc->sz--;
	printf("删除成功\n");
}


2.8 查找联系人信息

查找联系人信息同样需要搜索函数FindOfName(name, pc);,如果要查找的人存在,那么会返回它的下标,再通过下标对这个人信息进行打印。为了直观的看出各个信息是属于哪一类的,我们可以在打印前打印提示信息,注意:年龄是%-5s,后面打印信息时是%-5d

void SelectContact(Contact* pc)
{
	char name[NAME_MAX] = { 0 };
	printf("请输入要查找的人的名字:");
	scanf("%s", name);
	int ret = FindOfName(name, pc);
	if (ret == -1)
	{
		printf("找不到要查找的人\n");
		return;
	}
	printf("%-20s%-5s%-5s%-30s%-30s\n", "姓名", "年龄", "性别", "电话", "地址");
	printf("%-20s%-5d%-5s%-30s%-30s\n", pc->data[ret].name, pc->data[ret].age,
		pc->data[ret].gender, pc->data[ret].tele, pc->data[ret].addr);
}

2.9 修改联系人信息

修改联系人信息同样需要搜索函数FindOfName(name, pc);,如果要想修改的人存在,那么会返回它的下标,再通过下标对这个人的全部信息重新输入

void ModifyContact(Contact* pc)
{
	assert(pc);
	char name[NAME_MAX] = { 0 };
	printf("请输入要修改的人的名字:");
	scanf("%s", name);
	int ret = FindOfName(name, pc);
	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].gender);
	printf("请输入电话:");
	scanf("%s", pc->data[ret].tele);
	printf("请输入地址:");
	scanf("%s", pc->data[ret].addr);
}

2.10 打印所有联系人信息

打印所有联系人信息,无非就是遍历并打印所有元素,同样加上提示信息

void ShowContact(Contact* pc)
{
	assert(pc);
	if (pc->sz == 0)
	{
		printf("通讯录为空,打印无意义\n");
		return;
	}
	int i = 0;
	printf("%-20s%-5s%-5s%-30s%-30s\n", "姓名", "年龄", "性别", "电话", "地址");
	for (i = 0; i < pc->sz; i++)
	{
		printf("%-20s%-5d%-5s%-30s%-30s\n", pc->data[i].name, pc->data[i].age,
			pc->data[i].gender, pc->data[i].tele, pc->data[i].addr);
	}
}

2.11 以名字排序所有联系人

使用qsort函数可快速排序,了解qsort函数

int cmp(const void* a, const void* b)
{
	return strcmp((char*)a, (char*)b);
}

void SortContact(Contact* pc)
{
	assert(pc);
	qsort(pc->data, pc->sz, sizeof(pc->data[0]), cmp);
	printf("排序成功\n");
}

三. 模块化代码实现

3.1 test.c

#include"contact.h"

void menu()
{
	printf("-----------------------------------\n");
	printf("***********************************\n");
	printf("******  1.Add       2.Del    ******\n");
	printf("******  3.Select    4.Modify ******\n");
	printf("******  5.Show      6.Init   ******\n");
	printf("******  7.sort      0.exit   ******\n");
	printf("***********************************\n");
	printf("-----------------------------------\n");
}

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

int main()
{
	Contact con;
	//初始化通讯录
	InitContact(&con);
	int input = 0;
	do
	{ 
		menu();
		printf("请选择:");
		scanf("%d", &input);
		switch (input)
		{
		case ADD:
			AddContact(&con);
			break;
		case DEL:
			DelContact(&con);
			break;
		case SELECT:
			SelectContact(&con);
			break;
		case MODIFY:
			ModifyContact(&con);
			break;
		case SHOW:
			ShowContact(&con);
			break;
		case INIT:
			InitContact(&con);
			break;
		case SORT:
			SortContact(&con);
			break;
		case EXIT:
			printf("退出程序\n");
			break;
		default:
			printf("选择错误,请重新选择\n");
			break;
		}
	} while (input);
	return 0;
}

3.2 contact.h

#pragma once

#include<stdio.h>
#include<assert.h>
#include<string.h>


#define NAME_MAX 20
#define GENDER_MAX 5
#define TELE_MAX 30
#define ADDR_MAX 30
#define MAX 1000


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



typedef struct Contact
{
	PeoInfo data[MAX];
	int sz;
}Contact;


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

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

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

//打印通讯录
void ShowContact(Contact* pc);

//查找联系人
void SelectContact(Contact* pc);

//修改联系人信息
void ModifyContact(Contact* pc);

//以名字排序所有联系人
void SortContact(Contact* pc);

3.3 contact.c

#include"contact.h"

//初始化通讯录
void InitContact(Contact* pc)
{
	assert(pc);
	pc->sz = 0;
	memset(pc->data, 0, sizeof(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].gender);
	printf("请输入电话:");
	scanf("%s", pc->data[pc->sz].tele);
	printf("请输入地址:");
	scanf("%s", pc->data[pc->sz].addr);

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


int FindOfName(char* name, Contact* pc)
{
	assert(name && pc);
	int i = 0;
	for (i = 0; i < pc->sz; i++)
	{
		if (0 == strcmp(name, (pc->data[i].name)))
			return i;
	}
	return -1;
}

//删除联系人
void DelContact(Contact* pc)
{
	assert(pc);
	char name[NAME_MAX] = { 0 };
	if (pc->sz == 0)
	{
		printf("通讯录为空,删除失败\n");
		return;
	}
	printf("请输入要删除的人的名字:");
	scanf("%s", name);
	int ret = FindOfName(name, pc);
	if (ret == -1)
	{
		printf("找不到要删除的人\n");
		return;
	}
	int i = 0;
	for (i = ret; i < pc->sz - 1; i++)
	{
		pc->data[i] = pc->data[i + 1];
	}
	pc->sz--;
	printf("删除成功\n");
}


//打印通讯录
void ShowContact(Contact* pc)
{
	assert(pc);
	if (pc->sz == 0)
	{
		printf("通讯录为空,打印无意义\n");
		return;
	}
	int i = 0;
	printf("%-20s%-5s%-5s%-30s%-30s\n", "姓名", "年龄", "性别", "电话", "地址");
	for (i = 0; i < pc->sz; i++)
	{
		printf("%-20s%-5d%-5s%-30s%-30s\n", pc->data[i].name, pc->data[i].age,
			pc->data[i].gender, pc->data[i].tele, pc->data[i].addr);
	}
}



//查找联系人
void SelectContact(Contact* pc)
{
	char name[NAME_MAX] = { 0 };
	printf("请输入要查找的人的名字:");
	scanf("%s", name);
	int ret = FindOfName(name, pc);
	if (ret == -1)
	{
		printf("找不到要查找的人\n");
		return;
	}
	printf("%-20s%-5s%-5s%-30s%-30s\n", "姓名", "年龄", "性别", "电话", "地址");
	printf("%-20s%-5d%-5s%-30s%-30s\n", pc->data[ret].name, pc->data[ret].age,
		pc->data[ret].gender, pc->data[ret].tele, pc->data[ret].addr);
}



//修改联系人信息
void ModifyContact(Contact* pc)
{
	assert(pc);
	char name[NAME_MAX] = { 0 };
	printf("请输入要修改的人的名字:");
	scanf("%s", name);
	int ret = FindOfName(name, pc);
	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].gender);
	printf("请输入电话:");
	scanf("%s", pc->data[ret].tele);
	printf("请输入地址:");
	scanf("%s", pc->data[ret].addr);
}


int cmp(const void* a, const void* b)
{
	return strcmp((char*)a, (char*)b);
}


//以名字排序所有联系人
void SortContact(Contact* pc)
{
	assert(pc);
	qsort(pc->data, pc->sz, sizeof(pc->data[0]), cmp);
	printf("排序成功\n");
}

3.4 结果演示

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述


四. 存在的问题

前面实现的通讯录有什么问题呢?
1.录入的信息,等程序结束后,还存在吗?不存在了,因为数据是存放内存中的,只要程序退出,掉电,都会
丢失怎么解决呢?用文件存储,数据库…
2.通讯录的大小是固定的100个元素,存放100个人的信息如果信息太多,空间小了;如果信息太少,空间大了。怎么解决?用动态内存管理!
所以期待博主的下一篇优化的通讯录管理系统吧


好了,那么本篇博客就到此结束了,如果你觉得本篇博客对你有些帮助,可以给个大大的赞👍吗,感谢看到这里,我们下篇博客见❤️

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

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

相关文章

BOA服务器(一):简介

在嵌入式设备的管理与交互中&#xff0c;基于Web方式的应用成为目前的主流&#xff0c;这种程序结构也就是大家非常熟悉的B/S结构&#xff0c;即在嵌入式设备上运行一个支持脚本或CGI功能的Web服务器&#xff0c;能够生成动态页面&#xff0c;在用户端只需要通过Web浏览器就可以…

Itheima-Springboot2【二刷】

1. Springboot parent和starter区别 parent&#xff1a;开发Springboot项目需要继承spring-boot-starter-parent&#xff0c;其中定义了若干个依赖管理&#xff08;坐标版本号&#xff09;&#xff0c;避免依赖版本冲突&#xff1b;starter&#xff1a;开发Springboot项目需要…

请解释一下React中的条件渲染(conditional rendering)。

聚沙成塔每天进步一点点 ⭐ 专栏简介 前端入门之旅&#xff1a;探索Web开发的奇妙世界 欢迎来到前端入门之旅&#xff01;感兴趣的可以订阅本专栏哦&#xff01;这个专栏是为那些对Web开发感兴趣、刚刚踏入前端领域的朋友们量身打造的。无论你是完全的新手还是有一些基础的开发…

麒麟KYLINOS桌面操作系统2303上安装tigervnc

原文链接&#xff1a;麒麟KYLINOS桌面操作系统2303上安装tigervnc hello&#xff0c;大家好啊&#xff0c;今天给大家带来在麒麟桌面操作系统2303上安装tigervnc的文章&#xff0c;本篇文章给大家讲述如何安装并且远程连接使用&#xff0c;后面会给大家更新如何将tigervnc做成桌…

【ARM Cortex-M 系列 4 番外篇 -- 常用 benchmark 介绍】

文章目录 1.1 CPU 性能测试 MIPS 计算1.1.1 Cortex-M7 CPI 1.2 benchmark 小节1.3.1 Geekbenck 介绍 1.3 编译参数配置 1.1 CPU 性能测试 MIPS 计算 每秒百万指令数 (MIPS)&#xff1a;在数据压缩测试中&#xff0c;MIPS 每秒测量一次 CPU 执行的低级指令的数量。越高越好&…

二十、设计模式之迭代器模式

目录 二十、设计模式之迭代器模式能帮我们干什么&#xff1f;主要解决什么问题&#xff1f;优缺点优点缺点&#xff1a; 使用的场景角色 实现迭代器模式定义迭代器容器实现可迭代接口迭代器实现使用 总结 二十、设计模式之迭代器模式 所属类型定义行为型提供一种方法顺序访问一…

uni-app:解决异步请求返回值问题

可以使用 Promise 或者回调函数来处理异步请求的返回值。 方法一&#xff1a; Promise处理异步请求的返回值 使用 Promise 可以将异步请求的结果通过 resolve 和 reject 返回&#xff0c;然后通过 .then() 方法获取成功的结果&#xff0c;通过 .catch() 方法获取错误信息。 …

ES Nested解释

参考博客 参考博客 nested类型是对象数据类型的专用版本&#xff0c;它允许对象数组以可以彼此独立查询的方式进行索引

React之diff原理

一、是什么 跟Vue一致&#xff0c;React通过引入Virtual DOM的概念&#xff0c;极大地避免无效的Dom操作&#xff0c;使我们的页面的构建效率提到了极大的提升 而diff算法就是更高效地通过对比新旧Virtual DOM来找出真正的Dom变化之处 传统diff算法通过循环递归对节点进行依…

为什么亚马逊卖家一定要有独立站?新手低成本快速搭建跨境电商独立站完整图文教程

效果展示 翻译助手 一、购买域名 二、购买主机托管 三、搭建独立网站 四、网站装修设计 五、网站迁移 六、补充 前言&#xff1a;为什么亚马逊卖家一定要有独立站&#xff1f; 先来谈谈为什么亚马逊卖家一定得有独立站&#xff0c;从我一些个人经历来看&#xff0c;有独…

C语言程序设计——题目:用*号输出字母C的图案。程序分析:可先用‘*‘号在纸上写出字母C,再分行输出。

题目&#xff1a;用*号输出字母C的图案。 程序分析&#xff1a;可先用*号在纸上写出字母C&#xff0c;再分行输出。 #include<stdio.h> int main() {printf(" *****\n");printf(" *\n");printf("*\n");printf("*\n");printf(&…

如何一键核实验证身份证的真伪?

据报道&#xff0c;今年10月10日&#xff0c;广东省佛山市朱某因生活琐事与丈夫发生争吵&#xff0c;民警发现她的身份证有问题。 在民警打算进一步了解情况&#xff0c;查看夫妻二人的身份证件时&#xff0c;朱某的身份证引起了民警的注意。这张身份证表面很光滑&#xff0c;…

【JAVA学习笔记】34 - 房屋出租系统(综合性强)

项目代码 https://github.com/yinhai1114/Java_Learning_Code/tree/main/IDEA_chapter09/src/com/yinhai/houserent 一、项目需求说明 实现基于文本界面的房屋出租系统&#xff0c;能够实现对房屋信息的添加、修改和删除&#xff08;用数组实现&#xff09;&#xff0c;并能够…

大学兼职教师管理系统 用JAVA语言开发

一、项目介绍 基于VueSpringBootMySQL的大学兼职教师管理系统包含学生管理、教师管理、课程档案管理、课程评价管理、课程考勤管理、授课管理、课程成绩管理教龄/薪资分析可视化图表&#xff0c;还包含系统自带的用户管理、部门管理、角色管理、菜单管理、日志管理、数据字典管…

canal五部曲-canal是如何处理insert幂等性的

canal使用了Rocketmq来接收mysql采集的binlog的事件&#xff0c;做到采集和处理的解耦。同时满足一次采集多方消费的需求。那么既然使用到Rocketmq就一定会存在MQ消费超时或是处理失败MQ重发的问题。 那么canal是如何处理MQ重复消费幂等性问题的呢 一般&#xff0c;在业务上我…

网络安全保险行业面临的挑战与变革

保险业内大多数资产类别的数据可以追溯到几个世纪以前&#xff1b;然而&#xff0c;网络安全保险业仍处于初级阶段。由于勒索软件攻击、高度复杂的黑客和昂贵的数据泄漏事件不断增加&#xff0c;许多网络安全保险提供商开始感到害怕继续承保更多业务。 保险行业 根据最近的路…

电脑每过几天就要自动更新,一键教你解决

windows更新&#xff0c;暂停更新最多只能选5个周&#xff0c;还是很麻烦&#xff0c;那么看下图&#xff0c;教你如何改为10年后&#xff1b; 建立一个txt文件&#xff0c;复制下述内容&#xff0c;然后保存&#xff0c;再把后缀名改为.reg,运行一下就可以轻松改为10年了&…

Python爬虫网易云音乐,Tkinter制作音乐播放器

目录 一、效果展示 二、环境 三、实现过程 四、源码 一、效果展示 页面的美化以及功能还有待升级~ 先来说一下已有功能吧&#xff1a; 可以在搜索框中通过歌曲或歌手名称进行搜索&#xff0c;效果和在网易云官网搜索一样。 点击开始下载&#xff0c;就会将搜索结果的第一…

小程序实现圆环进度

一&#xff1a;需求 小程序中要展示进度&#xff0c;要求类似示例图&#xff0c;用圆环形式展示进度&#xff0c;那这该如何实现呢&#xff1f;这一篇文章主要讲的就是这样一个功能。 二&#xff1a;实现 实现的大致流程是把圆环进度条封装成一个组件&#xff0c;然后在需要使…

【开源框架】Glide的图片加载流程

引入依赖 以下的所有分析都是基于此版本的Glide分析 //引入第三方库glide implementation com.github.bumptech.glide:glide:4.11.0 annotationProcessor com.github.bumptech.glide:compiler:4.11.0分析 Glide的使用就是短短的一行代码 Glide.with(this).load("xxx&q…