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

C语言小程序:通讯录(静态版)

哈喽各位老铁们,今天给大家带来一期通讯录的静态版本的实现,何为静态版本后面会做解释,话不多说,直接开始!
关于通讯录,其实也就是类似于我们手机上的通讯录一样,有着各种各样的功能,小编来带大家实现一部分功能就好啦(1.添加联系人 2. 删除指定联系人 3.查找指定联系人 4.修改指定联系人 5.显示全部联系人 6.排序通讯录 7.清空通讯录)要实现这些功能,首先得要有一个可以存放联系人的一块空间,而要存放的联系人的个人信息有:名字、性别、年龄、电话、家庭地址。这些个人信息类型不同,大小也不同,那该如何去存放,如何查找,又该如何去修改?我们一步一步来通过代码的方式实现这些功能

1.文件的划分

在前面发布的博客中就提到过划分文件进行编写,在之前的三子棋、扫雷的代码中就是通过划分文件,每一个文件实现相对应的功能,互不干扰,那么通讯录也要使用同样的方法

头文件:Contact.h

在头文件里面主要实现函数的声明,变量的定义、头文件的包含

源文件:Contact.c

在这个源文件里面实现通讯录的实现模块

源文件:test.c

这个源文件里面实现测试通讯录相关的功能

2.通讯录

实现一个通讯录:
1.这个通讯录可以存放100个人的信息
2.每个人的信息:
名字、性别、年龄、电话、地址
3.通讯录所包含的功能
添加联系人、删除联系人、查找联系人、修改联系人、显示通讯录、排序通讯录、清空通讯录

首先我们先搭出通讯录的基本框架:

头文件:Contact.h

//头文件的包含#include <stdio.h>

源文件:test.c

#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   *****    0.Exit   ****\n");printf("**************************************\n");
}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 7://清空break;case 0:printf("退出通讯录!\n");break;default:printf("选择错误,请重新选择:>\n");break;}} while (input);return 0;
}

但是如果这样字写,在代码可读性不高,为什么呢?当代码走到switch case 语句中,这里的case1、case2...里面的1、2..都代表什么呢?就得返回到最上面重新查看,因此这里需要完善一下,我们可以使用枚举,将我们选择的全部可能型都一一列举出来,然后进行选择,就比较方便。

优化代码:

enum Option
{EXIT,ADD,DEL,SEARCH,MODIFY,SHOW,SORT,CLEAR
};
//枚举的可能取值默认是从0开始,在这里刚好对应菜单里面的选项
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 CLEAR://清空break;case EXIT:printf("退出通讯录!\n");break;default:printf("选择错误,请重新选择:>\n");break;}} while (input);return 0;
}

基本框架搭建好了之后,就得有一个块空间来存放我们的联系人了,而联系人的信息又有多种,因此就需要一个结构体来存放联系人的信息,这里还存在一个问题,我们存放的联系人从哪里开始存放呢?所以我们还需要一个变量来确定联系人该存放在哪里,而且每当我们存放一个联系人,这个变量就要+1,以便下一个联系人存放在上一个联系人的后面。

注:如果我们将这个结构体创建在源文件中,就得在两个源文件中都要创建,因此为了节省空间,可以直接将结构体变量创建在头文件中

头文件:Contact.h

//表示一个联系人的各种信息
typedef struct PeoInfo
{char name[20];int age;char sex[5];char tele[12];char addr[20];
}PeoInfo;//通讯录
typedef struct Contact
{PeoInfo data[100];   //用来存放100个人的信息int sz;              //记录通讯录中有效信息的个数
}Contact;
如果这样子写还是有一个弊端,如果后期要修改通讯录中存放联系人的个数和每一个联系人信息中存放的大小,所有有关的数组都得一一修改,因此我们可以直接用#define来定义大小

代码优化:

//大小的定义
#define MAX 100
#define MAX_NAME 20
#define MAX_SEX 5
#define MAX_TELE 12
#define MAX_ADDR 20//表示一个联系人的各种信息
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];   //用来存放100个人的信息int sz;              //记录通讯录中有效信息的个数
}Contact;

这样子写在后期需要修改的时候就比较方便


存放联系人的空间也搭建好了,但是创建好的空间里面刚刚开始放的是什么东西呢?我们也不知道,因此我们先得给通讯录进行初始化,让里面一个联系人也没有,让标记的变量也变为0

2.1初始化通讯录

初始化通讯录我们分装一个函数:InitContact

源文件: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 CLEAR://清空break;case EXIT:printf("退出通讯录!\n");break;default:printf("选择错误,请重新选择:>\n");break;}} while (input);return 0;
}

头文件Contact.h

#include <string.h>
//函数的声明
//初始化通讯录
void InitContact(Contact* pc);

源文件:Contact.c

//初始化通讯录
void InitContact(Contact* pc)
{pc->sz = 0;memset(pc->data, 0, sizeof(pc->data));//memset函数在使用时要包含头文件<string.h>
}

2.2添加联系人

初始化好通讯录的内容之后,接下来就到了我们进行通讯录功能的实现了,首先我们实现添加联系人功能,要添加联系人,我们要确定sz的大小,如果sz等于MAX了,那不就证明通讯录以及满了嘛,就再不能添加联系人了,只有sz小于MAX的时候才可以添加联系人

源文件:test.c

case ADD://添加联系人printf("添加联系人\n");AddContact(&con); //传址调用break;

头文件:Contact.h

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

源文件:Contact.c

//添加联系人
void AddContact(Contact* 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++;  //每一次添加完之后sz都要++printf("添加成功\n");
}

2.3展示通讯录

要展示通讯录,可以先打印一行标题,有助于展示,打印整个通讯录就可以使用循环,设置一个循环,循环条件只要小于sz的大小就可以

源文件:test.c

case SHOW://展示ShowContact(&con);//显示通讯录不需要修改通讯录其实传值调用也可以,但是为了节省空间使用传值调用break;

头文件:Contact.h

//显示通讯录
void ShowContact(Contact* pc);

源文件:Contact.c

//显示通讯录
void ShowContact(Contact* pc)
{//先打印标题printf("%-10s %-2d %-5s %-10s %-15s\n", "名字", "年龄", "性别", "电话", "地址");int i = 0;for (i = 0; i < pc->sz; i++){printf("%-10s %-2d %-5s %-10s %-15s\n", pc->data[i].name, pc->data[i].age, pc->data[i].sex, pc->data[i].tele, pc->data[i].addr);}
}

2.4删除联系人

要删除联系人,首先得判断这个通讯录里面有没有联系人呀,所以要先判断sz是否为0,如果为0就证明没有联系人,判断完之后,需要删除联系人,那么首先得找到所想删除的联系人的位置,然后将这个位置记录下来,通过下标的形式访问,然后进行删除,这里还要注意,如果找完了整个通讯录,没有找到与之匹配的名字,那么就没有这个人,在删除的时候就是将记录的那个位置上的人,用后面一个人的信息进行覆盖,依次类推,然后整个通讯录的总人数减1就行了

源文件:test.c

case DEL://删除联系人printf("删除联系人\n");DelContact(&con);

头文件:Contact.h

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

源文件:Contact.c

//删除联系人
void DelContact(Contact* pc)
{char name[MAX_NAME] = { 0 };//判断通讯录是否为空if (0 == pc->sz){printf("通讯录为空,无法删除!\n");return;}printf("请输入你要删除联系人的姓名:>");scanf("%s", name);int i = 0;int pos = 0;for (i = 0; i < pc->sz; i++){//找到所要删除的联系人所在的位置if (0 == strcmp(pc->data[i].name, name)){pos = i;break;}}if (i == pc->sz){printf("找不到所要删除的联系人\n");return;}//进行删除for (i = pos; i < pc->sz - 1; i++) //判断条件这里所要交换的比总数少一个{pc->data[i] = pc->data[i + 1];}//删除完之后sz减一pc->sz--;printf("删除成功\n");
}

2.5查找联系人

查找联系人和删除练习人的基本步骤一样,先判断是否为空通讯录,然后进行查找,记录位置,然后打印

源文件:test.c

case SEARCH://查找联系人printf("查找联系人\n");SearchContact(&con);break;

头文件:Contact.h

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

源文件:Contact.c

//查找联系人
void SearchContact(Contact* pc)
{char name[MAX_NAME] = { 0 };if (pc->sz == 0){printf("通讯录为空,查找不到!");return;}printf("请输入你要查找联系人的姓名:>");scanf("%s", name);int i = 0;int pos = 0;for (i = 0; i < pc->sz; i++){//找到所要查找的联系人所在的位置if (0 == strcmp(pc->data[i].name, name)){pos = i;break;}}if (i == pc->sz){printf("找不到所要查找的联系人\n");return;}//打印导航栏printf("%-10s %-4s %-5s %-12s %-30s\n", "姓名", "年龄", "性别", "电话", "地址");//打印数据printf("%-10s %-4d %-5s %-12s %-30s\n",pc->data[pos].name,pc->data[pos].age,pc->data[pos].sex,pc->data[pos].tele,pc->data[pos].addr);
}

写到这里,我们不难发现这个查找联系人的过程重复了两次,在删除联系人和查找的时候都出现了,因此我们可以简化一下代码,直接将查找的过程分装一个查找函数,然后在使用的时候代码就不显得那么冗余,每次使用查找就直接调用这个函数

代码优化:

static int FindByName(const Contact* pc, char name[]) //使用static修饰,        //只在本源文件中使用
{int i = 0;int pos = 0;for (i = 0; i < pc->sz; i++){//找到所要删除的联系人所在的位置if (0 == strcmp(pc->data[i].name, name)){return i;}}return -1;
}//删除联系人
void DelContact(Contact* pc)
{char name[MAX_NAME] = { 0 };//判断通讯录是否为空if (0 == pc->sz){printf("通讯录为空,无法删除!\n");return;}printf("请输入你要删除联系人的姓名:>");scanf("%s", name);int pos = FindByName(pc, name);int i = 0;if (pos == -1){printf("找不到所要删除的联系人\n");return;}//进行删除for (i = pos; i < pc->sz - 1; i++) //判断条件这里所要交换的比总数少一个{pc->data[i] = pc->data[i + 1];}pc->sz--;printf("删除成功\n");
}//查找联系人
void SearchContact(const Contact* pc) //使用const修饰更安全
{char name[MAX_NAME] = { 0 };if (pc->sz == 0){printf("通讯录为空,查找不到!");return;}printf("请输入你要查找联系人的姓名:>");scanf("%s", name);int pos = FindByName(pc, name);int i = 0;if (pos == -1){printf("找不到所要查找的联系人\n");return;}//打印导航栏printf("%-10s %-4s %-5s %-12s %-30s\n", "姓名", "年龄", "性别", "电话", "地址");//打印数据printf("%-10s %-4d %-5s %-12s %-30s\n",pc->data[pos].name,pc->data[pos].age,pc->data[pos].sex,pc->data[pos].tele,pc->data[pos].addr);
}

2.6修改联系人

要修改联系人,首先的找到联系人的位置,然后输入信息将其修改

源文件:test.c

case MODIFY://修改联系人printf("修改联系人\n");ModifyContact(&con);break;

头文件:Contact.h

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

源文件:Contact.c

//修改联系人
void menu1()
{printf("**********************************\n");printf("******1.姓名*********2.年龄*******\n");printf("******3.性别*********4.电话*******\n");printf("*************5.地址***************\n");printf("**********************************\n");
}
void ModifyContact(Contact* pc)
{int input = 0;char name[MAX_NAME] = { 0 };printf("请输入你要修改的联系人姓名:>");scanf("%s", name);//查找int pos = FindByName(pc, name);int i = 0;if (pos == -1){printf("找不到所要查找的联系人\n");return;}//修改printf("请输入要修改的具体信息:>\n");menu1();scanf("%d", &input);switch (input){case 1:printf("请输入新的姓名:>");scanf("%s", pc->data[pos].name);break;case 2:printf("请输入新的年龄:>");scanf("%d", &pc->data[pos].age);break;case 3:printf("请输入新的性别:>");scanf("%s", pc->data[pos].sex);break;case 4:printf("请输入新的电话:>");scanf("%s", pc->data[pos].tele);break;case 5:printf("请输入新的地址:>");scanf("%s", pc->data[pos].addr);break;default:printf("输入有误,修改失败\n");return;}printf("修改成功\n");
}

2.7排序联系人

要排序联系人,也就意味着要排序结构体成员,就需要用到qsort排序,如果不清楚可以点击查看->qsort排序详解

源文件:test.c

case SORT://排序联系人SortContact(&con);break;

头文件:Contcat.h

#include <stdlib.h>
//排序联系人
void SortContact(Contact* pc);

源文件:Contact.c

void menu2()
{printf("***************************\n");printf("******** 1.NAME  **********\n");printf("******** 2.AGE   **********\n");printf("***************************\n");
}//按照名字排序
int cmp_byname(const void* p1, const void* p2)
{return strcmp(((PeoInfo*)p1)->name, ((PeoInfo*)p2)->name);
}//按照年龄来排序
int cmp_byage(const void* p1, const void* p2)
{return ((PeoInfo*)p1)->age - ((PeoInfo*)p2)->age;
}//排序联系人
void SqrtContact(Contact* pc)
{int input = 0;if (pc->sz == 0){printf("通讯录没有联系人,无法排序!\n");return;}menu2();printf("请选择排序的对象:>");scanf("%d", &input);switch (input){case 1:qsort(pc, pc->sz, sizeof(PeoInfo), cmp_byname);break;case 2:qsort(pc, pc->sz, sizeof(PeoInfo), cmp_byage);break;}printf("排序成功\n");//排序成功之后打印一下ShowContact(pc);
}

2.8清空联系人

清空联系人本质上就是再将通讯录初始化,我们只需要再进行调用初始化函数就可以了

源文件:test.c

case CLEAR://清空联系人ClearContact(&con);break;

头文件:Contact.h

//清空联系人
void ClearContact(Contact* pc);

源文件:Contact.c

//清空联系人
void ClearContact(Contact* pc)
{//初始化通讯录InitContact(pc);printf("清空成功\n");//初始完之后再打印ShowContact(pc);
}

3.完整代码

头文件:Contact.h

#pragma once//头文件的包含#include <stdio.h>
#include <string.h>
#include <stdlib.h>//大小的定义
#define MAX 100
#define MAX_NAME 20
#define MAX_SEX 5
#define MAX_TELE 12
#define MAX_ADDR 20//表示一个联系人的各种信息
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];   //用来存放100个人的信息int sz;              //记录通讯录中有效信息的个数
}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 SqrtContact(Contact* pc);//清空联系人
void ClearContact(Contact* pc);

源文件:test.c

#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.Sqrt   ****\n");printf("****  7.Clear   *****    0.Exit   ****\n");printf("**************************************\n");
}enum Option
{EXIT,ADD,DEL,SEARCH,MODIFY,SHOW,SQRT,CLEAR
};int main()
{int input = 0;Contact con;   //创建通讯录变量//初始化通讯录InitContact(&con);  //要修改通讯录里面的内容要传递指针do{menu();printf("请选择通讯录的功能:>");scanf("%d", &input);switch (input){case ADD://添加联系人printf("添加联系人\n");AddContact(&con); //传址调用break;case DEL://删除联系人printf("删除联系人\n");DelContact(&con);break;case SEARCH://查找联系人printf("查找联系人\n");SearchContact(&con);break;case MODIFY://修改联系人printf("修改联系人\n");ModifyContact(&con);break;case SHOW://展示ShowContact(&con);//显示通讯录不需要修改通讯录其实传值调用也可以,但是为了节省空间使用传值调用break;case SQRT://排序联系人SqrtContact(&con);break;case CLEAR://清空联系人ClearContact(&con);break;case EXIT:printf("退出通讯录!\n");break;default:printf("选择错误,请重新选择:>\n");break;}} while (input);return 0;
}

源文件:Contact.c

#define _CRT_SECURE_NO_WARNINGS 1#include "Contact.h"
//通讯录的实现模块//初始化通讯录
void InitContact(Contact* pc)
{pc->sz = 0;memset(pc->data, 0, sizeof(pc->data));
}//添加联系人
void AddContact(Contact* 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++;  //每一次添加完之后sz都要++printf("添加成功\n");
}//显示通讯录
void ShowContact(const Contact* pc)
{printf("%-10s %-4s %-5s %-12s %-15s\n", "名字", "年龄", "性别", "电话", "地址");int i = 0;for (i = 0; i < pc->sz; i++){printf("%-10s %-4d %-5s %-12s %-15s\n", pc->data[i].name, pc->data[i].age, pc->data[i].sex, pc->data[i].tele, pc->data[i].addr);}
}//查找
static int FindByName(const Contact* pc, char name[])
{int i = 0;int pos = 0;for (i = 0; i < pc->sz; i++){//找到所要联系人所在的位置if (0 == strcmp(pc->data[i].name, name)){return i;}}return -1;
}
//删除联系人
void DelContact(Contact* pc)
{char name[MAX_NAME] = { 0 };//判断通讯录是否为空if (0 == pc->sz){printf("通讯录为空,无法删除!\n");return;}printf("请输入你要删除联系人的姓名:>");scanf("%s", name);int pos = FindByName(pc, name);int i = 0;if (pos == -1){printf("找不到所要删除的联系人\n");return;}//进行删除for (i = pos; 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 };if (pc->sz == 0){printf("通讯录为空,查找不到!");return;}printf("请输入你要查找联系人的姓名:>");scanf("%s", name);int pos = FindByName(pc, name);int i = 0;if (pos == -1){printf("找不到所要查找的联系人\n");return;}//打印导航栏printf("%-10s %-4s %-5s %-12s %-30s\n", "姓名", "年龄", "性别", "电话", "地址");//打印数据printf("%-10s %-4d %-5s %-12s %-30s\n",pc->data[pos].name,pc->data[pos].age,pc->data[pos].sex,pc->data[pos].tele,pc->data[pos].addr);
}//修改联系人
void menu1()
{printf("*********************************\n");printf("******1.姓名*********2.年龄*******\n");printf("******3.性别*********4.电话*******\n");printf("*************5.地址**************\n");printf("*********************************\n");
}
void ModifyContact(Contact* pc)
{int input = 0;char name[MAX_NAME] = { 0 };printf("请输入你要修改的联系人姓名:>");scanf("%s", name);//查找int pos = FindByName(pc, name);int i = 0;if (pos == -1){printf("找不到所要查找的联系人\n");return;}//修改printf("请输入要修改的具体信息:>\n");menu1();scanf("%d", &input);switch (input){case 1:printf("请输入新的姓名:>");scanf("%s", pc->data[pos].name);break;case 2:printf("请输入新的年龄:>");scanf("%d", &pc->data[pos].age);break;case 3:printf("请输入新的性别:>");scanf("%s", pc->data[pos].sex);break;case 4:printf("请输入新的电话:>");scanf("%s", pc->data[pos].tele);break;case 5:printf("请输入新的地址:>");scanf("%s", pc->data[pos].addr);break;default:printf("输入有误,修改失败\n");return;}printf("修改成功\n");
}void menu2()
{printf("***************************\n");printf("******** 1.NAME  **********\n");printf("******** 2.AGE   **********\n");printf("***************************\n");
}//按照名字排序
int cmp_byname(const void* p1, const void* p2)
{return strcmp(((PeoInfo*)p1)->name, ((PeoInfo*)p2)->name);
}//按照年龄来排序
int cmp_byage(const void* p1, const void* p2)
{return ((PeoInfo*)p1)->age - ((PeoInfo*)p2)->age;
}//排序联系人
void SqrtContact(Contact* pc)
{int input = 0;if (pc->sz == 0){printf("通讯录没有联系人,无法排序!\n");return;}menu2();printf("请选择排序的对象:>");scanf("%d", &input);switch (input){case 1:qsort(pc, pc->sz, sizeof(PeoInfo), cmp_byname);break;case 2:qsort(pc, pc->sz, sizeof(PeoInfo), cmp_byage);break;}printf("排序成功\n");//排序成功之后打印一下ShowContact(pc);
}//清空联系人
void ClearContact(Contact* pc)
{//初始化通讯录InitContact(pc);printf("清空成功\n");//初始完之后再打印ShowContact(pc);
}

关于通讯录的代码就展现在这里了,但是这只是静态版本,还有很多的不足,当退出程序后下一次再进入程序我们之前的信息就回收了,还有各个数组的大小都是固定的,没办法随时随地的变化,在后面也会补发上关于通讯录的动态版本的代码,最后感谢大家的支持!谢谢

相关文章:

C语言小程序:通讯录(静态版)

哈喽各位老铁们&#xff0c;今天给大家带来一期通讯录的静态版本的实现&#xff0c;何为静态版本后面会做解释&#xff0c;话不多说&#xff0c;直接开始&#xff01;关于通讯录&#xff0c;其实也就是类似于我们手机上的通讯录一样&#xff0c;有着各种各样的功能&#xff0c;…...

写CSDN博客两年半的收获--总结篇

&#x1f468;‍&#x1f4bb;作者简介&#xff1a;练习时长两年半的java博主 &#x1f39f;️个人主页&#xff1a;君临๑ ps&#xff1a;点赞是免费的&#xff0c;却可以让写博客的作者开心好几天&#x1f60e; 不知不觉间&#xff0c;在csdn写博客也有两年半的时间了&#x…...

中科亿海微FPGA应用(一、点灯)

1.软件&#xff1a; https://download.csdn.net/download/weixin_41784968/87564071 需要申请license才能使用&#xff1a;软件试用申请_软件试用申请_中科亿海微电子科技&#xff08;苏州&#xff09;有限公司 2.开发板&#xff1a; 芯片EQ6HL45&#xff0c;42.5k LUT。 3…...

ElasticSearch - SpringBoot整合ES:实现搜索结果排序 sort

文章目录00. 数据准备01. Elasticsearch 默认的排序方式是什么&#xff1f;02. Elasticsearch 支持哪些排序方式&#xff1f;03. ElasticSearch 如何指定排序方式&#xff1f;04. ElasticSearch 如何按照相关性排序&#xff1f;05. ElasticSearch 查询结果如何不按照相关性排序…...

IDEA的全新UI可以在配置里启用了,快来试试吧!

刚看到IDEA官方昨天发了这样一条推&#xff1a;IDEA的新UI可以在2022.3版本上直接使用了&#xff01;开启方法如下&#xff1a;打开IDEA的Setting界面&#xff0c;在Appearance & Behavior下有个被标注为Beta标签的New UI菜单&#xff0c;具体如下图&#xff1a;勾选Enable…...

第九章 镜像架构和规划 - 备份处于活动状态时自动进行故障转移

文章目录第九章 镜像架构和规划 - 备份处于活动状态时自动进行故障转移备份处于活动状态时自动进行故障转移备份不活动时的自动故障转移对各种中断场景的镜像响应响应主要中断场景的自动故障转移第九章 镜像架构和规划 - 备份处于活动状态时自动进行故障转移 备份处于活动状态…...

Barra模型因子的构建及应用系列七之Liquidity因子

一、摘要 在前期的Barra模型系列文章中&#xff0c;我们构建了Size因子、Beta因子、Momentum因子、Residual Volatility因子、NonLinear Size因子和Book-to-Price因子&#xff0c;并分别创建了对应的单因子策略&#xff0c;其中Size因子和NonLinear Siz因子具有很强的收益能力…...

走进二叉树的世界 ———性质讲解

二叉树的性质和证明前言1.二叉树的概念和结构特殊的二叉树&#xff1a;二叉树的性质前言 本篇博客主要讲述的是有关二叉树的一些概念&#xff0c;性质以及部分性质的相关证明&#xff0c;如果大伙发现了啥错误&#xff0c;可以在评论区指出&#x1f618;&#x1f618; 1.二叉树…...

【SSM】Spring + SpringMVC +MyBatis 框架整合

个人简介&#xff1a;Java领域新星创作者&#xff1b;阿里云技术博主、星级博主、专家博主&#xff1b;正在Java学习的路上摸爬滚打&#xff0c;记录学习的过程~ 个人主页&#xff1a;.29.的博客 学习社区&#xff1a;进去逛一逛~ SSM框架整合一、导入相关依赖二、配置web.xml文…...

【算法基础】一篇文章彻底弄懂Dijkstra算法|多图解+代码详解

博主简介&#xff1a;努力学习的大一在校计算机专业学生&#xff0c;热爱学习和创作。目前在学习和分享&#xff1a;算法、数据结构、Java等相关知识。博主主页&#xff1a; 是瑶瑶子啦所属专栏: 算法 &#xff1b;该专栏专注于蓝桥杯和ACM等算法竞赛&#x1f525;近期目标&…...

第二十三天01MySQL多表查询与事务

目录 1. 多表查询 1.1 概述 1.1.1 数据准备 1.1.2 介绍 1.1.3 分类 1.2 内连接 1.2.1 语法 1.2.2 案例演示 1.3 外连接 1.3.1 语法 1.3.2 案例演示 1.4 子查询 1.4.1 介绍 1.4.2 标量子查询 1.4.3 列子查询 1.4.4 行子查询 1.4.5 表子查询 1.5 案例 1.5.1 介…...

TCP协议详解

1.TCP的准备条件在古代的时候&#xff0c;古人们经常写书信进行交流&#xff0c;写书信的前提是你要知道这份信是要寄给谁在网络中&#xff0c;我们通过ip端口号找对目标对象&#xff0c;但是现在网站一般会对ip端口注册一个域名&#xff0c;所以我们一般就是对域名进行查找&am…...

Activiti7与Spring、Spring Boot整合开发

Activiti整合Spring 一、Activiti与Spring整合开发 1.1 Activiti与Spring整合的配置 1)、在pom.xml文件引入坐标 如下 <properties><slf4j.version>1.6.6</slf4j.version><log4j.version>1.2.12</log4j.version> </properties> <d…...

基于SpringBoot实现冬奥会运动会科普平台【源码+论文】

基于SpringBoot实现冬奥会科普平台演示开发语言&#xff1a;Java 框架&#xff1a;springboot JDK版本&#xff1a;JDK1.8 服务器&#xff1a;tomcat7 数据库&#xff1a;mysql 5.7 数据库工具&#xff1a;Navicat11 开发软件&#xff1a;eclipse/myeclipse/idea Maven包&#…...

一文吃透SpringBoot整合mybatis-plus(保姆式教程)

✅作者简介&#xff1a;2022年博客新星 第八。热爱国学的Java后端开发者&#xff0c;修心和技术同步精进。 &#x1f34e;个人主页&#xff1a;Java Fans的博客 &#x1f34a;个人信条&#xff1a;不迁怒&#xff0c;不贰过。小知识&#xff0c;大智慧。 &#x1f49e;当前专栏…...

C++ primer plus(第六版)编程练习答案 第4章 复合类型

一、程序清单 arrayone.cpp // arrayone.cpp -- small arrays of integers #include <iostream> int main() {using namespace std;int yams[3]; // creates array with three elementsyams[0] = 7; // assign value to first elementyams[1] = 8;yams[2] = 6;i…...

Kafka源码分析之Producer(一)

总览 根据kafka的3.1.0的源码example模块进行分析&#xff0c;如下图所示&#xff0c;一般实例代码就是我们分析源码的入口。 可以将produce的发送主要流程概述如下&#xff1a; 拦截器对发送的消息拦截处理&#xff1b; 获取元数据信息&#xff1b; 序列化处理&#xff1b;…...

springboot校友社交系统

050-springboot校友社交系统演示录像开发语言&#xff1a;Java 框架&#xff1a;springboot JDK版本&#xff1a;JDK1.8 服务器&#xff1a;tomcat7 数据库&#xff1a;mysql 5.7&#xff08;一定要5.7版本&#xff09; 数据库工具&#xff1a;Navicat11 开发软件&#xff1a;e…...

python flask项目部署

flask上传服务器pyhon安装下载Anacondasudo wget https://mirrors.tuna.tsinghua.edu.cn/anaconda/archive/Anaconda3-5.3.1-Linux-x86_64.sh可根据需要安装对应的版本https://repo.anaconda.com/archive/解压anaconda压缩包bash Anaconda3-5.3.1-Linux-x86_64.sh解压过程中会…...

常见排序算法(C语言实现)

文章目录排序介绍插入排序直接插入排序希尔排序选择排序选择排序堆排序交换排序冒泡排序快速排序递归实现Hoare版本挖坑法前后指针版本非递归实现Hoare版本挖坑法前后指针版本快排的优化三值取中小区间优化归并排序递归实现非递归实现计数排序排序算法复杂度及稳定性分析不同算…...

手游刚开服就被攻击怎么办?如何防御DDoS?

开服初期是手游最脆弱的阶段&#xff0c;极易成为DDoS攻击的目标。一旦遭遇攻击&#xff0c;可能导致服务器瘫痪、玩家流失&#xff0c;甚至造成巨大经济损失。本文为开发者提供一套简洁有效的应急与防御方案&#xff0c;帮助快速应对并构建长期防护体系。 一、遭遇攻击的紧急应…...

css实现圆环展示百分比,根据值动态展示所占比例

代码如下 <view class""><view class"circle-chart"><view v-if"!!num" class"pie-item" :style"{background: conic-gradient(var(--one-color) 0%,#E9E6F1 ${num}%),}"></view><view v-else …...

脑机新手指南(八):OpenBCI_GUI:从环境搭建到数据可视化(下)

一、数据处理与分析实战 &#xff08;一&#xff09;实时滤波与参数调整 基础滤波操作 60Hz 工频滤波&#xff1a;勾选界面右侧 “60Hz” 复选框&#xff0c;可有效抑制电网干扰&#xff08;适用于北美地区&#xff0c;欧洲用户可调整为 50Hz&#xff09;。 平滑处理&…...

前端倒计时误差!

提示:记录工作中遇到的需求及解决办法 文章目录 前言一、误差从何而来?二、五大解决方案1. 动态校准法(基础版)2. Web Worker 计时3. 服务器时间同步4. Performance API 高精度计时5. 页面可见性API优化三、生产环境最佳实践四、终极解决方案架构前言 前几天听说公司某个项…...

系统设计 --- MongoDB亿级数据查询优化策略

系统设计 --- MongoDB亿级数据查询分表策略 背景Solution --- 分表 背景 使用audit log实现Audi Trail功能 Audit Trail范围: 六个月数据量: 每秒5-7条audi log&#xff0c;共计7千万 – 1亿条数据需要实现全文检索按照时间倒序因为license问题&#xff0c;不能使用ELK只能使用…...

今日学习:Spring线程池|并发修改异常|链路丢失|登录续期|VIP过期策略|数值类缓存

文章目录 优雅版线程池ThreadPoolTaskExecutor和ThreadPoolTaskExecutor的装饰器并发修改异常并发修改异常简介实现机制设计原因及意义 使用线程池造成的链路丢失问题线程池导致的链路丢失问题发生原因 常见解决方法更好的解决方法设计精妙之处 登录续期登录续期常见实现方式特…...

使用Spring AI和MCP协议构建图片搜索服务

目录 使用Spring AI和MCP协议构建图片搜索服务 引言 技术栈概览 项目架构设计 架构图 服务端开发 1. 创建Spring Boot项目 2. 实现图片搜索工具 3. 配置传输模式 Stdio模式&#xff08;本地调用&#xff09; SSE模式&#xff08;远程调用&#xff09; 4. 注册工具提…...

Android写一个捕获全局异常的工具类

项目开发和实际运行过程中难免会遇到异常发生&#xff0c;系统提供了一个可以捕获全局异常的工具Uncaughtexceptionhandler&#xff0c;它是Thread的子类&#xff08;就是package java.lang;里线程的Thread&#xff09;。本文将利用它将设备信息、报错信息以及错误的发生时间都…...

[特殊字符] 手撸 Redis 互斥锁那些坑

&#x1f4d6; 手撸 Redis 互斥锁那些坑 最近搞业务遇到高并发下同一个 key 的互斥操作&#xff0c;想实现分布式环境下的互斥锁。于是私下顺手手撸了个基于 Redis 的简单互斥锁&#xff0c;也顺便跟 Redisson 的 RLock 机制对比了下&#xff0c;记录一波&#xff0c;别踩我踩过…...

基于开源AI智能名片链动2 + 1模式S2B2C商城小程序的沉浸式体验营销研究

摘要&#xff1a;在消费市场竞争日益激烈的当下&#xff0c;传统体验营销方式存在诸多局限。本文聚焦开源AI智能名片链动2 1模式S2B2C商城小程序&#xff0c;探讨其在沉浸式体验营销中的应用。通过对比传统品鉴、工厂参观等初级体验方式&#xff0c;分析沉浸式体验的优势与价值…...