通讯录的实现(超详细)——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;
}

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

 

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

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

相关文章

《MySQL45讲》笔记—索引

索引 索引是为了提高数据查询效率&#xff0c;就像书的目录一样。如下图&#xff0c;索引和数据就是位于存储引擎中&#xff1a; 索引常见模型 哈希表 以键值对存储的数据结构。适用于只有等值查询的场景。 有序数组 在等值查询和范围查询场景中性能都特别优秀。但是有…

开放自动化软件的硬件平台

自动化行业的产品主要以嵌入式系统为主&#xff0c;历来对产品硬件的可靠性和性能都提出很高的要求。最典型的产品要数PLC。PLC 要求满足体积小&#xff0c;实时性&#xff0c;可靠性&#xff0c;可扩展性强&#xff0c;环境要求高等特点。它们通常采用工业级高性能嵌入式SoC 实…

Vue 3:玩一下web前端技术(三)

前言 本章内容为VUE工作过程与相关使用讨论。 上一篇文章地址&#xff1a; Vue 3&#xff1a;玩一下web前端技术&#xff08;二&#xff09;_Lion King的博客-CSDN博客 下一篇文章地址&#xff1a; Vue 3&#xff1a;玩一下web前端技术&#xff08;四&#xff09;_Lion Ki…

SpringBoot 注解

SpringBoot SpringBoot&#xff08;SpringBootApplication&#xff09;问题引入我们的工程在引入spring-boot-starter-web依赖的时候&#xff0c;为什么没有指定版本&#xff08;版本锁定&#xff09;spring-boot-starter-web是个啥&#xff0c;为什么引入了它之后&#xff0c;…

【业务功能篇59】Springboot + Spring Security 权限管理 【下篇】

UserDetails接口定义了以下方法&#xff1a; getAuthorities(): 返回用户被授予的权限集合。这个方法返回的是一个集合类型&#xff0c;其中每个元素都是一个GrantedAuthority对象&#xff0c;表示用户被授予的权限。getPassword(): 返回用户的密码。这个方法返回的是一个字符…

springboot编写mp4视频播放接口

简单粗暴方式 直接读取指定文件&#xff0c;用文件流读取视频文件&#xff0c;输出到响应中 GetMapping("/display1/{fileName}")public void displayMp41(HttpServletRequest request, HttpServletResponse response,PathVariable("fileName") String fi…

stm32通过ESP8266接入原子云

1. ESP8266模块需要烧录原子云固件&#xff0c;此原子云固件和正常的ESP8266固件相比添加了ATATKCLDSTA 和 ATATKCLDCLS 这两条指令&#xff1a; 2. 原子云账号注册及设备建立 设备管理-新增设备-ESP8266 新建设备后新建分组&#xff0c;将设备加入到此分组中&#xff1a; 至此…

ICASSP 2023 | Cough Detection Using Millimeter-Wave FMCW Radar

原文链接&#xff1a;https://mp.weixin.qq.com/s?__bizMzg4MjgxMjgyMg&mid2247486540&idx1&sn6ebd9f58e9f08a369904f9c48e12d136&chksmcf51beb5f82637a3c65cf6fa53e8aa136021e35f63a58fdd7154fc486a285ecde8b8521fa499#rd ICASSP 2023 | Cough Detection Usi…

SwipeDelMenuLayout失效:Could not find SwipeDelMenuLayout-V1.3.0.jar

一、问题描述 最近在工作上的项目中接触到SwipeDelMenuLayout这个第三方Android开发库&#xff0c;然后我就根据网上的教程进行配置。这里先说一下我的开发环境&#xff1a;Android Studio版本是android-studio-2020.3.1.24-windows&#xff0c;gradle版本是7.0.2。 首先是在se…

RWEQ模型——土壤风蚀模拟

详情点击链接&#xff1a;基于“RWEQ”集成技术在土壤风蚀模拟与风蚀模数估算、变化归因分析中的实践应用及SCI论文撰写 前沿 土壤风蚀是一个全球性的环境问题。中国是世界上受土壤风蚀危害最严重的国家之一&#xff0c;土壤风蚀是中国干旱、半干旱及部分湿润地区土地荒漠化的…

【Docker】Docker应用部署之Docker容器安装Tomcat

目录 一、搜索镜像 二、拉取镜像 三、创建容器 四、测试使用 一、搜索镜像 docker search tomcat 二、拉取镜像 docker pull tomcat:版本 三、创建容器 首先在宿主机创建数据卷的目录 mkdir /root/tomcat # 创建目录 cd /root/tomcat # 进入目录 docker run -id -…

前端框架学习-Vue(二)

最近在学习Vue框架&#xff0c;Vue中的内容很多。相当于把之前后端的MVC&#xff0c;V层转移到前端来编写和部署。下面是学习Vue时的大纲。 Vue生命周期是Vue应用的生命周期Vue脚手架&#xff0c;即vue-cli&#xff0c;使用node.js 来创建和启动vue项目Vue组件知识&#xff0c;…

RS485/RS232自由转ETHERNET/IP网关profinet和ethernet区别

你是否曾经遇到过这样的问题&#xff1a;如何将ETHERNET/IP网络和RS485/RS232总线连接起来呢&#xff1f;捷米的JM-EIP-RS485/232通讯网关&#xff0c;自主研发的ETHERNET/IP从站功能&#xff0c;完美解决了这个难题。这款网关不仅可以将ETHERNET/IP网络和RS485/RS232总线连接起…

Zynq-Linux移植学习笔记之62- PL挂载复旦微flash

1、背景介绍 现在为了全国产化需要&#xff0c;之前所有的进口flash全部要换成国产flash 2、复旦微flash型号 其中EFM25QU256和EFM25QL256对标winbond的w25q256 nor flash 3、FPGA设置 复旦微flash只支持单线模式&#xff0c;当使用PL侧的IP核访问时&#xff0c;需要设置模式…

【系统架构】分布式系统架构设计

1 分布式系统是什么 分布式系统是指由多个计算机节点组成的一个系统&#xff0c;这些节点通过网络互相连接&#xff0c;并协同工作完成某个任务。 与单个计算机相比&#xff0c;分布式系统具有更高的可扩展性、可靠性和性能等优势&#xff0c;因此广泛应用于大规模数据处理、高…

IDEA代码自动格式化工具

1.自动import 在IDEA中&#xff0c;打开 IDEA 的设置&#xff0c;找到 Editor -> General -> Auto Import。勾选上 Add unambiguous imports on the flyOptimize imports on the fly (for current project) 2.gitee 提交格式化 设置方法如下: 1.打开设置 2.找到版本…

KMP算法总结

KMP算法总结 BF算法引导BF算法步骤&#xff08;图片演示&#xff09;代码演示 KMP算法推next数组代码演示 BF算法引导 BF算法是一个暴力的字符串匹配算法&#xff0c;时间复杂度是o&#xff08;m*n&#xff09; 假设主串和子串分别为 我们想要找到子串在主串的位置 BF算法核…

Spring Boot集成Swagger3.0,Knife4j导出文档

文章目录 Spring Boot集成Swagger3.0,Knife4j导出文档效果展示如何使用简要说明添加依赖添加配置类测试接口token配置位置 官网 说明情况 demo Spring Boot集成Swagger3.0,Knife4j导出文档 效果展示 如何使用 简要说明 Knife4j的前身是swagger-bootstrap-ui,前身swagger-boo…

Github-Copilot初体验-Pycharm插件的安装与测试

引言&#xff1a; 80%代码秒生成&#xff01;AI神器Copilot大升级 最近copilot又在众多独角兽公司的合力下&#xff0c;取得了重大升级。GitHub Copilot发布还不到两年&#xff0c; 就已经为100多万的开发者&#xff0c;编写了46%的代码&#xff0c;并提高了55%的编码速度。 …

springboot整合myabtis+mysql

一、pom.xml <!--mysql驱动包--><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId></dependency><!--springboot与JDBC整合包--><dependency><groupId>org.springframework.b…