【C语言】动态通讯录 -- 详解

⚪前言

前面详细介绍了静态版通讯录【C语言】静态通讯录 -- 详解_炫酷的伊莉娜的博客-CSDN博客,但是静态版通讯录的空间是无法被改变的,而且空间利用率也不高。为了解决静态通讯录这一缺点,这时就要有一个能够随着存入联系人数量的增加而增大空间的通讯录。接下来我们将探讨动态通讯录,在能够实现静态版通讯录的基础上,能够灵活调整通讯录联系人数量并实现其基本功能。

以下内容是在静态通讯录的基础上进行修改,大致思路不变。


一、实现目标

1、功能

  • 保存 1000 个联系人的信息
  • 添加联系人
  • 删除联系人
  • 修改联系人
  • 查找联系人
  • 排序

2、个人信息(结构体)

  • 名字
  • 年龄
  • 性别
  • 电话
  • 地址

动态版通讯录的要求:

  1. 默认能够存放 3 个联系人信息。
  2. 不够的话,每次增加 2 个联系人信息。

二、创建文件

  1. test.c(专门测试通讯录的功能)
  2. contact.c(接口的实现)
  3. contact.h(接口的声明)

三、初始页面的实现

1、实现主菜单页面

// test.c

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

效果图如下:


(2)main()
int main()
{int input = 0;// 创建通讯录struct Contact con; // con就是通讯录,里边包含:data指针和size,capacity// 初始化通讯录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 EXIT:DestoryContact(&con); // 销毁通讯录-释放动态开辟的内存printf("退出通讯录!\n");break;default:printf("选择错误!\n");break;}} while (input);return 0;
}

main() 函数代码中与之前的区别主要就是要在初始化的时候开辟动态内存空间,在输入 0 退出程序时,会将通讯录删除。其实仔细想想,确实需要这一步,因为在整个程序都没有结束时,动态开辟内存也并没有结束,所以只能是在整个程序结束的时候才能将动态开辟的内存释放掉。 


2、在contact.h 中引用所需要的文件和必要的定义

首先我们要 声明一个结构体,其中 包含了我们想要保存的信息(可以自己设置):
typedef struct PeoInfo
{char name[MAX_NAME];int age;char sex[MAX_SEX];char tele[MAX_TELE];char addr[MAX_ADDR];
}PeoInfo;

 定义结构体(与静态通讯录不同!)

        动态通讯录在定义结构体时,应该增加一个元素(capacity)来记录当前通讯录的最大容量,当达到这个最大容量的时候,就对动态通讯录进行扩容,增加内存空间,这样就能够很好地实现动态通讯录。 

        静态通讯录与动态通讯录最大的不同就在这,静态版是直接使用一个开辟好的数组,而动态版是使用一个指针变量,用于指向使用动态内存申请函数 malloc 所开辟的空间,然后使用开辟的这块空间对联系人信息进行储存,最大的优点是可以使用 realloc 函数对其进行扩容。这样就解决了静态通讯录在空间上的不足。

// 动态通讯录类型
typedef struct Contact
{struct PeoInfo *data; // 存放数据int size; // 记录当前已经有的元素个数int capacity; // 记录当前通讯录的最大容量
}Contact;// 静态通讯录类型
struct Contact
{struct PeoInfo data[MAX];// 可以存放1000个人的信息int size;// 记录通讯录中已经保存的信息个数
};

整体逻辑:

// contact.h
#pragma once // 避免头文件被重复引用// #define MAX 1000#define DEFAULT_SZ 3 // 通讯录初始状态的容量大小#define MAX_NAME 20
#define MAX_SEX 5
#define MAX_TELE 12
#define MAX_ADDR 30#include <stdio.h>
#include <string.h> // memset strcmp
#include <stdlib.h> // qsort malloc realloc
#include <assert.h> // assertenum Option
{EXIT,//0ADD,//1DEL,//2SEARCH,//3MODIFY,//4SHOW,//5SORT//6
};struct PeoInfo
{char name[MAX_NAME];int age;char sex[MAX_SEX];char tele[MAX_TELE];char addr[MAX_ADDR];
};// 动态通讯录类型
typedef struct Contact
{struct PeoInfo *data; // 存放数据int size; // 记录当前已经有的元素个数int capacity; // 记录当前通讯录的最大容量
}Contact;// 声明函数
// 初始化通讯录
void InitContact(struct Contact* ps);
// 增加联系人
void AddContact(struct Contact* ps);
// 展示通讯录信息
void ShowContact(const struct Contact* ps);
// 删除指定联系人信息
void DelContact(struct Contact* ps);
// 查找指定联系人信息
void SearchContact(const struct Contact* ps);
// 修改指定联系人信息
void ModifyContact(struct Contact* ps);
// 排序通讯录内容(按姓名排)
void SortContact(struct Contact* ps);
// 销毁通讯录
void DestoryContact(Contact* ps);

四、在 contact.c 上实现各个接口函数

1、初始化通讯录

malloc 函数在这里并没有把其数据初始化为 0 ,这里可以使用 memset 函数初始化存放联系人信息的结构体数组 data。

对于动态通讯录的初始化,就是申请一块初始的空间,用来存放信息,如果满了在在此基础上进行扩容。

// 初始化通讯录
void InitContact(struct Contact* ps)
{assert(ps);ps->size = 0;ps->capacity = DEFAULT_SZ;ps->data = (struct PeoInfo*)malloc(ps->capacity * sizeof(struct PeoInfo));if (ps->data == NULL){perror("InitContact::malloc");return;}memset(ps->data, 0, ps->capacity * sizeof(struct PeoInfo));
}

2、添加联系人

先判断通讯录人数是否已满,满了需要扩容,对已经申请过的空间进行扩容,可以使用库函数 realloc 实现。满了一次扩容 2 联系人信息的空间。

// 检测当前通讯录的容量
void CheckCapacity(struct Contact* ps)
{if (ps->size == ps->capacity){//增容struct PeoInfo* ptr = realloc(ps->data, (ps->capacity + 2) * sizeof(PeoInfo));if (ptr != NULL){ps->data = ptr;ps->capacity += 2;printf("增容成功!\n");}else{printf("增容失败!\n");}}
}// 添加联系人
void AddContact(struct Contact* ps)
{assert(ps);// 检测当前通讯录的容量// 1、如果满了就增加空间// 2、如果没满无需任何操作CheckCapacity(ps);// 增加数据printf("请输入名字:>");scanf("%s", ps->data[ps->size].name);printf("请输入年龄:>");scanf("%d", &(ps->data[ps->size].age)); // 年龄是一个整型变量 需要取地址printf("请输入性别:>");scanf("%s", ps->data[ps->size].sex);printf("请输入电话:>");scanf("%s", ps->data[ps->size].tele);printf("请输入地址:>");scanf("%s", ps->data[ps->size].addr);ps->size++;printf("添加成功!\n");
}

 注意由于 age 在这里是一个整型变量,所以要加上 &


3、展示通讯录中的信息

// 展示通讯录中的信息
void ShowContact(const struct Contact* ps)
{if (ps->size == 0){printf("通讯录为空!\n"); // 判断通讯录人数是否为0}else{int i = 0;// 打印标题printf("%-20s\t%-4s\t%-5s\t%-12s\t%-20s\n", "名字", "年龄", "性别", "电话", "地址");// 打印数据for (i = 0; i < ps->size; i++){printf("%-20s\t%-4d\t%-5s\t%-12s\t%-20s\n",ps->data[i].name,ps->data[i].age,ps->data[i].sex,ps->data[i].tele,ps->data[i].addr);}}
}

注意:因为只是打印信息,不会修改内容,所以加上 const 更加安全。 

为了让结果更美观,采用了左对齐的方式。printf 中 %-20s 中的 20 是指输出字段的宽度负号表示左对齐,如省略表示右对齐,如果输出的数据位数小于 20,则在数据右端补齐空格。


4、通过姓名查找指定联系人所在的下标 

// 通过姓名查找指定联系人所在下标
static int FindByName(const struct Contact* ps, char name[MAX_NAME])
{int i = 0;for (i = 0; i < ps->size; i++){if (0 == strcmp(ps->data[i].name, name)){return i; // 查找到返回联系人的下标}}return -1; // 找不到返回-1
}

为了解决代码的冗余,我们不妨分装一个函数来完成查找功能。该函数会在删除 / 修改 / 查找指定联系人信息的函数中被调用到,这些函数刚好又在同一源文件中,所以用 static 修饰函数,只能在所在此文件内使用。


5、删除指定联系人信息

先判断通讯录是否为空,如果不为空,再通过 FindByName() 函数查找通讯录中是否有你要删除的联系人,如果有则删除。

原理:把要删除的联系人后面一个人的信息依次从前向后往前移动一位,覆盖掉其信息,然后再将人数 -1。

// 删除指定联系人
void DelContact(struct Contact* ps)
{char name[MAX_NAME];int pos = 0;printf("请输入要删除人的名字:>");scanf("%s", name);// 1、查找要删除的人在什么位置// 找到了返回名字所在元素的下标// 找不到返回 -1pos = FindByName(ps, name);// 2、删除if (pos == -1){printf("要删除的人不存在!\n");}else{// 删除数据int j = 0;for (j = pos; j < ps->size - 1; j++){// 把要删除的人后面一个人的信息依次从前向后往前移动一位,覆盖掉其信息ps->data[j] = ps->data[j + 1];}ps->size--;printf("删除成功!\n");}
}

6、查找指定联系人信息

通过 FindByName() 函数查找通讯录中是否有你要查找的联系人,如果查找到,则打印该联系人的信息。 

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

 注意:因为只是查找信息,不会修改内容,所以加上 const 更加安全 。


7、修改指定联系人信息

通过 FindByName() 函数查找通讯录中是否有你要修改信息的联系人,如果有则修改。 

// 修改指定联系人信息
void ModifyContact(struct Contact* ps)
{int pos = 0;char name[MAX_NAME];printf("请输入要修改人的名字:>");scanf("%s", name);pos = FindByName(ps, name);if (pos == -1){printf("要修改人的信息不存在!\n");}else{printf("请输入名字:>");scanf("%s", ps->data[pos].name);printf("请输入年龄:>");scanf("%d", &ps->data[pos].age);printf("请输入性别:>");scanf("%s", ps->data[pos].sex);printf("请输入电话:>");scanf("%s", ps->data[pos].tele);printf("请输入地址:>");scanf("%s", ps->data[pos].addr);printf("修改完成!\n");}
}

8、排序通讯录内容

// 排序通讯录内容
// 比较结构体数组中两个元素的姓名成员
int compareStructType_name(const void* elem1, const void* elem2)
{// 姓名成员是字符串,用strcmp比较return strcmp(((struct PeoInfo*)elem1)->name, ((struct PeoInfo*)elem2)->name);
}// 以名字排序所有联系人
void SortContact(struct Contact* ps)
{// 判断通讯录是否为空if (ps->size == 0){printf("通讯录为空,无法排序!\n");return;}else{// 根据姓名成员对结构体数组升序排列qsort(ps->data, ps->size, sizeof(ps->data[0]), compareStructType_name);printf("以名字排序联系人成功!\n");}
}

该函数排序用的是姓名作为标准,也可以自己更换其他的排序方式。


9、销毁通讯录

使用动态内存开辟的空间是需要归还的,当通讯录使用完后是需要归还内存的,也就需要我们销毁通讯录。

// 销毁通讯录
void DestoryContact(Contact* ps)
{free(ps->data);ps->data = NULL;ps->capacity = 0;ps->size = 0;printf("销毁成功!\n");
}

五、代码整合

1、test.c

// 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.sort   ********\n");printf("****** 0.exit                   ********\n");printf("****************************************\n");
}int main()
{int input = 0;// 创建通讯录struct Contact con; // con就是通讯录,里边包含:data指针和size,capacity// 初始化通讯录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 EXIT:DestoryContact(&con); // 销毁通讯录-释放动态开辟的内存printf("退出通讯录!\n");break;default:printf("选择错误!\n");break;}} while (input);return 0;
}

2、contact.h

// contact.h
#pragma once // 避免头文件被重复引用// #define MAX 1000#define DEFAULT_SZ 3 // 通讯录初始状态的容量大小#define MAX_NAME 20
#define MAX_SEX 5
#define MAX_TELE 12
#define MAX_ADDR 30#include <stdio.h>
#include <string.h> // memset strcmp
#include <stdlib.h> // qsort malloc realloc
#include <assert.h> // assertenum Option
{EXIT,//0ADD,//1DEL,//2SEARCH,//3MODIFY,//4SHOW,//5SORT//6
};struct PeoInfo
{char name[MAX_NAME];int age;char sex[MAX_SEX];char tele[MAX_TELE];char addr[MAX_ADDR];
};// 动态通讯录类型
typedef struct Contact
{struct PeoInfo *data; // 存放数据int size; // 记录当前已经有的元素个数int capacity; // 记录当前通讯录的最大容量
}Contact;// 声明函数
// 初始化通讯录
void InitContact(struct Contact* ps);
// 增加联系人
void AddContact(struct Contact* ps);
// 展示通讯录信息
void ShowContact(const struct Contact* ps);
// 删除指定联系人信息
void DelContact(struct Contact* ps);
// 查找指定联系人信息
void SearchContact(const struct Contact* ps);
// 修改指定联系人信息
void ModifyContact(struct Contact* ps);
// 排序通讯录内容(按姓名排)
void SortContact(struct Contact* ps);
// 销毁通讯录
void DestoryContact(Contact* ps);

3、contact.c

// contact.c
#define _CRT_SECURE_NO_WARNINGS 1#include "contact.h"// 初始化通讯录
void InitContact(struct Contact* ps)
{assert(ps);ps->size = 0;ps->capacity = DEFAULT_SZ;ps->data = (struct PeoInfo*)malloc(ps->capacity * sizeof(struct PeoInfo));if (ps->data == NULL){perror("InitContact::malloc");return;}memset(ps->data, 0, ps->capacity * sizeof(struct PeoInfo));
}// 检测当前通讯录的容量
void CheckCapacity(struct Contact* ps)
{if (ps->size == ps->capacity){//增容struct PeoInfo* ptr = realloc(ps->data, (ps->capacity + 2) * sizeof(PeoInfo));if (ptr != NULL){ps->data = ptr;ps->capacity += 2;printf("增容成功!\n");}else{printf("增容失败!\n");}}
}// 添加联系人
void AddContact(struct Contact* ps)
{assert(ps);// 检测当前通讯录的容量// 1、如果满了就增加空间// 2、如果没满无需任何操作CheckCapacity(ps);// 增加数据printf("请输入名字:>");scanf("%s", ps->data[ps->size].name);printf("请输入年龄:>");scanf("%d", &(ps->data[ps->size].age)); // 年龄是一个整型变量 需要取地址printf("请输入性别:>");scanf("%s", ps->data[ps->size].sex);printf("请输入电话:>");scanf("%s", ps->data[ps->size].tele);printf("请输入地址:>");scanf("%s", ps->data[ps->size].addr);ps->size++;printf("添加成功!\n");
}// 展示通讯录中的信息
void ShowContact(const struct Contact* ps)
{if (ps->size == 0){printf("通讯录为空!\n"); // 判断通讯录人数是否为0}else{int i = 0;// 打印标题printf("%-20s\t%-4s\t%-5s\t%-12s\t%-20s\n", "名字", "年龄", "性别", "电话", "地址");// 打印数据for (i = 0; i < ps->size; i++){printf("%-20s\t%-4d\t%-5s\t%-12s\t%-20s\n",ps->data[i].name,ps->data[i].age,ps->data[i].sex,ps->data[i].tele,ps->data[i].addr);}}
}// 通过名字查找指定联系人所在的下标
static int FindByName(const struct Contact* ps, char name[MAX_NAME])
{int i = 0;for (i = 0; i < ps->size; i++){if (0 == strcmp(ps->data[i].name, name)){return i;}}return -1; // 找不到返回-1
}// 删除指定联系人
void DelContact(struct Contact* ps)
{char name[MAX_NAME];int pos = 0;printf("请输入要删除人的名字:>");scanf("%s", name);// 1、查找要删除的人在什么位置// 找到了返回名字所在元素的下标// 找不到返回 -1pos = FindByName(ps, name);// 2、删除if (pos == -1){printf("要删除的人不存在!\n");}else{// 删除数据int j = 0;for (j = pos; j < ps->size - 1; j++){// 把要删除的人后面一个人的信息依次从前向后往前移动一位,覆盖掉其信息ps->data[j] = ps->data[j + 1];}ps->size--;printf("删除成功!\n");}
}// 查找指定联系人信息
void SearchContact(const struct Contact* ps)
{int pos = 0;char name[MAX_NAME];printf("请输入要查找人的名字:>");scanf("%s", name);pos = FindByName(ps, name); // 查找if (pos == -1){printf("要查找的人不存在!\n");}else{printf("%-20s\t%-4s\t%-5s\t%-12s\t%-20s\n", "名字", "年龄", "性别", "电话", "地址");//数据printf("%-20s\t%-4d\t%-5s\t%-12s\t%-20s\n",ps->data[pos].name,ps->data[pos].age,ps->data[pos].sex,ps->data[pos].tele,ps->data[pos].addr);}
}// 修改指定联系人信息
void ModifyContact(struct Contact* ps)
{int pos = 0;char name[MAX_NAME];printf("请输入要修改人的名字:>");scanf("%s", name);pos = FindByName(ps, name);if (pos == -1){printf("要修改人的信息不存在!\n");}else{printf("请输入名字:>");scanf("%s", ps->data[pos].name);printf("请输入年龄:>");scanf("%d", &ps->data[pos].age);printf("请输入性别:>");scanf("%s", ps->data[pos].sex);printf("请输入电话:>");scanf("%s", ps->data[pos].tele);printf("请输入地址:>");scanf("%s", ps->data[pos].addr);printf("修改完成!\n");}
}// 排序通讯录内容
// 比较结构体数组中两个元素的姓名成员
int compareStructType_name(const void* elem1, const void* elem2)
{// 姓名成员是字符串,用strcmp比较return strcmp(((struct PeoInfo*)elem1)->name, ((struct PeoInfo*)elem2)->name);
}// 以名字排序所有联系人
void SortContact(struct Contact* ps)
{// 判断通讯录是否为空if (ps->size == 0){printf("通讯录为空,无法排序!\n");return;}else{// 根据姓名成员对结构体数组升序排列qsort(ps->data, ps->size, sizeof(ps->data[0]), compareStructType_name);printf("以名字排序联系人成功!\n");}
}// 销毁通讯录
void DestoryContact(Contact* ps)
{free(ps->data);ps->data = NULL;ps->capacity = 0;ps->size = 0;printf("销毁成功!\n");
}

六、程序运行效果 

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

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

相关文章

Ansys Zemax | 手机镜头设计 - 第 1 部分:光学设计

本文是 3 篇系列文章的一部分&#xff0c;该系列文章将讨论智能手机镜头模组设计的挑战&#xff0c;从概念、设计到制造和结构变形的分析。本文是三部分系列的第一部分&#xff0c;将专注于OpticStudio中镜头模组的设计、分析和可制造性评估。&#xff08;联系我们获取文章附件…

安防监控视频云存储平台EasyNVR通道频繁离线的原因排查与解决

安防视频监控汇聚EasyNVR视频集中存储平台&#xff0c;是基于RTSP/Onvif协议的安防视频平台&#xff0c;可支持将接入的视频流进行全平台、全终端分发&#xff0c;分发的视频流包括RTSP、RTMP、HTTP-FLV、WS-FLV、HLS、WebRTC等格式。为了满足用户的集成与二次开发需求&#xf…

企业计算机服务器遭到了locked勒索病毒攻击如何解决,勒索病毒解密

网络技术的不断发展&#xff0c;也为网络安全埋下了隐患&#xff0c;近期&#xff0c;我们收到很多企业的求助&#xff0c;企业的计算机服务器遭到了locked勒索病毒的攻击&#xff0c;导致企业的财务系统内的所有数据被加密无法读取&#xff0c;严重影响了企业的正常运行。最近…

如何通过观测云的RUM找到前端加载的瓶颈--可观测性入门篇

声明与保证 本文写作于2023年6月&#xff0c;性能优化的评价标准和优化方式仅适用于当前观测云控制台&#xff0c;当然随着产品迭代及技术更新&#xff0c;本文也会应要求适当更新。 创建、修订时间创建修改人版本2023/6/24观测云***v1.0.0 1.网站性能评价的发展史&#xff…

打开vim的语法高亮

在一个Ubuntu中自带的vim版本是8.2.4919&#xff0c;默认就是开始了语法高亮的&#xff0c;打开一个Java文件效果如下&#xff1a; 它不仅仅对Java文件有语法高亮&#xff0c;对很多的文件都有&#xff0c;比如vim的配置文件也有语法高亮&#xff0c;有语法高亮时读起来会容易…

DNNGP模型解读-early stopping 和 batch normalization的使用

一、考虑的因素&#xff08;仅代表个人观点&#xff09; 1.首先我们看到他的这篇文章所考虑的不同方面从而做出的不同改进&#xff0c;首先考虑到了对于基因组预测的深度学习方法的设计 &#xff0c;我们设计出来这个方法就是为了基因组预测而使用&#xff0c;这也是主要目的&…

排序算法-冒泡排序(C语言实现)

简介&#x1f600; 冒泡排序是一种简单但效率较低的排序算法。它重复地扫描待排序元素列表&#xff0c;比较相邻的两个元素&#xff0c;并将顺序错误的元素交换位置&#xff0c;直到整个列表排序完成。 实现&#x1f9d0; 以下内容为本人原创&#xff0c;经过自己整理得出&am…

WAVE SUMMIT2023六大分会场同步开启,飞桨+文心大模型加速区域产业智能化!

由深度学习技术及应用国家工程研究中心主办、百度飞桨和文心大模型承办的WAVE SUMMIT深度学习开发者大会2023将于8月16日重磅来袭&#xff01;届时上海、广州、深圳、成都、南昌和宁波六大分会场将同步开启&#xff01; 分会汇聚区域产业大咖、科研机构专家、知名学者和技术大…

【C++ 学习 ⑬】- 详解 list 容器

目录 一、list 容器的基本介绍 二、list 容器的成员函数 2.1 - 迭代器 2.2 - 修改操作 三、list 的模拟实现 3.1 - list.h 3.2 - 详解 list 容器的迭代器 3.2 - test.cpp 一、list 容器的基本介绍 list 容器以类模板 list<T>&#xff08;T 为存储元素的类型&…

【第二阶段】kotlin函数引用

针对上篇传入函数参数我们也可以重新定义一个函数&#xff0c;然后在main中调用时传入函数对象 lambda属于函数类型的对象&#xff0c;需要把普通函数变成函数类型的对象&#xff08;函数引用&#xff09;&#xff0c;使用“&#xff1a;&#xff1a;” /*** You can edit, ru…

DRF 缓存

应用环境 django4.2.3 &#xff0c;python3.10 由于对于服务而言&#xff0c;有些数据查询起来比较费时&#xff0c;所以&#xff0c;对于有些数据&#xff0c;我们需要将其缓存。 最近做了一个服务&#xff0c;用的时 DRF 的架构&#xff0c;刚好涉及缓存&#xff0c;特此记…

webSocket 笔记

1 认识webSocket WebSocket_ohana&#xff01;的博客-CSDN博客 一&#xff0c;什么是websocket WebSocket是HTML5下一种新的协议&#xff08;websocket协议本质上是一个基于tcp的协议&#xff09;它实现了浏览器与服务器全双工通信&#xff0c;能更好的节省服务器资源和带宽…

centos 7.9 部署django项目

1、部署框架 主要组件&#xff1a;nginx、uwsgi、django项目 访问页面流程&#xff1a;nginx---》uwsgi---》django---》uwsgi---》nginx 2、部署过程 操作系统&#xff1a;centos 7.9 配置信息&#xff1a;4核4G 50G 内网 eip &#xff1a;10.241.103.216 部署过程&…

深入学习SpringCloud Alibaba微服务架构,揭秘Nacos、Sentinel、Seata等核心技术,助力构建高效系统!

课程链接&#xff1a; 链接: https://pan.baidu.com/s/1hRN0R8VFcwjyCTWCEsz-8Q?pwdj6ej 提取码: j6ej 复制这段内容后打开百度网盘手机App&#xff0c;操作更方便哦 --来自百度网盘超级会员v4的分享 课程介绍&#xff1a; &#x1f4da;【第01阶段】课程简介&#xff1a;全…

Android FrameWork 层 Handler源码解析

Handler生产者-消费者模型 在android开发中&#xff0c;经常会在子线程中进行一些耗时操作&#xff0c;当操作完毕后会通过handler发送一些数据给主线程&#xff0c;通知主线程做相应的操作。 其中&#xff1a;子线程、handler、主线程&#xff0c;其实构成了线程模型中经典的…

STM32存储左右互搏 I2C总线FATS读写EEPROM ZD24C1MA

STM32存储左右互搏 I2C总线FATS读写EEPROM ZD24C1MA 在较低容量存储领域&#xff0c;EEPROM是常用的存储介质&#xff0c;可以通过直接或者文件操作方式进行读写。不同容量的EEPROM的地址对应位数不同&#xff0c;在发送字节的格式上有所区别。EEPROM是非快速访问存储&#xf…

vue2+Spring Boot2.7 大文件分片上传

之前我们文章 手把手带大家实现 vue2Spring Boot2.7 文件上传功能 将了上传文件 但如果文件很大 就不太好处理了 按正常情况甚至因为超量而报错 这里 我弄了个足够大的文件 我们先搭建 Spring Boot2.7 环境 首先 application.yml 代码编写如下 server:port: 80 upload:path:…

【佳佳怪文献分享】使用点云从半监督到全监督房间布局估计

标题&#xff1a;From Semi-supervised to Omni-supervised Room Layout Estimation Using Point Cloud 作者&#xff1a;Huan-ang Gao, Beiwen Tian, Pengfei Li, Xiaoxue Chen, Hao Zhao, Guyue Zhou , Yurong Chen and Hongbin Zha 来源&#xff1a;2023 IEEE Internation…

根据源码,模拟实现 RabbitMQ - 通过 SQLite + MyBatis 设计数据库(2)

目录 一、数据库设计 1.1、数据库选择 1.2、环境配置 1.3、建库建表接口实现 1.4、封装数据库操作 1.5、针对 DataBaseManager 进行单元测试 一、数据库设计 1.1、数据库选择 MySQL 是我们最熟悉的数据库&#xff0c;但是这里我们选择使用 SQLite&#xff0c;原因如下&am…

手机出现 不读卡 / 无信号时应该怎么办?

当手机屏幕亮起&#xff0c;一般在屏幕最上方都会有代表手机卡状态的显示&#xff0c;其中网络信号和读卡状态的标识&#xff0c;依旧有很多人分不太清&#xff0c;更不清楚改怎么办了。 1、当我们的手机里有两张卡时&#xff0c;则会有两个信号显示 2、信号状态一般是由短到…