c语言:通讯录管理系统(动态分配内存版)

        前言:在大多数高校内,都是通过设计一个通讯录管理系统来作为c语言课程设计,通过一个具体的系统设计将我们学习过的结构体和函数等知识糅合起来,可以很好的锻炼学生的编程思维,本文旨在为通讯录管理系统的设计提供思路和示例讲解,并且对如何动态的分配内存空间使得程序更高效的运行进行了讲解

  

        本文是在基础的通讯录管理系统上进行改进(文末有完整代码,欢迎大家使用),如果对于基础的通讯录管理系统有什么不懂的地方,可以参考笔者的上一篇文章,里面有详细的万字解读:

c语言:通讯录管理系统(增删查改)

目录

一.基础静态版本 (改进前)

头文件部分

函数实现部分

主函数部分

二.结构体的更改

三.扩容的设计

四.释放空间

五.最终完整代码 (改进后)

头文件部分

函数的实现部分 

主函数部分


一.基础静态版本 (改进前)

这里我们给出基础版本的代码,然后本文后续内容都是基于此进行改进

我们分为 3 个文件来设计:

  • Contact.h: 包含头文件的声明,对函数的声明,以及宏的申明
  • Contact.cpp: 通讯录管理系统中具体每一个函数的实现
  • test.cpp: 主函数,根据用户的选择进行调用相应的函数

头文件部分(Contact.h

#pragma once
#include<stdio.h>
#include<assert.h>
#include<string.h>#define Name_Max 20
#define Tel_Number 12
#define Sex_Max 5
#define Address_Max 30
#define Contact_Max 100//联系人结构体
typedef struct PeopleInformation
{char name[Name_Max];char telnumber[Tel_Number];int age;char sex[Sex_Max];char address[Address_Max];
}PeoInfor;//通讯录结构体
typedef struct Contact
{PeoInfor data[Contact_Max];//结构体数组存放联系人结构体int size;//记录当前通讯录中有多少个联系人
}Contact;//目录
void menu();//初始化通讯录
void InitContact(Contact* cp);//增加联系人
void AddContact(Contact* cp);//删除联系人
void DelContact(Contact* cp);//通过姓名进行查找联系人
int FindPeople(Contact* cp, char name[]);//展示全部通讯录信息
void ShowContact(const Contact* cp);//查询联系人
void SeachPeople(Contact* cp);//修改联系人信息
void ModifyContact(Contact* cp);

函数实现部分(Contact.cpp

#define _CRT_SECURE_NO_WARNINGS 1
#include "Contact.h"void menu()
{printf("\n");printf("-----------------------------\n");printf("---   1.添加联系人      -----\n");printf("---   2.删除联系人      -----\n");printf("---   3.查找联系人      -----\n");printf("---   4.修改联系人信息  -----\n");printf("---   5.显示全部信息    -----\n");printf("---   0.退出通讯录      -----\n");printf("-----------------------------\n");
}//初始化通讯录
void InitContact(Contact* cp)
{//判断非空assert(cp);cp->size = 0;memset(cp->data, 0, sizeof(cp->data));
}//增加联系人
void AddContact(Contact* cp)
{//判断非空assert(cp);//判断未满if (cp->size == Contact_Max){printf("通讯录已满,无法再添加新的联系人\n");return;}printf("请输入要添加的联系人的姓名:\n");scanf("%s", cp->data[cp->size].name);printf("请输入要添加的联系人的电话号:\n");scanf("%s", cp->data[cp->size].telnumber);printf("请输入要添加的联系人的年龄:\n");scanf("%d", &(cp->data[cp->size].age));printf("请输入要添加的联系人的性别:\n");scanf("%s", cp->data[cp->size].sex);printf("请输入要添加的联系人的住址:\n");scanf("%s", cp->data[cp->size].address);cp->size++;printf("添加成功\n");
}//通过姓名进行查找联系人
int FindPeople(Contact* cp, char name[])
{assert(cp);for (int i = 0; i < cp->size; i++){if (strcmp(cp->data[i].name, name) == 0){return i;}}return -1;
}//删除联系人
void DelContact(Contact* cp)
{assert(cp);char name[Name_Max];if (cp->size == 0){printf("通讯录为空,无需删除\n");return;}printf("请输入选择删除的联系人的姓名:\n");scanf("%s", name);int ret = FindPeople(cp, name);if (ret == -1){printf("要删除的联系人不存在\n");return;}for (int i = ret; i < cp->size-1 ; i++){cp->data[i] = cp->data[i + 1];}cp->size--;printf("删除成功\n");
}//查询联系人
void SeachPeople(Contact* cp)
{assert(cp);char name[Name_Max];if (cp->size == 0){printf("通讯录为空\n");return;}printf("请输入选择查找的联系人的姓名:\n");scanf("%s", name);int ret = FindPeople(cp, name);if (ret == -1){printf("要查找的联系人不存在\n");return;}//名字  年龄  性别    电话    地址//xxx   xxx    xxx    xxx     xxxprintf("%-10s%-5s%-5s%-12s%-30s\n", "名字", "年龄", "性别", "电话", "地址");//打印个人的信息printf("%-10s%-5d%-5s%-12s%-30s\n", cp->data[ret].name, cp->data[ret].age, cp->data[ret].sex, cp->data[ret].telnumber, cp->data[ret].address);
}//展示全部通讯录信息
void ShowContact(const Contact* cp)
{assert(cp);if (cp->size == 0){printf("通讯录为空\n");return;}//名字  年龄  性别    电话    地址//xxx   xxx    xxx    xxx     xxxprintf("%-10s%-5s%-5s%-12s%-30s\n", "名字", "年龄", "性别", "电话", "地址");for (int i = 0; i < cp->size; i++){//打印每个人的信息printf("%-10s%-5d%-5s%-12s%-30s\n",cp->data[i].name, cp->data[i].age, cp->data[i].sex, cp->data[i].telnumber, cp->data[i].address);}
}//修改联系人信息
void ModifyContact(Contact* cp)
{assert(cp);char name[Name_Max];if (cp->size == 0){printf("通讯录为空\n");return;}printf("请输入选择修改的联系人的姓名:\n");scanf("%s", name);int ret = FindPeople(cp, name);if (ret == -1){printf("要修改的联系人信息不存在\n");return;}printf("请输入要修改的联系人的姓名:\n");scanf("%s", cp->data[ret].name);printf("请输入要修改的联系人的电话号:\n");scanf("%s", cp->data[ret].telnumber);printf("请输入要修改的联系人的年龄:\n");scanf("%d", &(cp->data[ret].age));printf("请输入要修改的联系人的性别:\n");scanf("%s", cp->data[ret].sex);printf("请输入要修改的联系人的住址:\n");scanf("%s", cp->data[ret].address);printf("修改成功\n");
}

主函数部分(test.cpp

#define _CRT_SECURE_NO_WARNINGS 1
#include "Contact.h"//枚举,增加程序的可读性
enum options
{EXIT,ADD,DEL,SEACH,MODIFY,SHOW
};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 SEACH:SeachPeople(&con);break;//修改某个联系人的信息case MODIFY:ModifyContact(&con);break;//展示通讯录内的每一个联系人的信息case SHOW:ShowContact(&con);break;//退出通讯录管理系统case EXIT:printf("通讯录已退出\n");break;//预防非法输入default:printf("输入错误,请重新输入\n");break;}}while(input);return 0;
}

二.结构体的更改

        动态的分配内存就意味着通讯录这个结构体要动态的分配内存,根据通讯录内的信息进行分配,所以我们在这里对于通讯录结构体进行更改

//通讯录结构体
typedef struct Contact
{PeoInfor* data;//结构体数组存放联系人结构体int size;//记录当前通讯录中有多少个联系人int capacity;//记录当前存放的容量
}Contact;
  •         在这里我们将 data 从一个结构体数组改成了结构体指针,然后后续再使用 这个指针指向我们动态开辟的内存就完成了我们的需求设计
  •         并且新增了个变量 capacity 用来记录当前通讯录内的最大容量,当联系人的数量和容量相同的时候,也就是通讯录满容的时候,我们再使用 realloc 重新分配新的内存空间

三.扩容的设计

        我们封装一个函数方便我们添加新的联系人的时候进行扩容,先判断当前通讯录是否已满,如果满了就进行扩容,每一次扩容扩展 2 个联系人结构体的大小

  •         首先是判断部分,当当前通讯录的容量等于通讯录内实际存放的数据的大小的时候,我们就判定为通讯录已满,然后我们使用 realloc 开辟新的空间,比之前大 2 个联系人结构体的大小
  •         为了程序的健全性,我们也要判断开辟空间是否成功,如果成功就通过 ptr指针 指向联系人的数据部分,用 data 接收,如果开辟失败,我们就打印报错信息
void CheckContact(Contact* cp)
{if (cp->size == cp->capacity){PeoInfor* ptr = (PeoInfor*)realloc(cp->data, (cp->capacity + 2) * sizeof(PeoInfor));if (ptr != NULL){cp->data = ptr;cp->capacity += 2;printf("增容成功\n");}else{perror("AddContact->realloc");return;}}
}

四.释放空间

        由程序员申请开辟的空间也应当由程序员设置进行释放,在这个通讯录管理系统中也是如此,我们需要找到合适的释放位置,也就是当用户退出通讯录的时候,我们手动进行对开辟的空间进行释放,以避免造成内存泄漏

        那我们这里就封装一个释放空间的函数:

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

五.最终完整代码 (改进后)

头文件部分(Contact.h:

#pragma once
#pragma once
#include<stdio.h>
#include<assert.h>
#include<string.h>
#include<stdlib.h>#define Name_Max 20
#define Tel_Number 12
#define Sex_Max 5
#define Address_Max 30
#define Contact_Max 100
#define Contact_SZ 3//联系人结构体
typedef struct PeopleInformation
{char name[Name_Max];char telnumber[Tel_Number];int age;char sex[Sex_Max];char address[Address_Max];
}PeoInfor;//通讯录结构体
typedef struct Contact
{PeoInfor* data;//结构体数组存放联系人结构体int size;//记录当前通讯录中有多少个联系人int capacity;//记录当前存放的容量
}Contact;//目录
void menu();//初始化通讯录
void InitContact(Contact* cp);//增加联系人
void AddContact(Contact* cp);//删除联系人
void DelContact(Contact* cp);//通过姓名进行查找联系人
int FindPeople(Contact* cp, char name[]);//展示全部通讯录信息
void ShowContact(const Contact* cp);//查询联系人
void SeachPeople(Contact* cp);//修改联系人信息
void ModifyContact(Contact* cp);//扩容
void CheckContact(Contact* cp);//销毁通讯录
void DestoryContact(Contact* cp);

函数的实现部分 (Contact.cpp

#define _CRT_SECURE_NO_WARNINGS 1
#include "Contact.h"void menu()
{printf("\n");printf("-----------------------------\n");printf("---   1.添加联系人      -----\n");printf("---   2.删除联系人      -----\n");printf("---   3.查找联系人      -----\n");printf("---   4.修改联系人信息  -----\n");printf("---   5.显示全部信息    -----\n");printf("---   0.退出通讯录      -----\n");printf("-----------------------------\n");
}//初始化通讯录
void InitContact(Contact* cp)
{//判断非空assert(cp);cp->size = 0;cp->capacity = Contact_SZ;cp->data =(PeoInfor*)calloc(cp->capacity, sizeof(PeoInfor));if (cp->data == NULL){perror("InitContact->calloc");return;}
}void CheckContact(Contact* cp)
{if (cp->size == cp->capacity){PeoInfor* ptr = (PeoInfor*)realloc(cp->data, (cp->capacity + 2) * sizeof(PeoInfor));if (ptr != NULL){cp->data = ptr;cp->capacity += 2;printf("增容成功\n");}else{perror("AddContact->realloc");return;}}
}//增加联系人
void AddContact(Contact* cp)
{//判断非空assert(cp);//判断满后扩容CheckContact(cp);printf("请输入要添加的联系人的姓名:\n");scanf("%s", cp->data[cp->size].name);printf("请输入要添加的联系人的电话号:\n");scanf("%s", cp->data[cp->size].telnumber);printf("请输入要添加的联系人的年龄:\n");scanf("%d", &(cp->data[cp->size].age));printf("请输入要添加的联系人的性别:\n");scanf("%s", cp->data[cp->size].sex);printf("请输入要添加的联系人的住址:\n");scanf("%s", cp->data[cp->size].address);cp->size++;printf("添加成功\n");
}//通过姓名进行查找联系人
int FindPeople(Contact* cp, char name[])
{assert(cp);for (int i = 0; i < cp->size; i++){if (strcmp(cp->data[i].name, name) == 0){return i;}}return -1;
}//删除联系人
void DelContact(Contact* cp)
{assert(cp);char name[Name_Max];if (cp->size == 0){printf("通讯录为空,无需删除\n");return;}printf("请输入选择删除的联系人的姓名:\n");scanf("%s", name);int ret = FindPeople(cp, name);if (ret == -1){printf("要删除的联系人不存在\n");return;}for (int i = ret; i < cp->size - 1; i++){cp->data[i] = cp->data[i + 1];}cp->size--;printf("删除成功\n");
}//查询联系人
void SeachPeople(Contact* cp)
{assert(cp);char name[Name_Max];if (cp->size == 0){printf("通讯录为空\n");return;}printf("请输入选择查找的联系人的姓名:\n");scanf("%s", name);int ret = FindPeople(cp, name);if (ret == -1){printf("要查找的联系人不存在\n");return;}//名字  年龄  性别    电话    地址//xxx   xxx    xxx    xxx     xxxprintf("%-10s%-5s%-5s%-12s%-30s\n", "名字", "年龄", "性别", "电话", "地址");//打印个人的信息printf("%-10s%-5d%-5s%-12s%-30s\n", cp->data[ret].name, cp->data[ret].age, cp->data[ret].sex, cp->data[ret].telnumber, cp->data[ret].address);
}//展示全部通讯录信息
void ShowContact(const Contact* cp)
{assert(cp);if (cp->size == 0){printf("通讯录为空\n");return;}//名字  年龄  性别    电话    地址//xxx   xxx    xxx    xxx     xxxprintf("%-10s%-5s%-5s%-12s%-30s\n", "名字", "年龄", "性别", "电话", "地址");for (int i = 0; i < cp->size; i++){//打印每个人的信息printf("%-10s%-5d%-5s%-12s%-30s\n", cp->data[i].name, cp->data[i].age, cp->data[i].sex, cp->data[i].telnumber, cp->data[i].address);}
}//修改联系人信息
void ModifyContact(Contact* cp)
{assert(cp);char name[Name_Max];if (cp->size == 0){printf("通讯录为空\n");return;}printf("请输入选择修改的联系人的姓名:\n");scanf("%s", name);int ret = FindPeople(cp, name);if (ret == -1){printf("要修改的联系人信息不存在\n");return;}printf("请输入要修改的联系人的姓名:\n");scanf("%s", cp->data[ret].name);printf("请输入要修改的联系人的电话号:\n");scanf("%s", cp->data[ret].telnumber);printf("请输入要修改的联系人的年龄:\n");scanf("%d", &(cp->data[ret].age));printf("请输入要修改的联系人的性别:\n");scanf("%s", cp->data[ret].sex);printf("请输入要修改的联系人的住址:\n");scanf("%s", cp->data[ret].address);printf("修改成功\n");
}//销毁通讯录
void DestoryContact(Contact* cp)
{free(cp->data);cp->data = NULL;cp->size = 0;cp->capacity = 0;
}

主函数部分(test.cpp

#define _CRT_SECURE_NO_WARNINGS 1
#include "Contact.h"//枚举,增加程序的可读性
enum options
{EXIT,ADD,DEL,SEACH,MODIFY,SHOW
};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 SEACH:SeachPeople(&con);break;//修改某个联系人的信息case MODIFY:ModifyContact(&con);break;//展示通讯录内的每一个联系人的信息case SHOW:ShowContact(&con);break;//退出通讯录管理系统case EXIT:DestoryContact(&con);printf("通讯录已退出\n");break;//预防非法输入default:printf("输入错误,请重新输入\n");break;}} while (input);return 0;
}

本次分享就到此为止了,感谢您的支持,如有错误,欢迎积极指正

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

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

相关文章

2018架构真题案例(四十九)

某文件采用多级索引结构&#xff0c;磁盘大小4K字节&#xff0c;每个块号4字节&#xff0c;那么二级索引结果时&#xff0c;文件最大。 A、1024 B、1024*1024 C、2048*2048 D、4096*4096 答案&#xff1a;B 霍尔三维结构以时间堆、&#xff08;&#xff09;堆、知识堆组成…

R语言实现向量自回归和误差修正模型——附实战代码

大家好&#xff0c;我是带我去滑雪&#xff01; 向量自回归&#xff08;VAR&#xff09;模型和误差修正模型&#xff08;ECM&#xff09;是时间序列分析中常用的两种模型&#xff0c;它们用于研究多个变量之间的动态关系。VAR 模型适用于研究多个相关变量之间的相互影响和动态关…

二叉搜索树--验证二叉搜索树

验证二叉搜索树-力扣 98 题 解题思路&#xff1a;利用二叉树中序遍历的特性&#xff1a;遍历出来的结果是升序的即符合二叉搜索树 对于二叉树中序遍历不是太理解的&#xff0c;作者推荐的小白书&#xff1a;二叉树的初步认识_加瓦不加班的博客-CSDN博客 中序非递归实现 // 解…

剖析伦敦银最新价格走势图

国际金融市场瞬息万变&#xff0c;伦敦银的价格走势会受到诸多因素的影响&#xff0c;比如重要经济数据的公布&#xff0c;国际间的政治博弈&#xff0c;突发的政经大事&#xff0c;都可以令白银价格的走势&#xff0c;在短时间内暴涨暴跌的情况。 要在伦敦银市场实现良好的收益…

CCF CSP认证 历年题目自练Day27

题目一 试题编号&#xff1a; 202104-1 试题名称&#xff1a; 灰度直方图 时间限制&#xff1a; 1.0s 内存限制&#xff1a; 512.0MB 样例输入 7 11 8 0 7 0 0 0 7 0 0 7 7 0 7 0 7 0 7 0 7 0 7 0 7 7 0 0 0 7 0 0 0 7 0 7 7 0 0 0 0 7 0 0 7 7 0 7 0 0 0 0 0 7 0 7 0 0 7 0 …

Apache Doris (三十九):Doris数据导出 - MySQL dump导出

🏡 个人主页:IT贫道_大数据OLAP体系技术栈,Apache Doris,Clickhouse 技术-CSDN博客 🚩 私聊博主:加入大数据技术讨论群聊,获取更多大数据资料。 🔔 博主个人B栈地址:豹哥教你大数据的个人空间-豹哥教你大数据个人主页-哔哩哔哩视频 目录

解决Opencv dnn模块无法使用onnx模型的问题(将onnx的动态输入改成静态)

一、问题来源 最近做人脸识别项目&#xff0c;想只用OpenCV自带的人脸检测和识别模块实现&#xff0c;使用OpenCV传统方法&#xff1a;Haar级联分类器人脸检测LBPH算法人脸识别的教程已经有了&#xff0c;于是想着用OpenCV中的dnn模块来实现&#xff0c;dnn实现人脸检测也有&a…

在 centos7 上安装Docker

1、检查linux内核 Docker 运行在 CentOS 7 上&#xff0c;要求系统为64位、系统内核版本为 3.10 以上。 Docker 运行在 CentOS-6.5 或更高的版本的 CentOS 上&#xff0c;要求系统为64位、系统内核版本为 2.6.32-431 或者更高版本。 uname -r 2、使用 root 权限登录 Centos…

vue-5

一、文章内容概括 1.自定义指令 基本语法&#xff08;全局、局部注册&#xff09;指令的值v-loading的指令封装 2.插槽 默认插槽具名插槽作用域插槽 3.综合案例&#xff1a;商品列表 MyTag组件封装MyTable组件封装 4.路由入门 单页应用程序路由VueRouter的基本使用 二…

JavaScript Web APIs第六天笔记

Web APIs - 第6天笔记 目标&#xff1a;能够利用正则表达式完成小兔鲜注册页面的表单验证&#xff0c;具备常见的表单验证能力 正则表达式综合案例阶段案例 正则表达式 正则表达式&#xff08;Regular Expression&#xff09;是一种字符串匹配的模式&#xff08;规则&#xf…

33 WEB漏洞-逻辑越权之水平垂直越权全解

目录 前言水平&#xff0c;垂直越权&#xff0c;未授权访问Pikachu-本地水平垂直越权演示(漏洞成因)墨者水平-身份认证失效漏洞实战(漏洞成因)原理越权检测-Burpsuite插件Authz安装测试(插件使用)修复防御方案 前言 越权漏洞文章分享&#xff1a;https://www.cnblogs.com/zhen…

零基础Linux_14(基础IO_文件)缓冲区+文件系统inode等

目录 1. 缓冲区 1.1 缓冲区的存在 1.2 缓冲区的刷新策略 1.3 模拟C标准库中的文件操作 完整代码及验证&#xff1a; 1.4 重看缓冲区 1.5 stdout和stderr的区别 2. 文件系统 2.1 磁盘的物理结构CHS等 2.2 磁盘的抽象结构LBA等 2.3 文件管理inode等 2.4 对文件的操作…

QT5 WebCapture 页面定时截图工具

QT5 WebCapture 网页定时截图工具 1.设置启动时间&#xff0c;程序会到启动时间后开始对网页依次进行截图 2.根据所需截图的页面加载速度&#xff0c;设置页面等待时间&#xff0c;尽量达到等页面加载完成后&#xff0c;再执行截图 3.根据需求&#xff0c;设置截图周期 4.程序…

理解http中cookie!C/C++实现网络的HTTP cookie

HTTP嗅探&#xff08;HTTP Sniffing&#xff09;是一种网络监控技术&#xff0c;通过截获并分析网络上传输的HTTP数据包来获取敏感信息或进行攻击。其中&#xff0c;嗅探器&#xff08;Sniffer&#xff09;是一种用于嗅探HTTP流量的工具。 在HTTP嗅探中&#xff0c;cookie是一…

集成内部高端电源开关LTC3637HMSE、LTC3637MPMSE稳压器,TJA1443AT汽车CAN FD收发器。

一、LTC3637 76V、1A 降压型稳压器 &#xff08;简介&#xff09;LTC3637是一款高效率降压DC/DC稳压器&#xff0c;集成内部高端电源开关&#xff0c;功耗仅12μA DC&#xff0c;空载时可保持稳定的输出电压。LTC3637可提供高达1A的负载电流&#xff0c;并具有可编程峰值电流限…

php+html+js+ajax实现文件上传

phphtmljsajax实现文件上传 目录 一、表单单文件上传 1、上传页面 2、接受文件上传php 二、表单多文件上传 1、上传页面 2、接受文件上传php 三、表单异步xhr文件上传 1、上传页面 2、接受文件上传php 四、表单异步ajax文件上传 1、上传页面 2、接受文件上传ph…

PCL点云处理之点云重建为Mesh模型并保存到PLY文件 ---方法二 (二百一十一)

PCL点云处理之点云重建为Mesh模型并保存到PLY文件 ---方法二 (二百一十一) 一、算法介绍二、算法实现1.代码2.效果一、算法介绍 离散点云重建为mesh网格模型,并保存到PLY文件中,用于其他软件打开查看,代码非常简短,复制粘贴即可迅速上手使用,具体参数根据自己的点云数据…

【STM32单片机】防盗报警器设计

文章目录 一、功能简介二、软件设计三、实验现象联系作者 一、功能简介 本项目使用STM32F103C8T6单片机控制器&#xff0c;使用按键、动态数码管、蜂鸣器、指示灯、热释电人体红外传感器等。 主要功能&#xff1a; 系统运行后&#xff0c;默认处于布防状态&#xff0c;D1指示灯…

Web3 新手攻略:9 个不可或缺的 APP 助力你踏入加密领域

Web3世界充满了无限机遇&#xff0c;但要掌握它&#xff0c;您需要合适的工具&#xfffd;&#xfffd;&#xfffd;。今天&#xff0c;我将为您介绍9款Web3必备APP&#xff0c;涵盖钱包、DEX、和工具三大类别。而且&#xff0c;我要特别强烈推荐一个强大的钱包——Bitget Wall…

CAN 通信-底层

本文主要以rockchip的rk3568平台基础&#xff0c;介绍can 控制器、硬件电路和底层驱动。 rk3568 CAN 控制器 概览 CAN(控制器区域网络)总线是一种稳健的车载总线标准,它允许微控制器和设备在没有主机计算机的应用中相互通信。它是一个基于消息的协议,最初是为了在汽车中多路…