通讯录应用程序开发指南

目录

一、前言

二、构建通讯录应用程序

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.mzph.cn/news/237742.shtml

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

相关文章

PhysX——源码编译

从git下载源码 git主页 https://github.com/NVIDIA-Omniverse/PhysXclone地址 https://github.com/NVIDIA-Omniverse/PhysX.git源码编译 运行PhysX需要两个编译器的支持&#xff0c;CMake 3.12 或以上版本以及Python 2.7.6 版本 进入工程的 physx 目录&#xff0c;运行generate…

Java将枚举类转为json返回给前端

Java将枚举类转为json返回给前端 1.后端将枚举类直接返回给前端时只会显示枚举名称2.使用 JsonFormat 注解可以将枚举类转为json再返回给前端。2.1添加maven依赖2.2在枚举类上添加JsonFormat(shape JsonFormat.Shape.OBJECT)2.3编写接口返回给前端 1.后端将枚举类直接返回给前…

『Linux升级路』基础开发工具——gdb篇

&#x1f525;博客主页&#xff1a;小王又困了 &#x1f4da;系列专栏&#xff1a;Linux &#x1f31f;人之为学&#xff0c;不日近则日退 ❤️感谢大家点赞&#x1f44d;收藏⭐评论✍️ 目录 一、背景知识介绍 二、gdb指令介绍 一、背景知识介绍 在软件开发中&#xff0c…

WT2003HX高品质MP3语音芯片,支持立体声输出的应用优势

在当今的音频处理领域&#xff0c;立体声输出已经成为一项基本的需求。许多电子产品都要求能够支持立体声音效&#xff0c;为用户提供更为沉浸式的音频体验。针对这一市场需求&#xff0c;唯创知音推出了WT2003HX高品质MP3语音芯片&#xff0c;该芯片支持立体声输出&#xff0c…

Ubuntu 常用命令之 cal 命令用法介绍

&#x1f4d1;Linux/Ubuntu 常用命令归类整理 cal命令在Ubuntu系统下用于显示日历。它可以显示任何特定月份或整个年份的日历。 cal命令的参数如下 -1&#xff1a;只显示当前月份的日历。-3&#xff1a;显示前一个月、当前月和下一个月的日历。-s&#xff1a;指定日历的开始…

Redis命令参考手册完整版

Redis命令参考手册完整版 Key(键)DELKEYSRANDOMKEYTTLPTTLEXISTSMOVERENAMERENAMENXTYPEEXPIREPEXPIREEXPIREATPEXPIREATPERSISTSORT 获取 name 和 password<br />redis> SORT user_id BY user_level_* DESC GET user_name_* GET<br />user_password_*<br /&…

设计模式分类

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

音视频直播核心技术

直播流程 采集&#xff1a; 是视频直播开始的第一个环节&#xff0c;用户可以通过不同的终端采集视频&#xff0c;比如 iOS、Android、Mac、Windows 等。 前处理&#xff1a;主要就是美颜美型技术&#xff0c;以及还有加水印、模糊、去噪、滤镜等图像处理技术等等。 编码&#…

vue中监听Form表单值的变化

想要监听From表单中某个值的变化需要用到vue中的 watch watch: {inputForm.isHeating() {this.inputForm.otherHeating}}, isHeating是表单中的某个值&#xff0c;如果他变化就会清空另一个值

泛微OA C# 调用 WebAPI功能实现

泛微OA C# 调用 WebAPI功能实现 OA 在线文档地址1. 创建流程字段参数 mainData 简单说明字段表明细表2. 接口封装2.1 接口初始化2.2 接口注册2.3 获取Token2.4 拼装 Headers2.5 常用工作流方法2.5.1 创建2.5.2 删除2.5.3 撤回2.5.4 退回3. 接口调用OA 在线文档地址 Token认证 …

12.21_黑马数据结构与算法笔记Java

//最近在复习&#xff0c;&#xff0c;java的进度会比较慢一些 目录 219 排序算法 基数排序2 220 排序算法 java排序 221 排序 e01 根据另一个数组次序排序 222 排序 e02 根据出现频率排序 thinking&#xff1a;关于比较器 223 排序 e03 最大间距 解法1&#xff08;超出内…

快速学习 webpack

目录 1. webpack基本概念 webpack能做什么&#xff1f; 2. webpack的使用步骤 2.1_webpack 更新打包 3. webpack的配置 3.1_打包流程图 3.2_案例-webpack隔行变色 3.3_插件-自动生成html文件 3.4_加载器 - 处理css文件问题 3.5_加载器 - 处理css文件 3.6_加载器 - 处…

Linux文件目录结构与术语

/ 下的目录&#xff08;图形化界面样式&#xff09; Linux常用术语: 1.目录 -> 在Windows中叫文件夹 2.路径 -> 在Windows中叫文档所在的位置(如&#xff1a;文档hello.txt所在的位置是Winodws中的 D:\www文件夹下,也可以描述为&#xff1a;helllo.txt所在的路径是C:\www…

使用PE信息查看工具和Beyond Compare文件比较工具排查dll文件版本不对的问题

目录 1、问题说明 2、修改了代码&#xff0c;但安装版本还是有问题 3、使用PE信息查看工具查看音视频库文件&#xff08;二进制&#xff09;的时间戳 4、使用Beyond Compare比较两个库文件的差异 5、找到原因 6、最后 C软件异常排查从入门到精通系列教程&#xff08;专栏…

uniapp中使用封装步骤条组件

针对步骤条封装完终于清清楚楚啦 先看效果&#xff1a; 附上代码&#xff1a;使用可直接复用&#xff1a;数据是写在了当前组件中&#xff0c;如有必须&#xff0c;可以使用其中的props传值stepInfos传递相应的数据&#xff0c;根据steps步数就可以控制走到哪一步啦 <temp…

SpaceDesk如何连接平板/PC(生产力副屏)

1、下载安装 分为安卓端和PC端&#xff0c;两个设备都需要安装对应的软件。 SpaceDesk官网 https://link.zhihu.com/?targethttp%3A//spacedesk.net/ 需要魔法上网。安装过程比较简单&#xff0c;无脑下一步即可。 我已经把安装包准备好了&#xff0c;如果不想自己找&#…

k8s之共享存储pvpvc

目录 1.1 存储资源管理 1.2 持久卷pv的类型 1.3 实验mysql基于NFS共享存储实现持久化存储 1.3.1 安装NFS 1.3.2 PV参数详解 1.3.3 创建pv 1.3.4 mysql使用pvc持久卷 1.4 动态绑定pv 1.4.1 配置nfs-provisioner授权 1.4.2 部署nfs-client-provisioner 1.4.3 创建Stor…

CentOS7 安装 DockerCompose

目录 一、安装Docker 二、安装步骤 2.1 卸载 2.2 安装docker 2.3 启动docker 2.4 配置镜像加速器 一、安装Docker Docker 分为 CE 和 EE 两大版本。 CE 即社区版(免费&#xff0c;支持周期7个月)EE 即企业版强调安全&#xff0c;付费使用&#xff0c;支持周期 24 个月…

Altium Designer切换中文界面与英文界面的方法图文教程及视频演示

目录 视频演示1&#xff0c;概述2&#xff0c;汉化切换为中文界面3&#xff0c;切换为英文界面4&#xff0c;总结 视频演示 Altium Designer软件汉化方法 欢迎点击浏览更多高清视频演示 1&#xff0c;概述 Altium Designer支持汉化界面&#xff0c;本文演示Altium Designer软件…

中奖记录设计(策略+模板)

背景 最近需求要做一个活动需求,用户只要参与活动就可以获得奖励,奖励分为以下几种: 创角奖励: 用户在活动内的游戏创建角色即可中奖 等级奖励: 角色在游戏内级别达到某一个级别即可中奖 VIP级别奖励: 角色在游戏内VIP级别达到某一个级别即可中奖 排行榜奖励: 角色某一天充值榜…