精通C语言:打造高效便捷的通讯录管理系统

news2024/11/23 12:26:02

pFp8UCq.jpg

✨✨ 欢迎大家来到贝蒂大讲堂✨✨

🎈🎈养成好习惯,先赞后看哦~🎈🎈

所属专栏:C语言项目
贝蒂的主页:Betty‘s blog

引言

在我们大致学习完C语言之后,我们就可以利用目前所学的知识去做一些有意思的项目,而今天贝蒂就带大家完成一个通讯录的简易实现,

本章你可能需要的知识:

  1. 动态内存的使用:动态内存管理
  2. 文件的创建与使用:文件操作

1. 通讯录要求

  1. 通讯录包括每个人的姓名,性别,年龄,电话与地址。
  2. 玩家可以自由选择通讯录的进出。
  3. 玩家可以自由增删查改通讯录中的数据。

2. 多文件管理

为了方便代码的管理和保证通讯录实现逻辑的清晰性,我们将采用多文件管理的模式。

  1. 创建头文件contact.c,包含所有头文件(其他源文件只需引用它即可),以及所有通讯录功能的展现。

  2. 创建源文件contact.c,负责通讯录所有功能的具体代码实现。

  3. 创建源文件text.c,负责展现通讯录实现的总体逻辑。

3. 通讯录的准备

3.1 预处理信息

为了方便我们后续更换通讯的信息,我们可以利用来定义通讯录的具体信息的大小。

#define MAX 100//最大人数
#define MAX_NAME 20//名字最大长度
#define MAX_SEX 5//性别最大长度
#define MAX_TELE 12//电话最大长度
#define MAX_ADDR 30//地址最大长度

3.2 结构体定义

每个人的通讯录都要包含姓名,性别,年龄,电话与地址等信息,这时就需要我们创建一个结构体来方便管理。

typedef struct PeoInfo
{
	char name[MAX_NAME];//名字
	int age;//年龄
	char sex[MAX_SEX];//性别
	char tele[MAX_TELE];//电话
	char addr[MAX_ADDR];//地址
}PeoInfo;

而我们需要用这个结构体创建一个大小为100的数组,并且我们还需要知道当前通讯录的大小才能进行增删查改的操作,这两者息息相关,为了简化代码和增加代码的可读性,我们可以将这两者重新定义一个结构体。

typedef struct contact
{
	PeoInfo data[MAX];//一百个人的数据
	int sz;//通讯录的大小
}contact;

4. 简易菜单

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

画面展示:

5. 通讯录具体功能

5.1 初始化

我们首先对通讯录进行初始化。

void InitContact(contact* pc)//初始化
{
	assert(pc);
	pc->sz = 0;
	memset(pc->data, 0, sizeof(pc->data));
}

5.2 展示联系人

当用户选择5时自动展示通讯录中的用户,并且展示用户过程中需要进行对齐,便于用户观看。

void DisplayContact(contact* pc)//打印信息
{
	assert(pc);
	printf("%-15s\t%-5s\t%-5s\t%-12s\t%-30s\n", "姓名", "年纪",
		"性别", "电话", "地址");//默认右对齐,修改为左对齐
	//中间也要留下足够的空间
	for (int i = 0; i < pc->sz; i++)
	{
		printf("%-15s\t%-5d\t%-5s\t%-12s\t%-30s\n", pc->data[i].name,
			pc->data[i].age,
			pc->data[i].sex,
			pc->data[i].tele,
			pc->data[i].addr);
	}
}

5.3 添加联系人

用户选择1可以自由添加联系人,如果通讯录已满,则提醒用户通讯录已满,请先清理通讯录。

(1) 检查通讯录是否已满

如果通讯录满了返回0,未满则返回1。

int CheckContact(contact*pc)//检查大小
{
	assert(pc);
	if (pc->sz == 100)
	{
		return 0;
	}
	return 1;
}
(2) 添加

当通讯录未满时,用户可以输入数据添加新用户。

void AddContact(contact* pc)//增加联系人
{
	assert(pc);
	int ret = CheckContact(pc);//检查是否满了
	if (ret == 0)
	{
		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);
	printf("用户添加成功!\n");
	pc->sz++;
}

5.4 删除联系人

用户可以选择2清理通讯录,删除指定联系人

(1) 寻找下标

在删除指定练习人时我们需通过其姓名寻找该联系人的下标。找到返回其下标,否则返回-1、

int FindName(contact* pc, char name[])
{
	assert(pc&&name);
	for (int pos = 0; pos < pc->sz; pos++)
	{
		if (strcmp(pc->data[pos].name, name) == 0)
		{
			return pos;
		}
	}
	return -1;
}
(2) 删除

通过寻找到的下标,我们可以利用后面的数据依次覆盖来达到删除的目的。

注意:我们不能覆盖最后一个数据否则就会发生数组越界,这时我们只需减去通讯录此时的大小就好了。

void DeleteContact(contact* pc)//删除联系人
{
	assert(pc);
         assert(pc->sz >= 0);
	char name[MAX_NAME];
	printf("请输入需要删除人的姓名:> ");
	scanf("%s", name);
	int pos = FindName(pc, name);
	if (pos == -1)
	{
		printf("通讯录中并没有这个人!!\n");
		return;
	}
	for (int i = pos; i < pc->sz - 1; i++)
	{
		pc->data[i] = pc->data[i + 1];//覆盖
	}
    	printf("删除成功\n");
	pc->sz--;
}

删除前:

删除后 :

5.5 查找联系人

通过选择3查找指定联系人,没有找到则提醒用户没有该用户,查找到就打印其信息。

void SearchContact(contact* pc)//查找联系人
{
	assert(pc);
	char name[MAX_NAME];
	printf("请输入需要查找人的姓名:> ");
	scanf("%s", name);
	int pos = FindName(pc, name);
	if (pos == -1)
	{
		printf("通讯录中并没有这个人!!\n");
		return;
	}
	printf("%-15s\t%-5s\t%-5s\t%-12s\t%-30s\n", "姓名", "年纪",
		"性别", "电话", "地址");
	printf("%-15s\t%-5d\t%-5s\t%-12s\t%-30s", pc->data[pos].name,
		pc->data[pos].age,
		pc->data[pos].sex,
		pc->data[pos].tele,
		pc->data[pos].addr);
}

5.6 修改联系人

我们可以通过选择4修改指定联系人的信息。

void ModifyContact(contact* pc)//修改联系人
{
	assert(pc);
	char name[MAX_NAME];
	printf("请输入需要修改人的姓名:> ");
	scanf("%s", name);
	int pos = FindName(pc, name);
	if (pos == -1)
	{
		printf("通讯录中并没有这个人!!\n");
		return;
	}
	printf("请输入联系人的姓名:> ");
	scanf("%s", pc->data[pos].name);
	printf("请输入联系人的年龄:> ");
	scanf("%d", &(pc->data[pos].age));
	printf("请输入联系人的性别:> ");
	scanf("%s", pc->data[pos].sex);
	printf("请输入联系人的电话:> ");
	scanf("%s", pc->data[pos].tele);
	printf("请输入联系人的地址:> ");
	scanf("%s", pc->data[pos].addr);
	printf("修改成功\n");
}

修改前:

修改后:

5.7 排序联系人

我们可以选择6对通讯录进行排序,可以按照姓名,年纪,性别,电话,地址排序。

int cmp1(const void* p1, const void* p2)
{
	return strcmp(((PeoInfo*)p1)->name, ((PeoInfo*)p2)->name);
}
int cmp2(const void* p1, const void* p2)
{
	return ((PeoInfo*)p1)->age- ((PeoInfo*)p2)->age;
}
int cmp3(const void* p1, const void* p2)
{
	return strcmp(((PeoInfo*)p1)->sex, ((PeoInfo*)p2)->sex);
}
int cmp4(const void* p1, const void* p2)
{
	return strcmp(((PeoInfo*)p1)->tele, ((PeoInfo*)p2)->tele);
}
int cmp5(const void* p1, const void* p2)
{
	return strcmp(((PeoInfo*)p1)->addr, ((PeoInfo*)p2)->addr);
}
void SortByName(contact* pc)
{
	qsort(pc, pc->sz, sizeof(PeoInfo), cmp1);
}
void SortByAge(contact* pc)
{
	qsort(pc, pc->sz, sizeof(PeoInfo), cmp2);
}
void SortBySex(contact* pc)
{
	qsort(pc, pc->sz, sizeof(PeoInfo), cmp3);
}
void SortByTele(contact* pc)
{
	qsort(pc, pc->sz, sizeof(PeoInfo), cmp4);
}
void SortByAddr(contact* pc)
{
	qsort(pc, pc->sz, sizeof(PeoInfo), cmp4);
}
void SortContact(contact* pc)//排序联系人
{
	assert(pc);
	printf("请选择如何排序:> ");
	char input[20];
	scanf("%s", input);
	if (strcmp(input, "姓名")==0)
	{
		SortByName(pc);//按姓名排序
	}
	else if (strcmp(input, "年龄") == 0)
	{
		SortByAge(pc);//按年龄排序
	}
	else if (strcmp(input, "性别") == 0)
	{
		SortBySex(pc);//按性别排序
	}
	else if (strcmp(input, "电话") == 0)
	{
		SortByTele(pc);//按电话排序
	}
	else if (strcmp(input, "地址") == 0)
	{
		SortByAddr(pc);//按地址排序
	}
	else
	{
		printf("输入非法,请重新输入\n");
	}
}

6. 改进通讯录

6.1 动态内存开辟

上述通讯录有一个致命的缺点——通讯录大小固定,为了解决这个问题我可以使用我们前面学过的动态内存开辟

(1) 新增变量

为了方便我们知道此时的容量大小,我们将在结构体中加入新的变量。

typedef struct contact
{
	PeoInfo *data;//动态开辟的数据
	int sz;//通讯录的大小
	int capacity;//通讯录的容量
}contact;
(2) 初始化
void InitContact(contact* pc)//初始化
{
	assert(pc);
	pc->sz = 0;
	pc->data = (PeoInfo*)calloc(2, sizeof(PeoInfo));
	if (pc->data == NULL)
	{
		perror("InitContact:");
		return;
	}
	pc->capacity = 2;
	/*memset(pc->data, 0, sizeof(pc->data));*/
}
(3) 增容

当通讯录用户数量满时增加内存空间。

void CheckCapacity(contact* pc)//增容
{
	if (pc->sz == pc->capacity)
	{
		PeoInfo* tmp = (PeoInfo*)realloc(pc->data, (pc->capacity + 2) * sizeof(PeoInfo));
		if (tmp != NULL)
		{
			pc->data = tmp;
		}
		else
		{
			perror("CheckCapacity:");
			return;
		}
		pc->capacity += 2;
		printf("增容成功\n");
	}
}

6.2 文件保存

我们发现每当我们关闭程序时我们写入的数据会被清空,我们要想保存上次写入的数据就应该使用文件操作

(1) 加载数据

每次初始化时就要将上次文件的数据导入进来。

void LoadContact(contact* pc)//加载上次数据
{
	PeoInfo tmp = { 0 };
	FILE* pf = fopen("contact.txt", "rb");
	if (pf == NULL)
	{
		return;
	}
	//读取文件,存放到通讯录
	while (fread(&tmp, sizeof(PeoInfo), 1, pf))
	//返回值为0就是遇见文件末尾
	{
		CheckCapacity(pc);
		pc->data[pc->sz] = tmp;
		pc->sz++;
	}

	fclose(pf);
	pf = NULL;
}
(2) 保存数据

当程序正常结束时保存数据。

void SaveContact(contact* pc)//保存数据
{
	FILE* pfWrite = fopen("contact.txt", "wb");
	if (pfWrite == NULL)
	{
		perror("fopen:");
		return;
	}
	//写通讯录中数据到文件中
	int i = 0;
	for (i = 0; i < pc->sz; i++)
	{
		fwrite(&(pc->data[i]), sizeof(PeoInfo), 1, pfWrite);
	}
	fclose(pfWrite);
	pfWrite = NULL;
	printf("保存成功\n");

}

7. 通讯录逻辑的搭建

  1. 用户通过数字选择功能。
  2. 每次选择完之后返回菜单。
  3. 选择退出之后保存数据,程序结束。
enum Option
	//利用枚举增加代码的可读性
{
	EXIT,//0
	ADD,
	DEL,
	SEARCH,
	MODIFY,
	DISPLAY,
	SORT
};
void test()
{
	int input = 0;
	contact con;
	InitContact(&con);
	do
	{
		menu();
		printf("请输入你的选择:>");
		scanf("%d", &input);
		switch (input)
		{
		case ADD:
			AddContact(&con);
			break;
		case DEL:
			DeleteContact(&con);
			break;
		case SEARCH:
			SearchContact(&con);
			break;
		case MODIFY:
			ModifyContact(&con);
			break;
		case DISPLAY:
			DisplayContact(&con);
			break;
		case SORT:
			SortContact(&con);
			break;
		case EXIT:
			SaveContact(&con);//退出保存数据
		    DestroyContact(&con);
			break;
		default:
			printf("非法输入,请重新输入\n");
			break;
		}
	} while (input);
}
int main()
{
	test();
	return 0;
}

8. 完整代码

8.1 contact.h

#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<assert.h>
#define MAX_NAME 20//名字最大长度
#define MAX_SEX 5//性别最大长度
#define MAX_TELE 12//电话最大长度
#define MAX_ADDR 30//地址最大长度
typedef struct PeoInfo
{
	char name[MAX_NAME];//名字
	int age;//年龄
	char sex[MAX_SEX];//性别
	char tele[MAX_TELE];//电话
	char addr[MAX_ADDR];//地址
}PeoInfo;
typedef struct contact
{
	PeoInfo *data;//动态开辟的数据
	int sz;//通讯录的大小
	int capacity;//通讯录的容量
}contact;
void InitContact(contact* pc);//初始化
void DisplayContact(contact* pc);//打印信息
void AddContact(contact* pc);//增加联系人
void DeleteContact(contact* pc);//删除联系人
void SearchContact(contact* pc);//查找联系人
void ModifyContact(contact* pc);//修改联系人
void SortContact(contact* pc);//排序联系人
void SaveContact(contact* pc);//保存数据
void DestroyContact(contact* pc);//销毁内存

8.2 contact.c

#include"contact.h"
void CheckCapacity(contact* pc)//增容
{
	if (pc->sz == pc->capacity)
	{
		PeoInfo* tmp = (PeoInfo*)realloc(pc->data, (pc->capacity + 2) * sizeof(PeoInfo));
		if (tmp != NULL)
		{
			pc->data = tmp;
		}
		else
		{
			perror("CheckCapacity:");
			return;
		}
		pc->capacity += 2;
		printf("增容成功\n");
	}
}
void LoadContact(contact* pc)//加载上次数据
{
	PeoInfo tmp = { 0 };
	FILE* pf = fopen("contact.txt", "rb");
	if (pf == NULL)
	{
		return;
	}
	//读取文件,存放到通讯录
	while (fread(&tmp, sizeof(PeoInfo), 1, pf))
	//返回值为0就是遇见文件末尾
	{
		CheckCapacity(pc);
		pc->data[pc->sz] = tmp;
		pc->sz++;
	}

	fclose(pf);
	pf = NULL;
}

void InitContact(contact* pc)//初始化
{
	assert(pc);
	pc->sz = 0;
	pc->data = (PeoInfo*)calloc(2, sizeof(PeoInfo));
	if (pc->data == NULL)
	{
		perror("InitContact:");
		return;
	}
	pc->capacity = 2;
	LoadContact(pc);
	/*memset(pc->data, 0, sizeof(pc->data));*/
}
void DisplayContact(contact* pc)//打印信息
{
	assert(pc);
	printf("%-15s\t%-5s\t%-5s\t%-12s\t%-30s\n", "姓名", "年纪",
		"性别", "电话", "地址");//默认右对齐,修改为左对齐
	//中间也要留下足够的空间
	for (int i = 0; i < pc->sz; i++)
	{
		printf("%-15s\t%-5d\t%-5s\t%-12s\t%-30s\n", pc->data[i].name,
			pc->data[i].age,
			pc->data[i].sex,
			pc->data[i].tele,
			pc->data[i].addr);
	}
}

void AddContact(contact* pc)//增加联系人
{
	assert(pc);
	CheckCapacity(pc);//检查是否满了
	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);
	printf("用户添加成功!\n");
	pc->sz++;
}
int FindName(contact* pc, char name[])
{
	assert(pc&&name);
	for (int pos = 0; pos < pc->sz; pos++)
	{
		if (strcmp(pc->data[pos].name, name) == 0)
		{
			return pos;
		}
	}
	return -1;
}
void DeleteContact(contact* pc)//删除联系人
{
	assert(pc);
	assert(pc->sz >= 0);
	char name[MAX_NAME];
	printf("请输入需要删除人的姓名:> ");
	scanf("%s", name);
	int pos = FindName(pc, name);
	if (pos == -1)
	{
		printf("通讯录中并没有这个人!!\n");
		return;
	}
	for (int i = pos; i < pc->sz - 1; i++)
	{
		pc->data[i] = pc->data[i + 1];//覆盖
	}
	printf("删除成功\n");
	pc->sz--;
}
void SearchContact(contact* pc)//查找联系人
{
	assert(pc);
	char name[MAX_NAME];
	printf("请输入需要查找人的姓名:> ");
	scanf("%s", name);
	int pos = FindName(pc, name);
	if (pos == -1)
	{
		printf("通讯录中并没有这个人!!\n");
		return;
	}
	printf("%-15s\t%-5s\t%-5s\t%-12s\t%-30s\n", "姓名", "年纪",
		"性别", "电话", "地址");
	printf("%-15s\t%-5d\t%-5s\t%-12s\t%-30s", pc->data[pos].name,
		pc->data[pos].age,
		pc->data[pos].sex,
		pc->data[pos].tele,
		pc->data[pos].addr);
}
void ModifyContact(contact* pc)//修改联系人
{
	assert(pc);
	char name[MAX_NAME];
	printf("请输入需要修改人的姓名:> ");
	scanf("%s", name);
	int pos = FindName(pc, name);
	if (pos == -1)
	{
		printf("通讯录中并没有这个人!!\n");
		return;
	}
	printf("请输入联系人的姓名:> ");
	scanf("%s", pc->data[pos].name);
	printf("请输入联系人的年龄:> ");
	scanf("%d", &(pc->data[pos].age));
	printf("请输入联系人的性别:> ");
	scanf("%s", pc->data[pos].sex);
	printf("请输入联系人的电话:> ");
	scanf("%s", pc->data[pos].tele);
	printf("请输入联系人的地址:> ");
	scanf("%s", pc->data[pos].addr);
	printf("修改成功\n");
}
int cmp1(const void* p1, const void* p2)
{
	return strcmp(((PeoInfo*)p1)->name, ((PeoInfo*)p2)->name);
}
int cmp2(const void* p1, const void* p2)
{
	return ((PeoInfo*)p1)->age- ((PeoInfo*)p2)->age;
}
int cmp3(const void* p1, const void* p2)
{
	return strcmp(((PeoInfo*)p1)->sex, ((PeoInfo*)p2)->sex);
}
int cmp4(const void* p1, const void* p2)
{
	return strcmp(((PeoInfo*)p1)->tele, ((PeoInfo*)p2)->tele);
}
int cmp5(const void* p1, const void* p2)
{
	return strcmp(((PeoInfo*)p1)->addr, ((PeoInfo*)p2)->addr);
}
void SortByName(contact* pc)
{
	qsort(pc, pc->sz, sizeof(PeoInfo), cmp1);
}
void SortByAge(contact* pc)
{
	qsort(pc, pc->sz, sizeof(PeoInfo), cmp2);
}
void SortBySex(contact* pc)
{
	qsort(pc, pc->sz, sizeof(PeoInfo), cmp3);
}
void SortByTele(contact* pc)
{
	qsort(pc, pc->sz, sizeof(PeoInfo), cmp4);
}
void SortByAddr(contact* pc)
{
	qsort(pc, pc->sz, sizeof(PeoInfo), cmp4);
}
void SortContact(contact* pc)//排序联系人
{
	assert(pc);
	printf("请选择如何排序:> ");
	char input[20] = { 0 };
	scanf("%s", input);
	if (strcmp(input, "姓名")==0)
	{
		SortByName(pc);//按姓名排序
	}
	else if (strcmp(input, "年龄") == 0)
	{
		SortByAge(pc);//按年龄排序
	}
	else if (strcmp(input, "性别") == 0)
	{
		SortBySex(pc);//按性别排序
	}
	else if (strcmp(input, "电话") == 0)
	{
		SortByTele(pc);//按电话排序
	}
	else if (strcmp(input, "地址") == 0)
	{
		SortByAddr(pc);//按地址排序
	}
	else
	{
		printf("输入非法,请重新输入\n");
	}
}
void DestroyContact(contact* pc)
{
	free(pc->data);
	pc->data= NULL;
	pc->capacity = 0;
	pc->sz = 0;
	printf("销毁成功\n");
}
void SaveContact(contact* pc)//保存数据
{
	FILE* pfWrite = fopen("contact.txt", "wb");
	if (pfWrite == NULL)
	{
		perror("fopen:");
		return;
	}
	//写通讯录中数据到文件中
	int i = 0;
	for (i = 0; i < pc->sz; i++)
	{
		fwrite(&(pc->data[i]), sizeof(PeoInfo), 1, pfWrite);
	}
	fclose(pfWrite);
	pfWrite = NULL;
	printf("保存成功\n");

}

8.3 text.c

#include"contact.h"

enum Option
	//利用枚举增加代码的可读性
{
	EXIT,//0
	ADD,
	DEL,
	SEARCH,
	MODIFY,
	DISPLAY,
	SORT
};

void menu()
{
    printf("***********************************\n");
    printf("**    1.add          2.delete    **\n");
    printf("**    3.search       4.modify    **\n");
    printf("**    5.display      6.sort      **\n");
    printf("**             0.exit            **\n");
    printf("***********************************\n");
}
void test()
{
	int input = 0;
	contact con;
	InitContact(&con);
	do
	{
		menu();
		printf("请输入你的选择:>");
		scanf("%d", &input);
		switch (input)
		{
		case ADD:
			AddContact(&con);
			break;
		case DEL:
			DeleteContact(&con);
			break;
		case SEARCH:
			SearchContact(&con);
			break;
		case MODIFY:
			ModifyContact(&con);
			break;
		case DISPLAY:
			DisplayContact(&con);
			break;
		case SORT:
			SortContact(&con);
			break;
		case EXIT:
			SaveContact(&con);//退出保存数据
		    DestroyContact(&con);
			break;
		default:
			printf("非法输入,请重新输入\n");
			break;
		}
	} while (input);
}

int main()
{
	test();
	return 0;
}

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

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

相关文章

MATLAB环境下使用二维高分辨时频分析方法提取波状分量

MATLAB环境下使用二维高分辨时频分析方法提取波状分量&#xff08;分离混合地震数据&#xff09;。 为了得到更高的时频分辨率&#xff0c;近年来涌现出了大量的新的时频分析方法。有些以线性和非线性时频分析为基础&#xff0c;有些则另辟蹊径&#xff0c;比如Hilbert-Huang变…

2.12日学习打卡----初学RocketMQ(三)

2.12日学习打卡 目录&#xff1a; 2.12日学习打卡一. RocketMQ高级特性&#xff08;续&#xff09;消息重试延迟消息消息查询 二.RocketMQ应用实战生产端发送同步消息发送异步消息单向发送消息顺序发送消息消费顺序消息全局顺序消息延迟消息事务消息消息查询 一. RocketMQ高级特…

Packet Tracer - Configuring ASA Basic Settings and Firewall Using CLI

Packet Tracer - 使用CLI配置ASA基本设置和防火墙 IP地址表 目标 验证连接并探索ASA设备使用CLI配置ASA的基本设置和接口安全级别使用CLI配置路由、地址转换和检查策略配置DHCP、AAA和SSH服务配置DMZ区域、静态NAT和访问控制列表&#xff08;ACL&#xff09; 场景 您的公司…

grafana配置钉钉告警模版(一)

1、配置钉钉告警模版 创建钉钉告警模版&#xff0c;然后在创建钉钉告警时调用模版。 定义发送内容具体代码 my_text_alert_list 是模版名称后面再配置钉钉告警时需要调用。 {{/* 定义消息体片段 */}} {{ define "my_text_alert_list" }}{{ range . }}告警名称&…

redis为什么使用跳跃表而不是树

Redis中支持五种数据类型中有序集合Sorted Set的底层数据结构使用的跳跃表&#xff0c;为何不使用其他的如平衡二叉树、b树等数据结构呢&#xff1f; 1&#xff0c;redis的设计目标、性能需求&#xff1a; redis是高性能的非关系型&#xff08;NoSQL&#xff09;内存键值数据…

在Postgresql 下安装QGIS

安装QGIS的前提是需要 在windows下安装Postgres&#xff0c;具体可以参考文章&#xff1a; Windows 安装和连接使用 PgSql数据库 安装GIS的具体步骤如下&#xff1a; 一.打开 Application Stack Builder 二.选择默认端口和安装目标 三.选择【Spatial Extensions】 四.选择安装…

链式结构实现队列

链式结构实现队列 1.队列1.1队列的概念及结构1.2队列的实现 2. 队列的各种函数实现3. 队列的全部代码实现 1.队列 1.1队列的概念及结构 队列&#xff1a;只允许在一端进行插入数据操作&#xff0c;在另一端进行删除数据操作的特殊线性表&#xff0c;队列具有先进先出 FIFO(Fi…

【大厂AI课学习笔记】【2.1 人工智能项目开发规划与目标】(5)数据管理

今天学习了数据管理&#xff0c;以及数据管理和数据治理的区别和联系。 数据管理&#xff1a;利用计算机硬件和软件技术对数据进行有效的收集、存储、处理和应用的过程其目的在于充分有效地发挥数据的作用。 实现数据有效管理的关键是数据组织。 数据管理和数据治理的区别&am…

无人驾驶控制算法LQR和MPC的仿真实现

1. LQR控制器 1.1 问题陈述 考虑一个质量为 m m m 的滑块在光滑的一维地面上运动。初始时&#xff0c;滑块的位置和速度均为 0 0 0。我们的目标是设计一个控制器&#xff0c;基于传感器测得的滑块位置 x x x&#xff0c;为滑块提供外力 u u u&#xff0c;使其能够跟随参考…

每日一题——LeetCode1455.检查单词是否为句中其他单词的前缀

方法一 js函数slice() 将字符串按空格符分割为单词数组&#xff0c;记searchWord的长度为n&#xff0c;分割每个单词的前n位看是否和searchWord匹配 var isPrefixOfWord function(sentence, searchWord) {let res sentence.split(" ")for(i 0 ; i < res.lengt…

七天入门大模型 :大模型LLM 训练理论和实战最强总结!

本文对于想入门大模型、面试大模型岗位、大模型实具有很强的指导意义。喜欢记得收藏、关注、点赞 文章目录 技术交流群用通俗易懂方式讲解系列总览介绍预训练范式如何确定自己的模型需要做什么训练&#xff1f;模型推理的一般过程PyTorch 框架设备PyTorch基本训练代码范例Trans…

【复现】cellinx摄像设备 未授权漏洞_50

目录 一.概述 二 .漏洞影响 三.漏洞复现 1. 漏洞一&#xff1a; 四.修复建议&#xff1a; 五. 搜索语法&#xff1a; 六.免责声明 一.概述 cellinx是一家韩国的摄像设备 二 .漏洞影响 通过未授权访问可以创建用户进入后台&#xff0c;可能造成系统功能破坏。 三.漏洞复…

CCF编程能力等级认证GESP—C++8级—20231209

CCF编程能力等级认证GESP—C8级—20231209 单选题&#xff08;每题 2 分&#xff0c;共 30 分&#xff09;判断题&#xff08;每题 2 分&#xff0c;共 20 分&#xff09;编程题 (每题 25 分&#xff0c;共 50 分)奖品分配大量的工作沟通 答案及解析单选题判断题编程题1编程题2…

GIS利用不舒适指数绘制地区的生物气候舒适度图

生物气候舒适度定义了最适宜的气候条件,在这种条件下,人们感到健康和充满活力。生物气候舒适度地图对城市规划研究特别有用。温度、相对湿度和风速等要素对评估生物气候舒适度非常重要。[1] 人们已经得出了许多不同的指数来确定生物气候舒适度。在本博文中,我们将使用广泛使…

基于SringBoot+Vue的大学生社团管理系统

末尾获取源码作者介绍&#xff1a;大家好&#xff0c;我是墨韵&#xff0c;本人4年开发经验&#xff0c;专注定制项目开发 更多项目&#xff1a;CSDN主页YAML墨韵 学如逆水行舟&#xff0c;不进则退。学习如赶路&#xff0c;不能慢一步。 目录 一、项目简介 1.1 研究背景 1.…

英文论文(sci)解读复现【NO.21】一种基于空间坐标的轻量级目标检测器无人机航空图像的自注意

此前出了目标检测算法改进专栏&#xff0c;但是对于应用于什么场景&#xff0c;需要什么改进方法对应与自己的应用场景有效果&#xff0c;并且多少改进点能发什么水平的文章&#xff0c;为解决大家的困惑&#xff0c;此系列文章旨在给大家解读发表高水平学术期刊中的 SCI论文&a…

leetcode hot100不同路径Ⅱ

本题和之前做的不同路径类似&#xff0c;区别是本题中加入了障碍&#xff0c;遇到障碍之后需要避开&#xff08;注意&#xff0c;这里依旧是只能向下向右移动&#xff09;&#xff0c;那么也就是说&#xff0c;有障碍的点是到达不了的&#xff0c;并且 &#xff0c;我在初始化的…

Java基于微信小程序的医院挂号小程序,附源码

博主介绍&#xff1a;✌程序员徐师兄、7年大厂程序员经历。全网粉丝12w、csdn博客专家、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌ &#x1f345;文末获取源码联系&#x1f345; &#x1f447;&#x1f3fb; 精彩专栏推荐订阅&#x1f447;…

Atmel ATSHA204应用总结

1 ACES软件安装 Atmel Crypto Evaluation Studio (ACES) https://www.microchip.com/DevelopmentTools/ProductDetails/PartNO/Atmel%20Crypto%20%20Studio%20(ACES) 2 基本概念 ACES CE&#xff1a;Atmel Crypto Evalution Studio Configuration Environment&#xff08;基于加…

Intelij Terminal中文乱码解决

第一&#xff1a; &#xff08;重启Intelij生效&#xff09; -Dfile.encodingUTF-8 第二&#xff1a; &#xff08;重启Intelij生效&#xff09; 如果还不行&#xff0c;第三&#xff1a; 测试结果很ok&#xff1a;