当前位置: 首页 > news >正文

通讯录的实现(超详细)——C语言(进阶)

       

目录

一、创建联系人信息(结构体)

二、创建通讯录(结构体)

三、define定义常量

四、打印通讯录菜单

五、枚举菜单选项

六、初始化通讯录

七、实现通讯的的功能

7.1 增加加联系人

7.2 显示所有联系人的信息

​7.3 单独查找人的函数

7.4 删除指定联系人

7.5 查找指定联系人

7.6 修改指定联系人

7.7 按照名字顺序进行排序

7.8  清空所有联系人

八、通讯录优化——静态->动态

8.1 通讯录结构体优化

8.2 初始化函数的优化

8.3增加联系人的优化

8.4 释放通讯录的空间

九、完整代码 

test.c

contact.h

contact.c


实现一个通讯录,这里我们先来简单构思一下,通讯录中保存人的信息,分别有姓名,年龄,性别,电话,住址,假设我们通讯录中可以存放1000个人的信息。同时我们通讯录还要具备一些功能。包括;

①  增加联系人

②  删除指定联系人

③  修改指定联系人

④  查找指定联系人

⑤  显示所有联系人的信息

⑥  按照名字顺序进行排序

⑦  清空所有联系人

在写完之后,我们紧接着可以对通讯录进行优化,将静态通讯录改为动态通讯录。

一起跟着博主的思路来完成通讯录的实现吧!

        首先我们需要三个文件,分别是test.c——测试通讯录,contact.h——函数和类型的声明,contact.c——函数的实现,其次我们需要创建保存人信息的结构体。接下来我们开始慢代码实现吧!

一、创建联系人信息(结构体)

        为了保存联系人的各个信息,我们创建了一个结构体,放在头文件中,同时为了方便使用,对结构体重命名。

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

二、创建通讯录(结构体)

为了方便记录通讯录中现在的人数,创建一个结构体将联系人结构体和人数封装在一起。

//通讯录
typedef struct Contact
{PeoInfo data[100];int sz;
}Contact;

三、define定义常量

写到这里,我们发现如果以后想要更改通讯录的人数,或者名字的宽度,以及地址的宽度这些变量,要到代码中修改,很麻烦,我们可以通过define定义常量,这样使用或者更改的时候就会很方便,达到我们想要的效果。

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

四、打印通讯录菜单

因为每次使用至少使用一次,所以我们采用do—while循环来设计测试通讯录。

void menu()
{printf("*******************************\n");printf("********1.add      2.del*******\n");printf("********3.search   4.modify****\n");printf("********5.show     6.sort******\n");printf("*********    7.clear***********\n");printf("*********    0.exit ***********\n");printf("*******************************\n");
}
void test()
{int input = 0;do{menu();printf("请选择:> ");scanf("%d", &input);} while(input);
}

五、枚举菜单选项

为了代码美观,以及更方便的去识别代码的意思,我们可以采用自定义枚举的方式来实现功能选择。具体代码如下

enum Option
{Exit,//0   ——退出Add,//1    ——增加联系人Del,//2    ——删除指定联系人Search,//3 ——查找指定联系人信息Modify,//4 ——修改指定联系人信息Show,//5   ——显示通讯录中所有联系人Sort,//6   ——排序联系人Clear//7   ——清空所有联系人};

 这样就容易理解许多,效果如下所示:

void test()
{int input = 0;//定义通讯录Contact con;InitContact(&con);do{menu();//打印菜单printf("请选择:");scanf("%d", &input);switch (input){ case Add:AddContact(&con);break;case Del:DelContact(&con);break;case Search:SearchContact(&con);break;case Modify:ModifyContact(&con);break;case Show:ShowContact(&con);break;case Sort:SortContact(&con);break;case Clear:ClearContact(&con);break;case Exit:printf("退出通讯录\n");break;default:printf("选择错误,请重新选择\n");break;}} while (input);
}

六、初始化通讯录

当我们创建完通讯录之后,为了更好的实现后面的功能,最好初始化一下通讯录。

注意:在contact.h中声明,在contact.c中实现。

        这里博主使用memset来讲通讯录中的信息全部初始化为0,如果不想使用memset,也可以采用循环的形式来初始化。具体代码如下:

//初始化通讯录
void InitContact(Contact* pc)
{memset(pc->data, 0, sizeof(pc->data));pc->sz = 0;
}

七、实现通讯的的功能

注意:①以下函数的实行都是在contact.h中声明类型,然后在contact.v中实现

           ②在进入函数时,需要assert进行断言,防止传入空指针

           ③如果要进行的操作不需要更改通讯录的内容(例如:显示所有联系人)时,要用const修饰以下,保护通讯录内容。

7.1 增加加联系人

增加联系人我们首先需要判断通讯录里面的人数是否满了。没满才能继续进行操作

//增加联系人
void AddContact(Contact* pc)
{assert(pc);//断言,防止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("成功添加联系人");}

7.2 显示所有联系人的信息

当我们增加完联系人之后,我们想要看看是否成功添加,来看看通讯录中存在的联系人。

注意:我们打印的时候可以借助\t制表符来进行打印,这样打印出来会很整齐,很好看!

//显示所有联系人
void ShowContact(const Contact* pc)
{//断言assert(pc);//打印列标题printf("%-10s\t%-4s\t%-5s\t%-12s\t%-30s\n","姓名","年龄","性别","电话","地址");int i = 0;//打印数据for (i = 0; i < pc->sz; i++){printf("%-10s\t%-4d\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);}
}

具体效果如下图所示:

 7.3 单独查找人的函数

写到这里我们发现不管是删除联系人还是查找联系人以及修改联系人,都会经过查找这一步,所以单独写个查找的函数代码如下:

//只在本文件使用
static int FindName(const Contact* pc, char name[])
{int i = 0;for (i = 0; i < pc->sz; i++){if (strcmp(pc->data[i].name, name)==0){return i;}}return -1;
}

7.4 删除指定联系人

当我们写完单独查找人的函数后,这个删除指定联系人就会简单许多,在查找前仍然要检查一下通讯录是否为空,如果为空就没必要再继续下去了,先查找到指定联系人,看看是否存在,然后再删除,具体代码如下:

//删除指定联系人
void DelContact(Contact* pc)
{if (pc->sz == 0){printf("通讯录为空,无法删除\n");return;}char name[MAX_NAME]={0};assert(pc);//删除printf("请输入要删除人的名字:");scanf("%s", name);// 不管是删除联系人还是查找联系人以及修改联系人,都会经过查找这一步,所以单独写个查找的函数int del=FindName(pc, name);if (del == -1){printf("要删除的人不存在\n");return;}//删除所要删除的联系人int i = 0;for (i = del; i < pc->sz-1; i++){pc->data[i] = pc->data[i + 1];}//人数减一pc->sz--;printf("成功删除联系人\n");
}

7.5 查找指定联系人

直接调用单独查找人的函数即可,是不是很方便!如果查找的人不存在,那就直接跳出即可,如果找到,就答应查找的联系人,代码如下:

//查找指定联系人
void SearchContact(const Contact* pc)
{char name[MAX_NAME] = { 0 };assert(pc);printf("请输入要查找人的名字:");scanf("%s", name);int pos = FindName(pc, name);if (pos == -1){printf("要查找的人不存在\n");}else{printf("%-10s\t%-4s\t%-5s\t%-12s\t%-30s\n", "姓名", "年龄", "性别", "电话", "地址");printf("%-10s\t%-4d\t%-5s\t%-12s\t%-30s\n", pc->data[pos].name,pc->data[pos].age,pc->data[pos].sex,pc->data[pos].tele,pc->data[pos].addr);}
}

7.6 修改指定联系人

修改联系人很简单,这里就不多做解释啦,直接上代码!

//修改联系人
void ModifyContact(Contact* pc)
{char name[MAX_NAME] = { 0 };assert(pc);printf("请输入要修改联系人的姓名:");scanf("%s", name);int pos = FindName(pc, name);if (pos == -1){printf("要修改的联系人不存在\n");}else{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);}
}

7.7 按照名字顺序进行排序

这里博主就拿按照名字顺序进行排序,利用库函数qsort函数进行排序,具体qsort函数是什么,博主这里建议大家去查一查,了解一下,当然小编也准备单独写一篇博客来介绍qsort函数以及qsort的模拟实现,如果感兴趣,可以关注,期待小编更新哦。

int cmp_name(const void* p1, const void* p2)
{return strcmp(((PeoInfo*)p1)->name, ((PeoInfo*)p2)->name);
}
//排序联系人
void SortContact(Contact* pc)
{assert(pc);//就拿按照名字排序吧//利用qsort函数qsort(pc->data, pc->sz, sizeof((pc->data)[0]), cmp_name);//排序结束,输出通讯录//打印列标题printf("%-10s\t%-4s\t%-5s\t%-12s\t%-30s\n", "姓名", "年龄", "性别", "电话", "地址");int i = 0;//打印数据for (i = 0; i < pc->sz; i++){printf("%-10s\t%-4d\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);}
}

7.8  清空所有联系人

清空联系人也会很简单,就直接讲通讯录里面的sz人数置为0即可,具体代码如下

void ClearContact(Contact* pc)
{assert(pc);//其实清空联系人只需要把里面的人数清零即可int i = 0;printf("确定要清空所有联系人吗?确定请按1,按其余键返回\n");scanf("%d", &i);if (i == 1){pc->sz = 0;printf("清空联系人成功");}
}

八、通讯录优化——静态->动态

写到这里,其实简单的通讯录已经介绍完毕,但是我们这个通讯录其实可以进行优化的。

优化目标:

                ①通讯录空间不是固定的,大小可以调整的。

                ②默认能放三个人的信息,如果不够,就每次增加两个人的容量

8.1 通讯录结构体优化

因为这里的通讯录人数不是固定的了,所以我们首先想到的是优化通讯录这个结构。通讯录的空间是动态开辟的,由malloc开辟即可。

注意:①sz是记录当前放的有效元素的个数

            ②capacity是记录通讯录当前最大容量

#define DEFAULT_SZ 3  //起始容量
#define ADD_SZ 2    //每次需要增加的容量//动态版本//通讯录容量可以更改,不够时进行增加
typedef struct contact
{PeoInfo* data;//指向存放数据的空间int sz;//当前放的有效元素的个数int capacity;//通讯录当前最大容量
}Contact;

8.2 初始化函数的优化

初始化函数也不能是固定的100人全部初始化。而是应该最开始开辟三个人的空间。人数为0,容量为3。

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

8.3增加联系人的优化

这时动态版本的增加联系人就不存在满的问题了,而是先检查人数是否等于这里的最大容量的,如果等于,那就需要进行扩容了。(利用realloc函数)这里的好处就体现出来了,我们用多少空间,就开辟多少空间,每次只多开辟两个人的空间即可。

我们这里用int来接收增容的结果,如果增容成功,就返回1,增容失败就返回0,然后在进行判断,如果失败,就没必要继续往下走了。

//动态版本
void AddContact(Contact* pc)
{assert(pc);//断言,防止pc是空指针CheckCapacity(pc);if (0 == CheckCapacity(pc)){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");}
int CheckCapacity(Contact* pc)
{assert(pc);//判断通讯录是否满了if (pc->sz == pc->capacity){PeoInfo* ptr=(PeoInfo*)realloc(pc->data, (pc->capacity+ADD_SZ)*sizeof(PeoInfo));if (ptr == NULL){perror("CheckCapacity");return 0;}else{pc->data = ptr;pc->capacity += ADD_SZ;printf("增容成功\n");return 1;}}return 1;
}

8.4 释放通讯录的空间

因为这里的通讯录是动态开辟,所以当我们使用完之后要将开辟的内存释放掉,防止内存泄漏。

当然释放完空间,我们里面的信息也就没有了,这时要把人数置为0,容量变为3.

//因为通讯录是动态开辟的,所以使用完需要释放
void DestroyContact(Contact* pc)
{free(pc->data);pc->data = NULL;pc->capacity = 0;pc->sz = 0;
}

九、完整代码 

到这里,我们不管是简单的静态通讯录,还是动态的通讯录都实现完毕,代码博主这里放在一起来展示。

test.c

#define _CRT_SECURE_NO_WARNINGS 1#define _CRT_SECURE_NO_WARNINGS 1#include"contact.h"
void menu()
{printf("*******************************\n");printf("********1.add      2.del*******\n");printf("********3.search   4.modify****\n");printf("********5.show     6.sort******\n");printf("**********   7.clear***********\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:DelContact(&con);break;case Search:SearchContact(&con);break;case Modify:ModifyContact(&con);break;case Show:ShowContact(&con);break;case Sort:SortContact(&con);break;case Clear:ClearContact(&con);break;case Exit:DestroyContact(&con);printf("退出通讯录\n");break;default:printf("选择错误,请重新选择\n");break;}} while (input);
}
int main()
{test();return 0;
}

contact.h

#define _CRT_SECURE_NO_WARNINGS 1#pragma once#define MAX 100
#define MAX_NAME 20
#define MAX_SEX 5
#define MAX_TELE 12
#define MAX_ADDR 30#define DEFAULT_SZ 3
#define ADD_SZ 2#include<string.h>#include<stdio.h>#include<assert.h>#include<stdlib.h>//类型的声明enum Option
{Exit,//0Add,//1Del,//2Search,//3Modify,//4Show,//5Sort,//6Clear//7};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[MAX];
//	int sz;
//}Contact;//动态版本
//通讯录容量可以更改,不够时进行增加
typedef struct contact
{PeoInfo* data;//指向存放数据的空间int sz;//当前放的有效元素的个数int capacity;//通讯录当前最大容量
}Contact;//函数声明
//初始化通讯录函数
void InitContact(Contact* pc);//增加联系人信息
void AddContact(Contact* pc);//显示所有联系人的信息
void ShowContact(const Contact* pc);//删除指定联系人
void DelContact(Contact* pc);//查找指定联系人
void SearchContact(const Contact* pc);//修改联系人
void ModifyContact(Contact* pc);//排序联系人
void SortContact(Contact* pc);//清空联系人
void ClearContact(Contact* pc);//释放通讯录的空间
void DestroyContact(Contact* pc);

contact.c

#define _CRT_SECURE_NO_WARNINGS 1#define _CRT_SECURE_NO_WARNINGS 1
#include"contact.h"
//函数的实现//静态版本
初始化通讯录
//void InitContact(Contact* pc)
//{
//	memset(pc->data, 0, sizeof(pc->data));
//	pc->sz = 0;
//}//动态版本
void InitContact(Contact* pc)
{assert(pc);pc->data = (PeoInfo*)malloc(DEFAULT_SZ * sizeof(PeoInfo));if (pc->data == NULL){perror("InitContact");return;}pc->sz = 0;pc->capacity = DEFAULT_SZ;
}//静态版本
//增加联系人
//void AddContact(Contact* pc)
//{
//	assert(pc);//断言,防止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("成功添加联系人");
//
//}//动态版本
int CheckCapacity(Contact* pc)
{assert(pc);//判断通讯录是否满了if (pc->sz == pc->capacity){PeoInfo* ptr=(PeoInfo*)realloc(pc->data, (pc->capacity+ADD_SZ)*sizeof(PeoInfo));if (ptr == NULL){perror("CheckCapacity");return 0;}else{pc->data = ptr;pc->capacity += ADD_SZ;printf("增容成功\n");return 1;}}return 1;
}
void AddContact(Contact* pc)
{assert(pc);//断言,防止pc是空指针CheckCapacity(pc);if (0 == CheckCapacity(pc)){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 ShowContact(const Contact* pc)
{//断言assert(pc);//打印列标题printf("%-10s\t%-4s\t%-5s\t%-12s\t%-30s\n", "姓名", "年龄", "性别", "电话", "地址");int i = 0;//打印数据for (i = 0; i < pc->sz; i++){printf("%-10s\t%-4d\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);}
}//只在本文件使用
static int FindName(const Contact* pc, char name[])
{int i = 0;for (i = 0; i < pc->sz; i++){if (strcmp(pc->data[i].name, name) == 0){return i;}}return -1;
}//删除指定联系人
void DelContact(Contact* pc)
{if (pc->sz == 0){printf("通讯录为空,无法删除\n");return;}char name[MAX_NAME] = { 0 };assert(pc);//删除printf("请输入要删除人的名字:");scanf("%s", name);找到要删除的人//int i = 0;//int del = 0;//int flag = 0;//for (i = 0; i < pc->sz; i++)//{//	if (strcmp(pc->data[i].name, name)==0)//	{//		del = i;//		flag = 1;//找到了//		break;//	}//}//if (flag == 0)//{//	printf("要删除的人不存在\n");//	return;//}// 不管是删除联系人还是查找联系人以及修改联系人,都会经过查找这一步,所以单独写个查找的函数int del = FindName(pc, name);if (del == -1){printf("要删除的人不存在\n");return;}//删除所要删除的联系人int i = 0;for (i = del; i < pc->sz - 1; i++){pc->data[i] = pc->data[i + 1];}//人数减一pc->sz--;printf("成功删除联系人\n");
}//查找指定联系人
void SearchContact(const Contact* pc)
{char name[MAX_NAME] = { 0 };assert(pc);printf("请输入要查找人的名字:");scanf("%s", name);int pos = FindName(pc, name);if (pos == -1){printf("要查找的人不存在\n");}else{printf("%-10s\t%-4s\t%-5s\t%-12s\t%-30s\n", "姓名", "年龄", "性别", "电话", "地址");printf("%-10s\t%-4d\t%-5s\t%-12s\t%-30s\n", pc->data[pos].name,pc->data[pos].age,pc->data[pos].sex,pc->data[pos].tele,pc->data[pos].addr);}
}//修改联系人
void ModifyContact(Contact* pc)
{char name[MAX_NAME] = { 0 };assert(pc);printf("请输入要修改联系人的姓名:");scanf("%s", name);int pos = FindName(pc, name);if (pos == -1){printf("要修改的联系人不存在\n");}else{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);}
}int cmp_name(const void* p1, const void* p2)
{return strcmp(((PeoInfo*)p1)->name, ((PeoInfo*)p2)->name);
}
//排序联系人
void SortContact(Contact* pc)
{assert(pc);//就拿按照名字排序吧//利用qsort函数qsort(pc->data, pc->sz, sizeof((pc->data)[0]), cmp_name);//排序结束,输出通讯录//打印列标题printf("%-10s\t%-4s\t%-5s\t%-12s\t%-30s\n", "姓名", "年龄", "性别", "电话", "地址");int i = 0;//打印数据for (i = 0; i < pc->sz; i++){printf("%-10s\t%-4d\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 ClearContact(Contact* pc)
{assert(pc);//其实清空联系人只需要把里面的人数清零即可int i = 0;printf("确定要清空所有联系人吗?确定请按1,按其余键返回\n");scanf("%d", &i);if (i == 1){pc->sz = 0;printf("清空联系人成功");}
}//因为通讯录是动态开辟的,所以使用完需要释放
void DestroyContact(Contact* pc)
{free(pc->data);pc->data = NULL;pc->capacity = 0;pc->sz = 0;
}

好啦,到这里,今天的博主给大家带来的通讯录到这里就结束啦,如果哪里有问题,欢迎在评论区留言。如果觉得小编写的还不错的,那么可以一键三连哦,您的关注点赞和收藏是对小编最大的鼓励。谢谢大家!!!

 

相关文章:

通讯录的实现(超详细)——C语言(进阶)

目录 一、创建联系人信息&#xff08;结构体&#xff09; 二、创建通讯录&#xff08;结构体&#xff09; 三、define定义常量 四、打印通讯录菜单 五、枚举菜单选项 六、初始化通讯录 七、实现通讯的的功能 7.1 增加加联系人 7.2 显示所有联系人的信息 ​7.3 单独查…...

3D 渲染技巧-如何创建高质量写实渲染?

掌握创建高质量建筑渲染和任何 3D 渲染的艺术是一项复杂且需要技巧的工作&#xff0c;通常需要多年的经验和实践。实现逼真的结果需要仔细考虑众多因素&#xff0c;并避免可能导致缺乏真实性的假渲染效果的常见错误。 避免常见错误 - 提升渲染游戏的技巧 在追求创建真正逼真的…...

fastadmin采坑之获取当前登录admin用户的信息

在controller层里想要获取当前登录admin用户的信息 print_r($this->auth->getUserInfo());但是有个问题 我在fa_admin表中添加了新的字段&#xff0c;这个方法获取不到新字段的数值&#xff0c;具体也没有去研究估计跟方法有关 然后我直接用模型去获取数据&#xff0c;简…...

【Spring AOP + 自定义注解 + 动态数据源 实现主从库切换读写分离】—— 案例实战

&#x1f4a7; S p r i n g A O P 主从数据源切换 读写分离 自定义注解案例实战&#xff01; \color{#FF1493}{Spring AOP 主从数据源切换 读写分离 自定义注解 案例实战&#xff01;} SpringAOP主从数据源切换读写分离自定义注解案例实战&#xff01;&#x1f4a7; …...

【LeetCode每日一题合集】2023.7.24-2023.7.30

文章目录 771. 宝石与石头代码1——暴力代码2——位运算集合⭐&#xff08;英文字母的long集合表示&#xff09; 2208. 将数组和减半的最少操作次数&#xff08;贪心 优先队列&#xff09;2569. 更新数组后处理求和查询⭐⭐⭐⭐⭐&#xff08;线段树&#xff09;TODO2500. 删除…...

《吐血整理》进阶系列教程-拿捏Fiddler抓包教程(14)-Fiddler断点(breakpoints)实战,篡改或伪造数据

1.简介 上一篇主要就讲解和分享Fiddler断点的理论和操作&#xff0c;今天宏哥就用具体例子&#xff0c;将上一篇中的理论知识实践一下。而且在实际测试过程中&#xff0c;有时候需要修改请求或响应数据&#xff0c;或者直接模拟服务器响应&#xff0c;此时可以使用fiddler进行…...

ELK + Fliebeat + Kafka日志系统

参考&#xff1a; ELKFilebeatKafka分布式日志管理平台搭建_51CTO博客_elk 搭建 ELK 日志分析系统概述及部署&#xff08;上&#xff09;-阿里云开发者社区 ELK是三个开源软件的缩写&#xff0c;分别表示&#xff1a;Elasticsearch , Logstash, Kibana , 它们都是开源软件。…...

Scaling Instruction-Finetuned Language Models

Paper name Scaling Instruction-Finetuned Language Models Paper Reading Note Paper URL: https://arxiv.org/pdf/2210.11416.pdf TL;DR 2022 年谷歌出的文章&#xff0c;对指令微调的影响因素进行分析&#xff0c;提出了一些提升指令微调效果的方案。与该文章一起出品…...

rust 闭包函数

函数有自己的类型&#xff0c;可以像使用基础类型一样使用函数&#xff0c;包括将函数保存在变量中、保存在 vec 中、声明在结构体成员字段中。闭包函数也是函数&#xff0c;也有自己的类型定义。不过&#xff0c;函数实际上是指针类型&#xff0c;在 rust 所有权中属于借用的关…...

MySQL 实现分库和分表的备份 2023.7.29

1、分库备份 [rootlocalhost mysql-backup]# cat db_bak.sh #!/bin/bash k_userroot bak_password123456 bak_path/root/mysql-backup/ bak_cmd"-u$bak_user -p$bak_password" exc_db"Database|information_schema|mysql|performance_schema|sys" dbname…...

20230728----重返学习-跨域-模块化-webpack初步

day-122-one-hundred-and-twenty-two-20230728-跨域-模块化-webpack初步 跨域 跨域 为什么要跨域&#xff1f; 浏览器为了安全&#xff0c;不能让我们的html文件可以随意引用别的服务器中的文件&#xff0c;只允许我们的html或js文件中&#xff0c;请求我们自己服务器。这个…...

[SQL挖掘机] - 多表连接: union all

介绍: sql中的union all是用于合并两个或多个select语句的结果集的操作符。与union不同的是&#xff0c;union all不会自动去除重复的行&#xff0c;它会简单地将多个查询的结果集合并在一起&#xff0c;包括重复的行。 用法: union all的基本语法如下&#xff1a; select_…...

TypeError: run() got an unexpected keyword argument ‘hide_label‘ yolov5最新版本报错

报错展示 解决方法 把detect.py中的如上部分的 --hide-label改为 --hide-labels&#xff0c;成功解决....

什么是Java中的集成测试?

Java中的集成测试&#xff08;Integration Test&#xff09;是一种测试方法&#xff0c;用于测试多个模块或组件之间的交互和集成。在Java中&#xff0c;集成测试通常使用单元测试框架&#xff08;如JUnit&#xff09;编写和运行。 对于初学者来说&#xff0c;集成测试可能有些…...

打卡力扣题目二

#左耳听风 ARST 打卡活动重启# 目录 一、问题 二、 解题方法一 三、enumerate函数介绍 关于 ARTS 的释义 —— 每周完成一个 ARTS&#xff1a; ● Algorithm: 每周至少做一个 LeetCode 的算法题 ● Review: 阅读并点评至少一篇英文技术文章 ● Tips: 学习至少一个技术技巧 …...

【Qt】QML-02:QQuickView用法

1、先看demo QtCreator自动生成的工程是使用QQmlApplicationEngine来加载qml文件&#xff0c;下面的demo将使用QQuickView来加载qml文件 #include <QGuiApplication> #include <QtQuick/QQuickView>int main(int argc, char *argv[]) {QGuiApplication app(argc,…...

【IDEA】idea不自动生成target

文章目录 1. 不生成target2. 仅部分文件不生成target2.1. 一般原因就是资源没有设置2.2. 配置编译src/main/java文件夹下的资源文件2.3. 清理缓存&#xff08;王炸&#xff09; 3. 参考资料 本文描述idea不生成target的几种情况以及处理方法 1. 不生成target 像下图这样根本就…...

从官网认识 JDK,JRE,JVM 三者的关系

点击下方关注我&#xff0c;然后右上角点击...“设为星标”&#xff0c;就能第一时间收到更新推送啦~~~ JVM 是一些大厂面试必问点&#xff0c;要想解决 OOM、性能调优方面的问题&#xff0c;掌握 JVM 知识必不可少&#xff0c;从今天开始&#xff0c;将为大家介绍 JVM 的常用知…...

python 将pdf文件转图片

有小伙伴问了怎么将 pdf文件转图片的问题&#xff0c;我百度了一波儿&#xff0c;搞了以下python代码给他封装成exe工具了。 中途打包踩了个坑&#xff0c;python进程池的问题&#xff0c;本地运行没啥问题&#xff0c;打包好的exe文件双击就会使电脑内存爆破卡死&#xff0c;…...

js原型以及原型链

目录 原型隐式原型显式原型constructornew操作符 重写原型对象原型链继承原型链继承借用构造函数继承组合构造继承 原型继承寄生继承组合寄生继承 原型继承关系 原型 在JavaScript中&#xff0c;每个对象都有一个内置属性[[prototype]]&#xff0c;这个属性指向一个另一个对象…...

Java面向对象编程实战详解(图书管理系统示例)

文章目录 面向编程概念图书管理系统示例需求分析设计阶段编码实现创建目录结构Book类的编码BookList类的编码User类的编码AdminUser类的编码NormalUser类的编码启动类的编写具体的操作实现IOperation接口新增图书的实现借阅图书的实现删除图书的实现显示图书的实现查找图书的实…...

ubuntu设置主机ip

ubuntu 设置ip sudo dhclient -r enp67s0 # 是你的网卡&#xff0c;可以通过ifconfig 查&#xff0c;比如enp0 sudo ifconfig enp67s0 192.168.1.114 netmask 255.255.255.0 Ubuntu显示有线网已连接但无法上网&#xff0c;已经确认网口、交换机&#xff08;路由器&#xff…...

CleanMyMac X4.14.1中文版如何清理 Mac系统?CleanMyMac 真的能断网激活吗?

CleanMyMac X4.14.1中文版如何清理 Mac系统&#xff1f;Mac系统在使用过程中都会产生大量系统垃圾&#xff0c;如不需要的系统语言安装包&#xff0c;视频网站缓存文件&#xff0c;mac软件卸载残留的注册表等。 随着时间推移&#xff0c;mac系统垃圾就会越来越多&#xff0c;电…...

详细介绍 React 中如何使用 redux

在使用之前要先了解它的配套插件&#xff1a; 在React中使用redux&#xff0c;官方要求安装其他插件 Redux Toolkit 和 react-redux Redux Toolkit&#xff1a;它是一个官方推荐的工具集&#xff0c;旨在简化 Redux 的使用和管理。Redux Toolkit 提供了一些提高开发效率的工具…...

VLOOKUP多条件查询

LOOKUP(1,0/((A3:A15A18)*(C3:C15C18)),F3:F15)...

分页插件Mybatis

<plugins><!-- com.github.pagehelper为PageHelper类所在包名 --><plugin interceptor"com.github.pagehelper.PageInterceptor"><!-- 配置方言:告诉分页插件使用底层数据库是什么--><property name"helperDialect" value"…...

AXI协议之AXILite开发设计(四)—Block Design使用

微信公众号上线&#xff0c;搜索公众号小灰灰的FPGA,关注可获取相关源码&#xff0c;定期更新有关FPGA的项目以及开源项目源码&#xff0c;包括但不限于各类检测芯片驱动、低速接口驱动、高速接口驱动、数据信号处理、图像处理以及AXI总线等 2、AXI interconnect互联组件的使用…...

音视频——帧内预测

H264编码(帧内预测) 在帧内预测模式中&#xff0c;预测块P是基于已编码重建块和当前块形成的。对亮度像素而言&#xff0c;P块用于44子块或者1616宏块的相关操作。44亮度子块有9种可选预测模式&#xff0c;独立预测每一个44亮度子块&#xff0c;适用于带有大量细节的图像编码&…...

2.uni-app项目文件

uni-app像是vue与微信小程序的合体&#xff0c;使用 uni-ui项目 模板创建的项目文件如下 目录 1 pages 2 pages.json 3 App.vue 4 index.html 5 static 6 uni_modules 7 manifest.json 8 main.js 9 uni.scss 1 pages 这个是放页面的&#xff0c;默认里面有…...

JavaScript学习 -- 对称加密算法DES

在现代的互联网时代&#xff0c;数据安全性备受关注。为了保护敏感数据的机密性&#xff0c;对称加密算法是一种常用的方法。在JavaScript中&#xff0c;DES&#xff08;Data Encryption Standard&#xff09;是一种常用的对称加密算法。本篇博客将为您展示如何在JavaScript中使…...

二级域名可以做网站/网络营销怎么推广

微信 php 自定义菜单我申请了一个微信公众平台的测试账号&#xff0c;之前已经通过验证&#xff0c;关注后用我的微信号向测试账号发消息可以得到测试账号的正确响应&#xff0c;我现在想实现微信的自定义菜单&#xff0c;下面用***代替了我测试账号的appid和secret&#xff0c…...

做网站买主机还是服务器/还有哪些平台能免费营销产品

上证综合指数作为A股市场第一条股票指数&#xff0c;将于7月22日迎来重大优化。修订后的编制方案将剔除风险警示股票、延长新股计入时间&#xff0c;并计入科创板上市证券。上证综合指数等以样本股的发行股本数为权数进行加权计算&#xff0c;计算公式为&#xff1a; 报告期指…...

建立自己公司网站的方法/合肥网络科技有限公司

今天最多人问的莫过于这个问题了。“初级会计师今天开始打印准考证了吗&#xff1f;”一开始我挺懵逼的&#xff0c;初级会计师考试时间出来了吗&#xff1f;为什么官网没消息的&#xff1f;不对啊&#xff1f;我登录了官网按了也带打印不了啊&#xff1f;后来我才知道&#xf…...

零基础学室内设计/seo网络营销的技术

1、ContextMenuStrip--右键菜单 可以绑定在任何一个控件上&#xff0c;添加操作快捷键&#xff0c;并可以设置多层 每行相当于一个按钮&#xff0c;输入-可添加分割线 2、MenuStrip--菜单 优先级最高&#xff0c;一定会出现在窗体最上面 设置快捷键&#xff1a;选中菜单项--右键…...

wordpress管理账户/seo网站编辑优化招聘

问题描述第一分钟&#xff0c;上帝说&#xff1a;要有题。于是就有了L&#xff0c;Y&#xff0c;M&#xff0c;C第二分钟&#xff0c;LYC说&#xff1a;要有向量。于是就有了长度为n写满随机整数的向量第三分钟&#xff0c;YUHCH说&#xff1a;要有查询。于是就有了Q个查询&…...

国外域名注册哪个网站好/重庆排名优化整站优化

展开全部您好&#xff0c;如果您经常被骚扰电话困32313133353236313431303231363533e4b893e5b19e31333335313166扰&#xff0c;可以尝试安装腾讯手机管家进行骚扰电话拦截与举报喔。管家除了可以拦截骚扰电话外&#xff0c;还可以拦截垃圾短信&#xff0c;将讨厌的号码设为黑名…...