通讯录应用程序开发指南

目录

一、前言

二、构建通讯录应用程序

2.1通讯录框架

(1)打印菜单

(2) 联系人信息的声明

(3)创建通讯录

(4)初始化通讯录

2.2功能实现 

(1)增加联系人

(2)显示联系人

(3)删除联系人

(4)查找联系人

(5)修改联系人

(6)排序联系人

三、通讯录的优化

3.1 文件存储

🌴保存信息到文件中:

🌴加载文件中的信息到通讯录:

3.2 动态开辟内存

🌴创建通讯录 :

🌴初始化通讯录: 

🌴增加联系人:

 🌴销毁通讯录:

四、源码


一、前言

在日常生活中,我们经常需要管理大量的联系人信息,包括电话号码、电子邮件地址等。通讯录应用程序成为了我们生活中不可或缺的一部分,它可以帮助我们高效的管理和查找联系人信息。在本篇博客中,我们将探讨如何使用C语言编写一个简单的通讯录应用程序。通过学习这个实例,我们将了解如何使用C语言来处理数据、实现基本的增删查改功能,并且获得实际的编程实际经验。

二、构建通讯录应用程序

本篇博客所实现的通讯录有如下功能:

  1. 可以保存100个人(人数由自己控制)的信息;
  2. 增加联系人的信息;
  3. 删除指定联系人的信息;
  4. 查找指定联系人的信息;
  5. 修改指定联系人的信息;
  6. 显示所有联系人的信息
  7. 排序通讯录的信息。

联系人的信息有:名字、年龄、性别、电话、住址。

2.1通讯录框架

(1)打印菜单

为了能够实现人机交互,我们需要打印菜单以供用户选择想要实现的功能。

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");
}enum Option
{EXIT,//0ADD,//1DEL,//2SEARCH,//3MODIFY,//4SHOW,//5SORT//6
};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 EXIT:printf("退出通讯录\n");break;default:printf("选择错误,请重新选择!\n");break;}} while (input);return 0;
}

🌴打印效果:

(2) 联系人信息的声明

#define NAME_MAX 20
#define SEX_MAX 5
#define TELE_MAX 12
#define ADDR_MAX 30typedef struct PeoInfo
{char name[NAME_MAX];int age;char sex[SEX_MAX];char tele[TELE_MAX];char addr[ADDR_MAX];
}PeoInfo;

(3)创建通讯录

#define MAX 100typedef struct Contact
{PeoInfo data[MAX];//存放联系人的数据int sz;//记录当前通讯录中存放的人的信息个数
}Contact;

(4)初始化通讯录

void InitContact(Contact* pc)
{assert(pc);//保证指针的有效性memset(pc->data, 0, sizeof(pc->data));pc->sz = 0;
}

2.2功能实现 

(1)增加联系人

void AddContact(Contact* pc)
{assert(pc);//判断通讯录是否已满if (pc->sz == MAX){printf("通讯录已满,无法增加\n");return;}//增加信息printf("请输入联系人的姓名:");scanf("%s", pc->data[pc->sz].name);printf("请输入联系人的年龄:");scanf("%s", &(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");
}

🌴效果:

(2)显示联系人

联系人增加成功后,我们想看到他的所有信息,这时候我们就可以让他显示在屏幕上。 

void ShowContact(const Contact* pc)
{assert(pc);//判断通讯录是否为空,如果为空,则无需打印if (pc->sz == 0){printf("通讯录为空!\n");return;}//为了增加美观性,打印标题行printf("%-20s%-5s%-5s%-15s%-30s\n", "姓名", "年龄", "性别", "电话", "地址");for (int i = 0; i < pc->sz; i++){printf("%-20s%-5d%-5s%-15s%-30s\n", pc->data[i].name, pc->data[i].age, pc->data[i].sex, pc->data[i].tele, pc->data[i].addr);}
}

🌴效果:

(3)删除联系人

我们发现,不管是删除联系人,还是修改联系人,我们首先要找到这个联系人,所以我们还要写一个查找联系人的函数。 查找联系人的过程就是将这个通讯录遍历一遍,找到它的每个元素,然后跟我们要查找的这个人相比较,如果相同,就返回这个元素的下标,如果找不到,就返回-1。

//查找联系人
int FindByContact(Contact* pc, char name[])
{assert(pc);for (int i = 0; i < pc->sz; i++){if (strcmp(pc->data[i].name, name) == 0){return i;}}return -1;
}//删除联系人的信息
void DelContact(Contact* pc)
{assert(pc);char name[NAME_MAX];//判断通讯录是否为空,如果为空,则无需删除if (pc->sz == 0){printf("通讯录为空,无需删除\n");return;}//查找联系人printf("请输入要删除联系人的名字:");scanf("%s", name);int ret = FindByContact(pc, name);if (ret == -1){printf("查无此人\n");return;}//删除联系人for (int i = ret; i < pc->sz - 1; i++){pc->data[i] = pc->data[i + 1];}pc->sz--;printf("删除成功\n");
}

 🌴效果:

(4)查找联系人

void SearchContact(Contact* pc)
{assert(pc);char name[NAME_MAX];printf("请输入要查找人的姓名:");scanf("%s", name);int ret = FindByContact(pc, name);if (ret == -1){printf("查无此人\n");return;}//显示联系人printf("%-20s%-5s%-5s%-15s%-30s\n", "姓名", "年龄", "性别", "电话", "地址");printf("%-20s%-5d%-5s%-15s%-30s\n",pc->data[ret].name, pc->data[ret].age, pc->data[ret].sex, pc->data[ret].tele, pc->data[ret].addr);
}

  🌴效果:

(5)修改联系人

void ModifyContact(Contact* pc)
{int input = 0;assert(pc);char name[NAME_MAX];printf("请输入要修改人的姓名:");scanf("%s", name);int ret = FindByContact(pc, name);if (ret == -1){printf("查无此人\n");return;}//修改信息do{printf("请选择要修改的信息:%s %s %s %s %s %s\n", "1.姓名", "2.年龄", "3.性别", "4.电话", "5.地址", "0.退出");scanf("%d", &input);switch (input){case 1:printf("请输入要修改人的姓名:\n");scanf("%s", pc->data[ret].name);printf("修改成功\n");break;case 2:printf("请输入要修改人的年龄:\n");scanf("%d", &(pc->data[ret].age));printf("修改成功\n");break;case 3:printf("请输入要修改人的性别:\n");scanf("%s", pc->data[ret].sex);printf("修改成功\n");break;case 4:printf("请输入要修改人的电话:\n");scanf("%s", pc->data[ret].tele);printf("修改成功\n");break;case 5:printf("请输入要修改人的地址:\n");scanf("%s", pc->data[ret].addr);printf("修改成功\n");break;case 0:printf("退出修改\n");break;default:printf("修改项中没有此信息,请重新选择\n");break;}} while (input);
}

 🌴效果:

 

(6)排序联系人

//比较函数,用于qsort排序
int compareByAge(const void* a, const void* b)
{return ((PeoInfo*)a)->age - ((PeoInfo*)b)->age;
}//排序联系人
void SortContactAge(Contact* pc)
{assert(pc);if (pc->sz == 0){printf("通讯录为空,无需排序!\n");return;}qsort(pc->data, pc->sz, sizeof(PeoInfo), compareByAge);printf("%-20s%-5s%-5s%-15s%-30s\n", "姓名", "年龄", "性别", "电话", "地址");for (int i = 0; i < pc->sz; i++){printf("%-20s%-5d%-5s%-15s%-30s\n",pc->data[i].name, pc->data[i].age, pc->data[i].sex, pc->data[i].tele, pc->data[i].addr);}printf("排序成功!\n");
}

  🌴效果:

三、通讯录的优化

当我们将上面实现的通讯录运行起来后,我们会发现以下几点问题:

  1. 录入的信息等程序结束后,就不存在了,这是因为数据是存放在内存中的,只要程序退出,或者掉电,都会丢失。
  2. 我们可以发现通讯录的大小是固定的100个元素,可以存放100个人的信息,但如果信息太多,空间就会有点小,不够用;而信息太少,空间又会太大,造成空间的浪费。

那该怎么解决呢?

  • 对于第1点,我们可以使用文件存储或数据库存储的方式来保存录入的联系人信息。
  • 对于第2点,我们可以用动态内存开辟的方式来开辟空间。

3.1 文件存储

🌴保存信息到文件中:

//保存信息到文件中去
void SaveContact(Contact* pc)
{//打开文件FILE* pf = fopen("contact.txt", "wb");if (pf == NULL){perror("SaveContact");return;}//写数据int i = 0;for (i = 0; i < pc->sz; i++){fwrite(pc->data + i, sizeof(PeoInfo), 1, pf);}//关闭文件fclose(pf);pf = NULL;
}

🌴加载文件中的信息到通讯录:

void Checkcapacity(Contact* pc);//声明增容函数void LoadContact(Contact* pc)
{//打开文件FILE* pf = fopen("contact.txt", "rb");if (pf == NULL){perror("LoadContact");return;}//读文件PeoInfo tmp = { 0 };while (fread(&tmp, sizeof(PeoInfo), 1, pf)){Checkcapacity(pc);pc->data[pc->sz] = tmp;pc->sz++;}//关闭文件fclose(pf);pf = NULL;
}//文件版本的初始化函数
void InitContact(Contact* pc)
{assert(pc);//保证指针的有效性pc->sz = 0;pc->capacity = DEFAULT_SZ;pc->data = calloc(DEFAULT_SZ, sizeof(PeoInfo));if (pc->data == NULL){perror("InitContact->calloc");return;}//加载文件中的信息到通讯录LoadContact(pc);
}

3.2 动态开辟内存

  1. 让通讯录刚开始时存放3个人的信息。
  2. 空间如果放满,可以增加容量,每次增加2个人的信息的空间。

🌴创建通讯录 :

 将data数组改为指针变量用来接收calloc函数开辟空间后的地址;增加一个变量capacity用来记录通讯录的当前容量,如果存放的信息满3个人,则增加容量。

//动态通讯录的版本
typedef struct Contact
{PeoInfo* data;//存放数据int sz;//记录当前通讯录中存放的人的信息个数int capacity;//记录的是通讯录的当前容量
}Contact;

🌴初始化通讯录: 

将通讯录容量初始化为3,这里可以定义宏,以方便修改,再用calloc函数开辟空间。

//动态版本
#define DEFAULT_SZ 3void InitContact(Contact* pc)
{assert(pc);//保证指针的有效性pc->sz = 0;pc->capacity = DEFAULT_SZ;pc->data = calloc(DEFAULT_SZ , sizeof(PeoInfo));if (pc->data == NULL){perror("InitContact->calloc");return;}
}

🌴增加联系人:

当通讯录满了以后,我们要考虑增容的问题,所以还要修改增加函数,将每次要增加的容量也定义为宏,方便修改。

//动态版本
#define DEFAULT_INC 2void Checkcapacity(Contact* pc)
{if (pc->sz == pc->capacity){PeoInfo* ptr = (PeoInfo*)realloc(pc->data, (pc->capacity + DEFAULT_INC) * sizeof(PeoInfo));if (ptr == NULL){pc->data = ptr;pc->capacity += DEFAULT_INC;printf("增容成功!\n");}else{perror("AddContact->recalloc");return;}}
}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);pc->sz++;printf("联系人添加成功\n");
}

 🌴销毁通讯录:

当我们要退出通讯录的时候,要将realloc函数开辟的空间释放掉。

//销毁通讯录
void DestoryContact(Contact* pc)
{free(pc->data);pc->data = NULL;pc->sz = 0;pc->capacity = 0;
}

四、源码

🌻(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("***  0.exit                   ***\n");printf("*********************************\n");
}enum Option
{EXIT,//0ADD,//1DEL,//2SEARCH,//3MODIFY,//4SHOW,//5SORT//6
};int main()
{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:SortContactAge(&con);break;case EXIT://保存信息到文件SaveContact(&con);//销毁通讯录DestoryContact(&con);printf("退出通讯录\n");break;default:printf("选择错误,请重新选择!\n");break;}} while (input);return 0;
}

 🌻(contact.h)

#include <stdio.h>
#include <assert.h>
#include <string.h>
#include <stdlib.h>#define NAME_MAX 20
#define SEX_MAX 5
#define TELE_MAX 12
#define ADDR_MAX 30#define MAX 100#define DEFAULT_SZ 3
#define DEFAULT_INC 2typedef struct PeoInfo
{char name[NAME_MAX];int age;char sex[SEX_MAX];char tele[TELE_MAX];char addr[ADDR_MAX];
}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(Contact* pc);//修改联系人
void ModifyContact(Contact* pc);//排序联系人
void SortContactAge(Contact* pc);//销毁通讯录
void DestoryContact(Contact* pc);//保存信息到文件中
void SaveContact(Contact* pc);//加载文件中的信息到通讯录
void LoadContact(Contact* pc);

 🌻(contact.c)

#include "Contact.h"//初始化通讯录
// 静态版本
//void InitContact(Contact* pc)
//{
//	assert(pc);//保证指针的有效性
//
//	memset(pc->data, 0, sizeof(pc->data));
//	pc->sz = 0;
//}void Checkcapacity(Contact* pc);//声明增容函数void LoadContact(Contact* pc)
{//打开文件FILE* pf = fopen("contact.txt", "rb");if (pf == NULL){perror("LoadContact");return;}//读文件PeoInfo tmp = { 0 };while (fread(&tmp, sizeof(PeoInfo), 1, pf)){Checkcapacity(pc);pc->data[pc->sz] = tmp;pc->sz++;}//关闭文件fclose(pf);pf = NULL;
}//文件版本的初始化函数
void InitContact(Contact* pc)
{assert(pc);//保证指针的有效性pc->sz = 0;pc->capacity = DEFAULT_SZ;pc->data = calloc(DEFAULT_SZ, sizeof(PeoInfo));if (pc->data == NULL){perror("InitContact->calloc");return;}//加载文件中的信息到通讯录LoadContact(pc);
}动态版本的初始化函数
//void InitContact(Contact* pc)
//{
//	assert(pc);//保证指针的有效性
//
//	pc->sz = 0;
//	pc->capacity = DEFAULT_SZ;
//	pc->data = calloc(DEFAULT_SZ , sizeof(PeoInfo));
//	if (pc->data == NULL)
//	{
//		perror("InitContact->calloc");
//		return;
//	}
//}//增加联系人信息
//静态版本
//void AddContact(Contact* pc)
//{
//	assert(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("联系人添加成功\n");
//}void Checkcapacity(Contact* pc)
{if (pc->sz == pc->capacity){PeoInfo* ptr = (PeoInfo*)realloc(pc->data, (pc->capacity + DEFAULT_INC) * sizeof(PeoInfo));if (ptr != NULL){pc->data = ptr;pc->capacity += DEFAULT_INC;printf("增容成功!\n");}else{perror("AddContact->recalloc");return;}}
}//动态版本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);pc->sz++;printf("联系人添加成功\n");
}//显示所有联系人的信息
void ShowContact(const Contact* pc)
{assert(pc);//判断通讯录是否为空,如果为空,则无需打印if (pc->sz == 0){printf("通讯录为空!\n");return;}//为了增加美观性,打印标题行printf("%-20s%-5s%-5s%-15s%-30s\n", "姓名", "年龄", "性别", "电话", "地址");for (int i = 0; i < pc->sz; i++){printf("%-20s%-5d%-5s%-15s%-30s\n", pc->data[i].name, pc->data[i].age, pc->data[i].sex, pc->data[i].tele, pc->data[i].addr);}
}//查找联系人
int FindByContact(Contact* pc, char name[])
{assert(pc);for (int i = 0; i < pc->sz; i++){if (strcmp(pc->data[i].name, name) == 0){return i;}}return -1;
}//删除联系人的信息
void DelContact(Contact* pc)
{assert(pc);char name[NAME_MAX];//判断通讯录是否为空,如果为空,则无需删除if (pc->sz == 0){printf("通讯录为空,无需删除\n");return;}//查找联系人printf("请输入要删除联系人的名字:");scanf("%s", name);int ret = FindByContact(pc, name);if (ret == -1){printf("查无此人\n");return;}//删除联系人for (int i = ret; i < pc->sz - 1; i++){pc->data[i] = pc->data[i + 1];}pc->sz--;printf("删除成功\n");
}//查找联系人的信息
void SearchContact(Contact* pc)
{assert(pc);char name[NAME_MAX];printf("请输入要查找人的姓名:");scanf("%s", name);int ret = FindByContact(pc, name);if (ret == -1){printf("查无此人\n");return;}//显示联系人printf("%-20s%-5s%-5s%-15s%-30s\n", "姓名", "年龄", "性别", "电话", "地址");printf("%-20s%-5d%-5s%-15s%-30s\n",pc->data[ret].name, pc->data[ret].age, pc->data[ret].sex, pc->data[ret].tele, pc->data[ret].addr);
}//修改联系人
void ModifyContact(Contact* pc)
{int input = 0;assert(pc);char name[NAME_MAX];printf("请输入要修改人的姓名:");scanf("%s", name);int ret = FindByContact(pc, name);if (ret == -1){printf("查无此人\n");return;}do{printf("请选择要修改的信息:%s %s %s %s %s %s\n", "1.姓名", "2.年龄", "3.性别", "4.电话", "5.地址", "0.退出");scanf("%d", &input);switch (input){case 1:printf("请输入要修改人的姓名:\n");scanf("%s", pc->data[ret].name);printf("修改成功\n");break;case 2:printf("请输入要修改人的年龄:\n");scanf("%d", &(pc->data[ret].age));printf("修改成功\n");break;case 3:printf("请输入要修改人的性别:\n");scanf("%s", pc->data[ret].sex);printf("修改成功\n");break;case 4:printf("请输入要修改人的电话:\n");scanf("%s", pc->data[ret].tele);printf("修改成功\n");break;case 5:printf("请输入要修改人的地址:\n");scanf("%s", pc->data[ret].addr);printf("修改成功\n");break;case 0:printf("退出修改\n");break;default:printf("修改项中没有此信息,请重新选择\n");break;}} while (input);
}//比较函数,用于qsort排序
int compareByAge(const void* a, const void* b)
{return ((PeoInfo*)a)->age - ((PeoInfo*)b)->age;
}//排序联系人
void SortContactAge(Contact* pc)
{assert(pc);if (pc->sz == 0){printf("通讯录为空,无需排序!\n");return;}qsort(pc->data, pc->sz, sizeof(PeoInfo), compareByAge);printf("%-20s%-5s%-5s%-15s%-30s\n", "姓名", "年龄", "性别", "电话", "地址");for (int i = 0; i < pc->sz; i++){printf("%-20s%-5d%-5s%-15s%-30s\n",pc->data[i].name, pc->data[i].age, pc->data[i].sex, pc->data[i].tele, pc->data[i].addr);}printf("排序成功!\n");
}//销毁通讯录
void DestoryContact(Contact* pc)
{free(pc->data);pc->data = NULL;pc->sz = 0;pc->capacity = 0;
}//保存信息到文件中去
void SaveContact(Contact* pc)
{//打开文件FILE* pf = fopen("contact.txt", "wb");if (pf == NULL){perror("SaveContact");return;}//写数据int i = 0;for (i = 0; i < pc->sz; i++){fwrite(pc->data + i, sizeof(PeoInfo), 1, pf);}//关闭文件fclose(pf);pf = NULL;
}

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

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

相关文章

2. 创建型模式 - 抽象工厂模式

亦称&#xff1a; Abstract Factory 意图 抽象工厂模式是一种创建型设计模式&#xff0c; 它能创建一系列相关的对象&#xff0c; 而无需指定其具体类。 问题 假设你正在开发一款家具商店模拟器。 你的代码中包括一些类&#xff0c; 用于表示&#xff1a; 一系列相关产品&…

yum install net-tools 命令报错,无法安装成功

编辑网卡文件 插入数据&#xff0c;输入&#xff1a; i 保存编辑&#xff1a;输入 Esc 然后:wq

初学gitrepo的种种

经过各种折腾之后&#xff0c;发现git其实还是很简单的&#xff1b; 首先你需要两台机器&#xff0c;一台作为服务器&#xff0c;一台作为开发机器&#xff0c;开发机器从服务器上拉取代码。 目 目录 git建仓 开发机器拉取代码 初始化仓代码 repo管理 repo工具的下载 …

如何使用Docker搭建青龙面板并结合内网穿透工具发布至公网可访问

文章目录 一、前期准备本教程环境为&#xff1a;Centos7&#xff0c;可以跑Docker的系统都可以使用。本教程使用Docker部署青龙&#xff0c;如何安装Docker详见&#xff1a; 二、安装青龙面板三、映射本地部署的青龙面板至公网四、使用固定公网地址访问本地部署的青龙面板 正文…

腾讯云发布升级版金融音视频解决方案,提供全新架构、安全和特性

远程银行、视频尽调、全媒体客服、路演直播……近年来&#xff0c;音视频技术支撑下的非接触式金融服务&#xff0c;成为了金融机构数字化转型和探索服务创新的重要方向。 12月21日&#xff0c;腾讯云正式发布升级版金融级音视频解决方案。新方案在架构、安全和特性上进行全面…

设计模式分类

不同设计模式的复杂程度、 细节层次以及在整个系统中的应用范围等方面各不相同。 我喜欢将其类比于道路的建造&#xff1a; 如果你希望让十字路口更加安全&#xff0c; 那么可以安装一些交通信号灯&#xff0c; 或者修建包含行人地下通道在内的多层互通式立交桥。 最基础的、 底…

性能压测工具:wrk

一般我们压测的时候&#xff0c;需要了解衡量系统性能的一些参数指标&#xff0c;比如。 1、性能指标简介 1.1 延迟 简单易懂。green:一般指响应时间 95线&#xff1a;P95。平均100%的请求中95%已经响应的时间 99线&#xff1a;P99。平均100%的请求中99%已经响应的时间 平均…

linux 上安装 minio

第一步&#xff0c;下载 wget https://dl.minio.org.cn/server/minio/release/linux-amd64/minio 第二步&#xff0c;修改权限 chmod x minio 第三步&#xff0c;设置 Path mv minio /usr/local/bin/ 第四步&#xff0c;创建 minio mkdir minio 第五步&#xff0c;启动 …

应用 Strangler 模式将遗留系统分解为微服务

许多来源在一般情况下提供了微服务的解释&#xff0c;但缺乏特定领域的示例。新来者或不确定从哪里开始的人可能会发现掌握如何将遗留系统过渡到微服务架构具有挑战性。本指南主要面向那些正在努力启动迁移工作的个人&#xff0c;它提供了特定于业务的示例来帮助理解该过程。 …

Spring Boot学习随笔- 拦截器实现和配置(HandlerInterceptor、addInterceptors)、jar包部署和war包部署

学习视频&#xff1a;【编程不良人】2021年SpringBoot最新最全教程 第十三章、拦截器 拦截器 &#xff1a;Interceptor 拦截 中断 类似于javaweb中的Filter&#xff0c;不过没有Filter那么强大 作用 Spring MVC的拦截器是一种用于在请求处理过程中进行预处理和后处理的机制。拦…

机器学习算法(11)——集成技术(Boosting——梯度提升)

一、说明 在在这篇文章中&#xff0c;我们学习了另一种称为梯度增强的集成技术。这是我在机器学习算法集成技术文章系列中与bagging一起介绍的一种增强技术。我还讨论了随机森林和 AdaBoost 算法。但在这里我们讨论的是梯度提升&#xff0c;在我们深入研究梯度提升之前&#xf…

(1)(1.9) MSP (version 4.2)

文章目录 前言 1 协议概述 2 配置 3 参数说明 前言 ArduPilot 支持 MSP 协议&#xff0c;可通过任何串行端口进行遥测、OSD 和传感器。这样&#xff0c;ArduPilot 就能将遥测数据发送到 MSP 兼容设备&#xff08;如大疆护目镜&#xff09;&#xff0c;用于屏幕显示&#x…

C# SixLabors.ImageSharp.Drawing的多种用途

生成验证码 /// <summary> /// 生成二维码 /// </summary> /// <param name"webRootPath">wwwroot目录</param> /// <param name"verifyCode">验证码</param> /// <param name"width">图片宽度</…

Spring Boot学习随笔- 文件上传和下载(在线打开、附件下载、MultipartFile)

学习视频&#xff1a;【编程不良人】2021年SpringBoot最新最全教程 第十二章、文件上传、下载 文件上传 文件上传是指将文件从客户端计算机传输到服务器的过程。 上传思路 前端的上传页面&#xff1a;提交方式必须为post&#xff0c;enctype属性必须为multipart/form-data开发…

在modelsim中查看断言

方法一&#xff1a;单纯的modelsim环境 &#xff08;1&#xff09;编译verilog代码时按照system verilog进行编译 vlog -sv abc.v 或者使用通配符编译所有的.v或者.sv文件 &#xff08; vlog -sv *.sv *.v&#xff09; &#xff08;2&#xff09;仿真命令加一个-assert…

R语言——基本操作(二)

目录 一、矩阵与数组 二、列表 三、数据框 四、因子 五、缺失数据 六、字符串 七、日期和时间 参考 一、矩阵与数组 matrix&#xff1a;创建矩阵&#xff0c;nrow 和 ncol 可以省略&#xff0c;但其值必须满足分配条件&#xff0c;否则会报错 只写一个值则自动分配&…

基于JAVA的海南旅游景点推荐系统 开源项目

目录 一、摘要1.1 项目介绍1.2 项目录屏 二、功能模块2.1 用户端2.2 管理员端 三、系统展示四、核心代码4.1 随机景点推荐4.2 景点评价4.3 协同推荐算法4.4 网站登录4.5 查询景点美食 五、免责说明 一、摘要 1.1 项目介绍 基于VueSpringBootMySQL的海南旅游推荐系统&#xff…

如何选择适合的UI自动化测试工具

随着软件开发项目的复杂性增加&#xff0c;UI自动化测试成为确保应用程序质量的关键步骤之一。然而&#xff0c;在选择UI自动化测试工具时&#xff0c;开发团队需要考虑多个因素&#xff0c;以确保选取的工具适用于项目需求并提供可靠的测试结果。 1. 了解项目需求 在选择UI自动…

百度侯震宇详解:大模型将如何重构云计算?

12月20日&#xff0c;在2023百度云智大会智算大会上&#xff0c;百度集团副总裁侯震宇以“大模型重构云计算”为主题发表演讲。他强调&#xff0c;AI原生时代&#xff0c;面向大模型的基础设施体系需要全面重构&#xff0c;为构建繁荣的AI原生生态筑牢底座。 侯震宇表示&…

Android蓝牙协议栈fluoride(八) - 音乐播放与控制(1)

概述 通常情况下音乐播放与控制这两个profile(即A2DP和AVRCP)都是同时存在的&#xff0c;A2DP分为Sink(SNK)和Source(SRC)两个角色&#xff0c;ACRVP分为Controller(CT)和Target(TG)两个角色。接下来的几篇博客将详细介绍这两个profile。 Sink和Source、CT和TG都是成对出现的。…