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

C语言进阶——通讯录模拟实现

🌇个人主页:_麦麦_

📚今日名言:只有走在路上,才能摆脱局限,摆脱执着,让所有的选择,探寻,猜测,想象都生机勃勃。——余秋雨《文化苦旅》

目录

一、前言

二、正文

1.大体框架

2.界面显示

3. 创建通讯录

4.初始化通讯录

5.增加联系人

6.显示联系人

7. 删除联系人

 8.查找联系人

9.修改联系人

10. 排序联系人

 三、结语


一、前言

        在上一章的结构体的学习中,相信小伙伴们或多或少都有所收获,但是有的小伙伴可能会问,结构体到底能用来做什么呢?今天,我们就借助结构体和之前所学的知识来实现通讯录。

二、正文

1.大体框架

        相信在座的小伙伴们一定有人做过类似的小游戏或项目,编程的大忌就是将所有的代码都放在同一个文件里,写的时候有多好爽快,后期对代码进行修改和维护的时候就有痛苦。这期通讯录的实现我们大致分为三个模块,一个用于测试通讯录,即对各种函数的调用【text.c】;另一个用于通讯录的实现,其中放置着通讯录功能的具体实现【contact.c】;最后一个就是函数的声明了[contact.h].

2.界面显示

         就像之前的扫雷与三子棋游戏一样,这个通讯录的第一步一定是要让使用者看到通讯录的页面,继而在使用者选择之后进行下一步的操作。因而我们仍旧采取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("***    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 0:printf("退出通讯录\n");break;default:printf("输入错误,请重新输入\n");}}while (input);return 0;
}

 

         在以上代码的逻辑下,使用者刚开始就能够看到我们设置好的界面,并进行功能的输入,如果输入为0就退出通讯录,通讯录为功能相应的数字就进行相应的功能【还未填写完整】,若为其他数字,则重新输入。

3. 创建通讯录

        为了实现我们菜单中的各个功能,首先我们要有这些功能的受体——通讯录,只有创建好通讯录 ,才能进行功能的操作。在生活中,我们手机上的通讯录都存有联系人的相关信息,例如姓名,年龄,性别,手机号码等等 ,其次在后面的功能中我们还需要知道这个通讯录中联系人的数量是多少。显然,我们需要一个自定义结构变量来定义通讯录,在这个结构体中有两个变量,一个是存放联系人信息的变量,另一个是存放联系人数量的变量。而存放联系人的信息显然需要一个数组,数组的大小即对应着能存放多少联系人,而数组中的元素就是联系人的信息,这也无法用一个单一类型变量来定义,所以我们还需要额外定义一个结构体变量来代表联系人的各种信息。具体代码如下:

//结构体——联系人的信息
struct peo
{char name[20];    //姓名char sex[10];     //性别int age;          //年龄  char addr[40];    //地址char tel[20];     //电话
};//结构体——通讯录
typedef struct contact
{struct peo Peo[contact_num];	//通讯录中联系人的信息int sz;							//当前存放联系人的个数
}contact;

4.初始化通讯录

        在通讯录的创建之后,就是对其的初始化了,为了方便,我们就都置成0就好了。

//Init_Contact——初始化通讯录void Init_Contact(contact* pc)
{pc->sz = 0;memset(pc, 0, sizeof(pc->Peo));
}

5.增加联系人

         在通讯录的创建和初始化完成之后,就是通讯录功能的实现了。首先是“增加联系人”这一功能。我们先是定义一个函数,这个函数的参数就是我们的通讯录,采用传递通讯录地址的方式,返回值为空,因为我们只是对通讯录的内容进行改变,并不需要返回任何东西。然后是函数的具体实现,我们要做的是在联系人信息这一数组中添加一个联系人,并在添加之后将通讯录当前存储的联系人数量+1。此外如果通讯录已满,我们需要提醒使用者无法再添加联系人。具体代码如下: 

 //Add——增加联系人void Add(contact* Contact){assert(Contact);if (Contact->sz < contact_num){printf("请输入联系人的姓名:>\n");scanf("%s", (Contact->Peo[Contact->sz]).name);printf("请输入联系人的性别:>\n");scanf("%s", Contact->Peo[Contact->sz].sex);printf("请输入联系人的年龄:>\n");scanf("%d", &(Contact->Peo[Contact->sz].age));printf("请输入联系人的地址:>\n");scanf("%s", Contact->Peo[Contact->sz].addr);printf("请输入联系人的电话:>\n");scanf("%s", Contact->Peo[Contact->sz].tel);Contact->sz++;}elseprintf("通讯录已满无法添加\n");}

  

6.显示联系人

        为了观察我们在执行增加联系人这个函数是否成功,我们接下来进行“显示联系人”这一功能的实现。同样的先是定义显示联系人这一函数,函数参数是通讯录,采取传址调用的方式,无需返回任何参数。函数的实现就是依据通讯录中所存储的联系人数量,来调用存储联系人信息的数组,并将其显示在屏幕上,为了数据显示的整齐和美观,笔者对打印的数据类型进行了小小的改善,对数据所占空间进行了设置,并将数据左对齐并在数据后输出一个水平制表符。 

 //Show——展示联系人void Show( const contact* Contact){assert(Contact);int pos = 0;    //联系人对应下标printf("%-20s\t%-10s\t%-4s\t%-40s\t%-20s\n","姓名", "性别", "年龄", "地址", "电话");for (pos = 0; pos < Contact->sz; pos++){printf("%-20s\t%-10s\t%-4d%\t%-40s\t%-20s\n", Contact->Peo[pos].name,Contact->Peo[pos].sex,Contact->Peo[pos].age,Contact->Peo[pos].addr,Contact->Peo[pos].tel);}}

7. 删除联系人

        首先是“删除联系人”这一函数的定义,参数为通讯录这一结构体,采取传址调用的方式,返回参数无。继而是函数具体的实现,笔者是根据使用者所输入的所要删除联系人的姓名来找到联系人在数组中对应的下标,从而进行各项信息的删除。这里有个小技巧,无论是删除联系人,修改联系人,搜索联系人都需要在根据输入的姓名对联系人进行查找,因而我们可以将这个功能封装成一个函数,在使用这一功能的时候只需要调用就行了。具体代码实现如下:

//Find_by_name——通过姓名,找到联系人所对应的下标int Find_by_name( const contact* Contact, char *name){int i = 0;for (i = 0; i < Contact->sz; i++){if (strcmp(&(Contact->Peo[i].name),name)==0)return i;}return -1;}//Del——删除联系人void Del(contact* Contact){char name[20] = { 0 };int i = 0;printf("请输入要删除的联系人:>");scanf("%s", name);int pos = Find_by_name(Contact, &name);if (-1 == pos){printf("该联系人不存在\n");return;}else{for (i = pos; i < Contact->sz-1; i++){Contact->Peo[i] = Contact->Peo[i + 1];}Contact->sz--;}}

 

 8.查找联系人

        首先是对“查找联系人”函数的定义,函数参数为通讯录,采取传址调用的方式,返回参数为0。然后是具体功能的实现,先是根据输入的姓名查找到对应的下标,再将其显示在屏幕上。具体代码如下:

//Search——搜索联系人void Search(const contact* Contact){char name[20] = {0};printf("请输入要寻找的联系人:>");scanf("%s", name);int pos= Find_by_name(Contact, &name);if (-1==pos){printf("该联系人不存在\n");return;}else{printf("%-10s\t%-6s\t%-4s\t%-40s\t%-20s\n", "姓名", "性别", "年龄", "地址", "电话");printf("%-10s\t%-6s\t%-4d%\t%-40s\t%-20s\n", Contact->Peo[pos].name,Contact->Peo[pos].sex,Contact->Peo[pos].age,Contact->Peo[pos].addr,Contact->Peo[pos].tel);} }

9.修改联系人

         首先是对“修改联系人”函数的定义,函数参数为通讯录,采取传址调用的方式,返回参数为0。然后是具体功能的实现,先是根据输入的姓名查找到对应的下标,再依据添加联系人的代码实现联系人信息的修改。具体代码如下:

//Modify——修改联系人void Modify(contact* Contact){assert(Contact);char name[20] = { 0 };printf("请输入要修改的联系人\n");scanf("%s", name);int pos = Find_by_name(Contact, &name);if (-1 == pos){printf("该联系人不存在\n");return;}else{printf("请输入联系人的姓名:>\n");scanf("%s", (Contact->Peo[pos]).name);printf("请输入联系人的性别:>\n");scanf("%s", Contact->Peo[pos].sex);printf("请输入联系人的年龄:>\n");scanf("%d", &(Contact->Peo[pos].age));printf("请输入联系人的地址:>\n");scanf("%s", Contact->Peo[pos].addr);printf("请输入联系人的电话:>\n");scanf("%s", Contact->Peo[pos].tel);}}

10. 排序联系人

        对联系人排序依据有很多,这里仅对联系人的年龄进行排序。采取冒泡排序的方式,冒泡排序的实现在前面的推文已经介绍过了,有兴趣的小伙伴可以康一康。https://blog.csdn.net/m0_73953114/article/details/128766018

//sort——按照年龄对联系人进行排序void sort(contact* Contact,contact* tmp){//执行冒泡排序的趟数int i = 0;for (i = 0; i < Contact->sz - 1; i++){//一趟冒泡排序中交换的次数int j = 0;for (j = 0; j < Contact->sz - 1-i; j++){if (Contact->Peo[j].age > Contact->Peo[j + 1].age){tmp->Peo[0] = Contact->Peo[j];Contact->Peo[j] = Contact->Peo[j + 1];Contact->Peo[j + 1] = tmp->Peo[0];}}}}

        到这里,整个通讯录就写完了,整体的代码如下: 

//main.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");
}int main()
{contact	Contact;	//创建通讯录contact tmp;Init_Contact(&Contact);		//初始化通讯录Init_Contact(&tmp);		int input = 0;do{menu();		//打印菜单printf("请选择你所需的功能:");scanf("%d", &input);switch (input){case 1:Add(&Contact);break;case 2:Del(&Contact);break;case 3:Search(&Contact);break;case 4:Modify(&Contact);break;case 5:Show(&Contact);break;case 6:sort(&Contact,&tmp);break;case 0:printf("退出通讯录\n");break;default:printf("输入错误,请重新输入\n");}}while (input);return 0;
}//contact.h
#define _CRT_SECURE_NO_WARNINGS 1
#pragma once
#define contact_num 100
#include <stdio.h>
#include <string.h>
#include <assert.h>//结构体——联系人的信息
struct peo
{char name[20];	//姓名char sex[10];	//性别int age;		//年龄char addr[40];	//地址char tel[20];	//电话
};
//结构体——通讯录
typedef struct contact
{struct peo Peo[contact_num];	//通讯录中联系人的信息int sz;							//当前存放联系人的个数
}contact;void Init_Contact(contact* pc);	//初始化通讯录
void Add(contact* Contact);		//添加联系人
void Show(const contact* Contact);	//展示联系人
void Search(const contact* Contact);	//搜索联系人
void Del(contact* Contact);		//删除联系人
void Modify(contact* Contact);	//修改联系人
void sort(contact* Contact,contact* tmp);	//排序联系人——年龄//contact.c
#include "contact.h"//Init_Contact——初始化通讯录void Init_Contact(contact* pc)
{pc->sz = 0;memset(pc, 0, sizeof(pc->Peo));
}//Add——增加联系人void Add(contact* Contact){assert(Contact);if (Contact->sz < contact_num){printf("请输入联系人的姓名:>\n");scanf("%s", (Contact->Peo[Contact->sz]).name);printf("请输入联系人的性别:>\n");scanf("%s", Contact->Peo[Contact->sz].sex);printf("请输入联系人的年龄:>\n");scanf("%d", &(Contact->Peo[Contact->sz].age));printf("请输入联系人的地址:>\n");scanf("%s", Contact->Peo[Contact->sz].addr);printf("请输入联系人的电话:>\n");scanf("%s", Contact->Peo[Contact->sz].tel);Contact->sz++;}elseprintf("通讯录已满无法添加\n");}//Show——展示联系人void Show( const contact* Contact){assert(Contact);int pos = 0;printf("%-10s\t%-6s\t%-4s\t%-40s\t%-20s\n","姓名", "性别", "年龄", "地址", "电话");for (pos = 0; pos < Contact->sz; pos++){printf("%-10s\t%-6s\t%-4d%\t%-40s\t%-20s\n", Contact->Peo[pos].name,Contact->Peo[pos].sex,Contact->Peo[pos].age,Contact->Peo[pos].addr,Contact->Peo[pos].tel);}}//Find_by_name——通过姓名,找到联系人所对应的下标int Find_by_name( const contact* Contact, char *name){int i = 0;for (i = 0; i < Contact->sz; i++){if (strcmp(&(Contact->Peo[i].name),name)==0)return i;}return -1;}//Search——搜索联系人void Search(const contact* Contact){char name[20] = {0};printf("请输入要寻找的联系人:>");scanf("%s", name);int pos= Find_by_name(Contact, &name);if (-1==pos){printf("该联系人不存在\n");return;}else{printf("%-10s\t%-6s\t%-4s\t%-40s\t%-20s\n", "姓名", "性别", "年龄", "地址", "电话");printf("%-10s\t%-6s\t%-4d%\t%-40s\t%-20s\n", Contact->Peo[pos].name,Contact->Peo[pos].sex,Contact->Peo[pos].age,Contact->Peo[pos].addr,Contact->Peo[pos].tel);} }//Del——删除联系人void Del(contact* Contact){char name[20] = { 0 };int i = 0;printf("请输入要删除的联系人:>");scanf("%s", name);int pos = Find_by_name(Contact, &name);if (-1 == pos){printf("该联系人不存在\n");return;}else{for (i = pos; i < Contact->sz-1; i++){Contact->Peo[i] = Contact->Peo[i + 1];}Contact->sz--;}}//Modify——修改联系人void Modify(contact* Contact){assert(Contact);char name[20] = { 0 };printf("请输入要修改的联系人\n");scanf("%s", name);int pos = Find_by_name(Contact, &name);if (-1 == pos){printf("该联系人不存在\n");return;}else{printf("请输入联系人的姓名:>\n");scanf("%s", (Contact->Peo[pos]).name);printf("请输入联系人的性别:>\n");scanf("%s", Contact->Peo[pos].sex);printf("请输入联系人的年龄:>\n");scanf("%d", &(Contact->Peo[pos].age));printf("请输入联系人的地址:>\n");scanf("%s", Contact->Peo[pos].addr);printf("请输入联系人的电话:>\n");scanf("%s", Contact->Peo[pos].tel);}}//sort——按照年龄对联系人进行排序void sort(contact* Contact,contact* tmp){//执行冒泡排序的趟数int i = 0;for (i = 0; i < Contact->sz - 1; i++){//一趟冒泡排序中交换的次数int j = 0;for (j = 0; j < Contact->sz - 1-i; j++){if (Contact->Peo[j].age > Contact->Peo[j + 1].age){tmp->Peo[0] = Contact->Peo[j];Contact->Peo[j] = Contact->Peo[j + 1];Contact->Peo[j + 1] = tmp->Peo[0];}}}}

 三、结语

        关于通讯录的讲解就已经全部结束了,下期我们会分享自定义类型的其他成员!

        关注我 _麦麦_分享更多干货:_麦麦_的博客_CSDN博客-领域博主
        大家的「关注❤️ + 点赞👍 + 收藏⭐」就是我创作的最大动力!谢谢大家的支持,我们下期见!

相关文章:

C语言进阶——通讯录模拟实现

&#x1f307;个人主页&#xff1a;_麦麦_ &#x1f4da;今日名言&#xff1a;只有走在路上&#xff0c;才能摆脱局限&#xff0c;摆脱执着&#xff0c;让所有的选择&#xff0c;探寻&#xff0c;猜测&#xff0c;想象都生机勃勃。——余秋雨《文化苦旅》 目录 一、前言 二、正…...

【C#基础】C# 变量和常量的使用

序号系列文章1【C#基础】C# 程序通用结构总结2【C#基础】C# 程序基础语法解析3【C#基础】C# 数据类型总结文章目录前言一. 变量&#xff08;variable&#xff09;1&#xff0c;变量定义及初始化2&#xff0c;变量的类别3&#xff0c;接收输出变量二. 常量&#xff08;constant&…...

nvm安装后出现‘node‘ 不是内部或外部命令,也不是可运行的程序 或批处理文件

出现这个问题多半是path地址不对。 打开系统环境变量。看看path里面有没有&#xff1f;没有的话&#xff0c;加上就行&#xff01; 我的报错原因就是因为path里没有自动加上nvm的相关路径。 注意项&#xff1a; 1&#xff0c;在安装nvm之前&#xff0c;提前要把本机以前安装…...

张驰咨询:关于六西格玛,有一些常见的疑惑!

​ 很多想要学习六西格玛的学员&#xff0c;经常会有这些困惑&#xff1a; 以前没有接触过六西格玛&#xff0c;需要什么基础吗&#xff1f;自学还是培训&#xff1f;哪些行业会用到六西格玛呢&#xff1f;学习六西格玛对以后的工作有哪些帮助&#xff1f;如何选择六西格玛培…...

【Vercel】教你部署imsyy/home个人主页

本篇博客教你如何部署一个自己的个人主页 项目地址&#xff1a;https://github.com/imsyy/home 本文首发于 慕雪的寒舍 1.fork仓库vercel部署 首先我们点击fork&#xff0c;将仓库复刻到自己的账户 随后进入vercel&#xff0c;点击dashboard-add new-project 选择你复刻的仓库…...

GeekChallenge

2.GeekChallenge 1.web 1.朋友的学妹 url&#xff1a;http://49.234.224.119:7413/ 右键点击查看源码&#xff0c;找到flagU1lDe0YxQF80c19oNExwZnVsbGxsbGx9 然后base64解码得到SYC{F1_4s_h4Lpfullllll} 2.EZwww url&#xff1a;http://47.100.46.169:3901/ 根据网站提示…...

Java文件IO

文章目录Java中的文件操作File常用构造方法方法文件内容的读写——数据流InputStreamFileInputStream利用Scanner进行字符读取OutputStreamPrintWriter按字符读取文件(FileReader)练习代码实例如何按字节进行数据读如何按字节进行数据写如何按字符进行数据读如何按字符进行数据…...

useSSL使用安全套接字协议(史上最全最详细)

useSSL使用安全套接字协议&#xff08;史上最全最详细&#xff09; SSL即为&#xff1a;Secure Sockets Layer 安全套接字协议。 useSSLfalse和useSSLtrue的区别&#xff1a; 在MySQL进行连接时&#xff1a; 如果MySQL的版本是5.7之后的版本必须要加上useSSLfalse&#xff0c…...

面向对象复习(2)

面向对象(2) 对象与引用 java语言中除基本类型之外的变量都称之为引用类型 java中的对象时通过引用对其操作的 Car bm new Car(); 右边的new Car是以Car类为模板,调用无参构造函数,在堆空间中创建一个Car对象 左边的Car bm 在栈中创建了一个Car类型的引用变量,所谓Car的…...

python中使用numpy包的向量矩阵相乘

一直对np的线性运算不太清晰&#xff0c;正好上课讲到了&#xff0c;做一个笔记整个理解一下 1.向量和矩阵 在numpy中&#xff0c;一重方括号表示的是向量vector&#xff0c;vector没有行列的概念。二重方括号表示矩阵matrix&#xff0c;有行列。 代码显示如下&#xff1a; …...

ElasticSearch 学习(一)

目录一、Elasticsearch 简介二、Elasticsearch 发展史三、Elasticsearch 功能四、Elasticsearch 特点五、Elasticsearch 应用场景一、Elasticsearch 简介 Elasticsearch 是一个实时的分布式搜索分析引擎&#xff0c;它能让你以前所未有的速度和规模&#xff0c;去探索你的数据…...

【新】华为OD机试 - 交换字符(Python)| 刷完获取OD招聘渠道

交换字符 题目 给定一个字符串 S 变化规则: 交换字符串中任意两个不同位置的字符 M S 都是小写字符组成 1 <= S.length <= 1000 输入 一串小写字母组成的字符串 输出 按照要求变换得到最小字符串 示例一 输入 abcdef输出 abcdef示例二 输入 bcdefa输出 acde…...

手把手教你解决传说中的NPE空指针异常

1. 前言最近有好几个初学java的小伙伴&#xff0c;甚至是学习到了JavaWeb、框架阶段的小伙伴也跑来问壹哥&#xff0c;该如何解决Java中的NullPointerException空指针异常。因为NPE是初学者特别常见的典型异常&#xff0c;所以壹哥在这里专门写一篇文章&#xff0c;来手把手地教…...

【pytorch安装】conda安装pytorch无法安装cpu版本(完整解决过程)

问题描述 在安装pytorch过程中&#xff0c;发现最后验证torch时总是返回结果为False&#xff0c;结果翻上去发现自己安装的是cpu版本的。 然后又通过conda去更换不同版本尝试&#xff0c;发现都是cpu版本的。 问题分析 通过conda安装pytorch是从源中搜索匹配指令中的文件&am…...

云计算ACP云服务器ECS实例题库

&#x1f618;作者简介&#xff1a;一名99年软件运维应届毕业生&#xff0c;正在自学云计算课程。&#x1f44a;宣言&#xff1a;人生就是B&#xff08;birth&#xff09;和D&#xff08;death&#xff09;之间的C&#xff08;choise&#xff09;&#xff0c;做好每一个选择。&…...

面试题:作用域、变量提升、块级作用域、函数作用域、暂存性死区、var和let的区别

<script>var a 10;(function () {console.log(a)a 5console.log(window.a)var a 20;console.log(a)})() </script> 上述代码&#xff1a; 1、主要是涉及到变量提升和函数作用域&#xff0c;var a20这行代码会在函数作用域中提升var a 至最顶部&#xf…...

JAVA练习49-爬楼梯

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 目录 前言 一、题目-爬楼梯 1.题目描述 2.思路与代码 2.1 思路 2.2 代码 总结 前言 提示&#xff1a;这里可以添加本文要记录的大概内容&#xff1a; 2月13日练习内容…...

深兰科技机器人商丘制造基地正式投产,助力商丘经济高质量发展

2月9日&#xff0c;深兰科技机器人商丘制造基地投产仪式在商丘市梁园区北航创新园隆重举行。商丘市人大常委会副主任、梁园区委书记张兵&#xff0c;梁园区区长薛天江、河南省装备制造业协会会长张桦&#xff0c;河南省机器人行业协会会长王济昌&#xff0c;深兰科技集团董事长…...

ES倒排索引/查询、写入流程

ES学习笔记 Elasticsearch学习笔记_巨輪的博客-CSDN博客 Elasticsearch学习之图解Elasticsearch中的_source、_all、store和index属性_BUse的博客-CSDN博客 倒排索引 倒排索引&#xff1a;ES倒排索引底层原理及FST算法的实现过程_es fst_Elastic开源社区的博客-CSDN博客 【…...

2023软考考哪个证书好?

软考有三个级别&#xff08;初级&#xff0c;中级和高级&#xff09;&#xff0c;这三个级别分别对应5个方向&#xff0c;下面这张图片呢&#xff0c;可以一目了然&#xff0c;一些小小建议&#xff01;&#xff01;&#xff01;遵循一个原则&#xff1a;首先选专业对口的科目&…...

【WiFi帧结构】

文章目录 帧结构MAC头部管理帧 帧结构 Wi-Fi的帧分为三部分组成&#xff1a;MAC头部frame bodyFCS&#xff0c;其中MAC是固定格式的&#xff0c;frame body是可变长度。 MAC头部有frame control&#xff0c;duration&#xff0c;address1&#xff0c;address2&#xff0c;addre…...

汽车生产虚拟实训中的技能提升与生产优化​

在制造业蓬勃发展的大背景下&#xff0c;虚拟教学实训宛如一颗璀璨的新星&#xff0c;正发挥着不可或缺且日益凸显的关键作用&#xff0c;源源不断地为企业的稳健前行与创新发展注入磅礴强大的动力。就以汽车制造企业这一极具代表性的行业主体为例&#xff0c;汽车生产线上各类…...

ESP32 I2S音频总线学习笔记(四): INMP441采集音频并实时播放

简介 前面两期文章我们介绍了I2S的读取和写入&#xff0c;一个是通过INMP441麦克风模块采集音频&#xff0c;一个是通过PCM5102A模块播放音频&#xff0c;那如果我们将两者结合起来&#xff0c;将麦克风采集到的音频通过PCM5102A播放&#xff0c;是不是就可以做一个扩音器了呢…...

CMake控制VS2022项目文件分组

我们可以通过 CMake 控制源文件的组织结构,使它们在 VS 解决方案资源管理器中以“组”(Filter)的形式进行分类展示。 🎯 目标 通过 CMake 脚本将 .cpp、.h 等源文件分组显示在 Visual Studio 2022 的解决方案资源管理器中。 ✅ 支持的方法汇总(共4种) 方法描述是否推荐…...

JS手写代码篇----使用Promise封装AJAX请求

15、使用Promise封装AJAX请求 promise就有reject和resolve了&#xff0c;就不必写成功和失败的回调函数了 const BASEURL ./手写ajax/test.jsonfunction promiseAjax() {return new Promise((resolve, reject) > {const xhr new XMLHttpRequest();xhr.open("get&quo…...

k8s从入门到放弃之HPA控制器

k8s从入门到放弃之HPA控制器 Kubernetes中的Horizontal Pod Autoscaler (HPA)控制器是一种用于自动扩展部署、副本集或复制控制器中Pod数量的机制。它可以根据观察到的CPU利用率&#xff08;或其他自定义指标&#xff09;来调整这些对象的规模&#xff0c;从而帮助应用程序在负…...

TCP/IP 网络编程 | 服务端 客户端的封装

设计模式 文章目录 设计模式一、socket.h 接口&#xff08;interface&#xff09;二、socket.cpp 实现&#xff08;implementation&#xff09;三、server.cpp 使用封装&#xff08;main 函数&#xff09;四、client.cpp 使用封装&#xff08;main 函数&#xff09;五、退出方法…...

EasyRTC音视频实时通话功能在WebRTC与智能硬件整合中的应用与优势

一、WebRTC与智能硬件整合趋势​ 随着物联网和实时通信需求的爆发式增长&#xff0c;WebRTC作为开源实时通信技术&#xff0c;为浏览器与移动应用提供免插件的音视频通信能力&#xff0c;在智能硬件领域的融合应用已成必然趋势。智能硬件不再局限于单一功能&#xff0c;对实时…...

Linux实现线程同步的方式有哪些?

什么是线程同步&#xff1f; 想象一下超市收银台&#xff1a;如果所有顾客&#xff08;线程&#xff09;同时挤向同一个收银台&#xff08;共享资源&#xff09;&#xff0c;场面会一片混乱。线程同步就是给顾客们发"排队号码牌"&#xff0c;确保&#xff1a; 有序访…...

React 样式方案与状态方案初探

React 本身只提供了基础 UI 层开发范式&#xff0c;其他特性的支持需要借助相关社区方案实现。本文将介绍 React 应用体系中样式方案与状态方案的主流选择&#xff0c;帮助开发者根据项目需求做出合适的选择。 1. React 样式方案 1.1. 内联样式 (Inline Styles) 通过 style …...