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

C++STL之vector(超详细)

C++STL之vector

  • 1.vector基本介绍
  • 2.vector重要接口
    • 2.1.构造函数
    • 2.2.迭代器
    • 2.3.空间
      • 2.3.1.resize
      • 2.3.2.capacity
    • 2.4.增删查找
  • 3.迭代器失效
  • 4.迭代器分类

🌟🌟hello,各位读者大大们你们好呀🌟🌟
🚀🚀系列专栏:【C++的学习】
📝📝本篇内容:vector基本介绍;vector重要接口:构造函数;迭代器;空间;增删查改;迭代器失效;迭代器分类
⬆⬆⬆⬆上一篇:C++IO流
💖💖作者简介:轩情吖,请多多指教(> •̀֊•́ ) ̖́-

1.vector基本介绍

① 在我们C语言中有数组,C++中因此也设计了array来代替C语言中的数组,但是它有一个缺点,就是array是静态空间,一旦配置了空间就无法改变,这就让使用者非常麻烦。但是vector就不一样,它是动态空间,一旦底层空间不足,就会自动扩容,压根不需要担心空间不足而造成问题。
②vector扩容:当新元素插入进来时,发现内存不足,这个时候就会先扩容开辟新的空间(并不是原地扩容,因为可能后面没有内存),然后把原来的数据拷贝过去,再进行插入,然后把旧的空间给释放掉。并且我们扩容的空间基本上是以倍数来增长的,保证后续再有元素插入时,不需要扩容,导致效率低下。
③vector支持随机访问,即像数组一样[ ]来访问,非常高效,同时在末尾删除和末尾插入元素非常高效,这得益于它的结构。但是其他的位置进行操作效率就会比较低下,没有list好

2.vector重要接口

☞vector参考文档

2.1.构造函数

对于任何容器,首先看的肯定是构造函数
在这里插入图片描述
讲一下其中比较重要的

vector构造函数
vector()默认构造函数
vector(const vector&)拷贝构造
vector(size_type n,const value_type&val)构造n个val
vector(InputIterator first, InputIterator last)使用迭代器构造
#include <vector>
#include <iostream>
using namespace std;
int main()
{vector<int> v1;//默认构造int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };vector<int> v2(arr, arr + 10);//使用迭代器来构造for (auto& e : v2){cout << e << " ";}cout << endl;vector<int> v3(2, 10);//构造2个为10的元素for (auto& e : v3){cout << e <<" ";}vector<int> v4(v3);//拷贝构造return 0;
}

在这里插入图片描述

2.2.迭代器

我们来看一下迭代器,迭代器就是迭代器是一种访问容器内元素的对象,它提供了一种方法来顺序访问容器中的各个元素,而不需要了解容器的内部工作原理。

vector迭代器iterator/reverse_iterator
begin+end正向迭代器
rbegin+rend反向迭代器
#include <iostream>
#include <vector>
using namespace std;
int main()
{int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };vector<int> v(arr, arr + 10);//使用迭代器//正向迭代器vector<int>::iterator it = v.begin();while (it != v.end())//end是最后一个元素的下一个位置{cout << *it <<' ';//像指针一样使用it++;}cout << endl;//反向迭代器vector<int>::reverse_iterator rit = v.rbegin();while (rit != v.rend()){cout << *rit << ' ';//像指针一样使用rit++;//这里是++,而不是--,因为已经说明是反向迭代器,就该使用++}return 0;
}

在这里插入图片描述

2.3.空间

vector空间
size_type size() const;获取数据个数
size_type capacity() const;获取vector的容量大小
bool empty() const;vector是否为空
void reserve (size_type n);提前开辟空间,只会改变vector的capacity,能够缓解vector增容代价问题
void resize (size_type n, value_type val = value_type());改变vector的size,可以变大也可以变小
#include <iostream>
#include <vector>
using namespace std;
int main()
{vector<int> v;//emptyif (v.empty()){cout << "empty" << endl;}cout << "------------------" << endl;//sizev.push_back(10);v.push_back(10);v.push_back(10);cout << v.size() << endl;cout << "------------------" << endl;//capacitycout << v.capacity() << endl;cout << "------------------" << endl;//reversev.reserve(10);//提前扩容到能存放10个元素的空间cout << v.size() << endl;//3,不会改变cout << v.capacity() << endl;//10cout << "------------------" << endl;//resizev.resize(20);cout << v.size() << endl;//20,改变size,元素为默认值cout << v.capacity() << endl;//20return 0;
}

在这里插入图片描述

2.3.1.resize

其中我们的resize还有其他的功能,可以缩小空间以及设定自己想要的元素,resize在开空间的同时还会进行初始化,影响size
具体演示见下面

#include <iostream>
#include <vector>
using namespace std;
int main()
{vector<int> v;v.push_back(10);v.push_back(11);v.push_back(12);v.push_back(13);v.push_back(14);cout <<"size:"<<v.size() << endl;for (auto& e : v){cout << e << " ";}cout << endl;cout << "---------------------" << endl;v.resize(3);cout << "size:" << v.size() << endl;for (auto& e : v){cout << e << " ";}cout << endl;cout << "---------------------" << endl;v.resize(10,33);//把7个元素都设置为33cout << "size:" << v.size() << endl;for (auto& e : v){cout << e << " ";}cout << endl;cout << "---------------------" << endl;return 0;
}

在这里插入图片描述

2.3.2.capacity

我们这边再详细讨论一下capacity这个成员函数,我们想一下,我们的vector的扩容是按照什么来的呢?需要空间就扩容?一个个扩容?我们来看一下下面的一段代码,分别在windows和Linux下展示

#include <iostream>
#include <vector>
using namespace std;
int main()
{vector<int> v;size_t cap = v.capacity();cout <<"initital capacity:"<< cap << endl;for (int i = 0; i < 100; i++){v.push_back(i);if (cap != v.capacity()){cap = v.capacity();cout << "capacity changed:" << cap << endl;}} return 0;
}

windows:
在这里插入图片描述

Linux:
在这里插入图片描述

capacity的代码在vs和g++下分别运行会发现,vs下capacity是按1.5倍增长的,g++是按2倍增长的。这个问题经常会考察,不要固化的认为,vector增容都是2倍,具体增长多少是根据具体的需求定义的。vs是PJ版本STL,g++是SGI版本STL。

我们还要注意下它的效率问题,如果我们提前知道需要多少空间,就可以提前扩容来保证一次的开辟空间,来避免多次扩容的效率低下

#include <iostream>
#include  <vector>
using namespace std;
int main()
{vector<int> v;v.reserve(100);//提前开辟好空间,防止一遍遍的扩容造成效率低下for (int i = 0; i < 100; i++){v.push_back(i);}cout << v.capacity() << endl;//100return 0;
}

2.4.增删查找

vector增删查改
void push_back (const value_type& val);尾插
void pop_back();尾删
InputIterator find (InputIterator first, InputIterator last, const T& val);这是算法中的,查找
iterator insert (iterator position, const value_type& val);在position前插入元素
void insert (iterator position, size_type n, const value_type& val);在position位置前插入n个val
iterator erase (iterator position);删除position位置的元素
iterator erase (const_iterator first, const_iterator last);删除迭代器范围的元素
void swap (vector& x);交换两个vector
reference operator[] (size_type n);像数组一样的访问
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
int main()
{vector<int> v(2, 10);v.push_back(11);//尾插v.push_back(12);v.push_back(13);v.push_back(14);cout << "initiatl element:";for (auto& e : v){cout << e << " ";}cout << endl;cout << "------------------------------------------------------" << endl;v.pop_back();//尾删cout << "after pop_back():";for (auto& e : v){cout << e << " ";}cout << endl;cout << "------------------------------------------------------" << endl;v.insert(v.begin(), 9);//在第一个元素前的位置插入一个9cout << "after insert(v.begin(),9):";for (auto& e : v){cout << e << " ";}cout << endl;cout << "------------------------------------------------------" << endl;//find && erasevector<int>::iterator it=find(v.begin(), v.end(),12);//查找元素为12的位置if (it != v.end()){//如果返回的迭代器为end()说明没找到v.erase(it);}cout << "after erase(it):";for (auto& e : v){cout << e << " ";}cout << endl;cout << "------------------------------------------------------" << endl;//operator[]for (int i = 0; i < v.size(); i++){v[i] = i;//operator[]的返回值是引用}cout << "after change element through operator[]:";for (auto& e : v){cout << e << " ";}cout << endl;cout << "------------------------------------------------------" << endl;return 0;
}

在这里插入图片描述

3.迭代器失效

接下来我们要谈谈迭代器失效的问题了,这个如果不了解底层的话就会很容易掉进坑里面
首先我们先讲insert导致的迭代器失效
在这里插入图片描述
在我们使用insert的时候,如果空间不足了,那我们的vector就会自动帮我们扩容,但是扩容常常需要经历三个步骤:开辟新的空间;移动元素到新空间;释放原来的空间。我们vector底层的实现的迭代器本身就是指针,只不过是typedef了一下。仔细想想,问题就来了,当我们插入后,有概率空间不足,扩容后,原本的迭代器(指针)就是野指针了,没有指向新空间

//!!!!error code
#include <iostream>
#include <vector>
using namespace std;
int main()
{vector<int> v;v.push_back(11);v.push_back(12);v.push_back(13);v.push_back(14);cout << v.capacity() << endl;//接下来再插入就会扩容	vector<int>::iterator it = v.begin();v.insert(it, 10);cout << v.capacity() << endl;cout << *it << endl;return 0;
}

上述代码就演示了这个情况,使用一块已经被释放的空间,造成的后果是程序崩溃,我们仅仅演示了一下insert造成的结果,其实其他会造成扩容的函数如resize,reverse,push_back都会造成迭代器失效,同时从另一个角度来说,我们所传入的迭代器position所指向的内容已经不是我们想要的了,这也是迭代器失效的一种情况,因此insert以后我们认为迭代器已经失效,不能再使用

下一种情况是erase,思考一下?erase会扩容吗?答案是并不会,只是删除元素,所以说就没问题了?不不不,仔细思考一下,我的迭代器此时指向最后一个元素,如果我erase了一个元素呢,我们底层的_finish指针就会–,那此时的迭代器就相等于是指向无效空间

//!!!!!error code
#include <iostream>
using namespace std;
#include <vector>
int main()
{int a[] = { 1, 2, 3, 4 };vector<int> v(a, a + sizeof(a) / sizeof(int));// 使用find查找3所在位置的iteratorvector<int>::iterator pos = find(v.begin(), v.end(), 3);// 删除pos位置的数据,导致pos迭代器失效。v.erase(pos);cout << *pos << endl; // 此处会导致非法访问return 0;
}

在这里插入图片描述

可以运行一下上面的代码分别在Linux和Windows下,在Windows下会崩溃,但是在Linux可以运行,这不得不说VS的检查非常严,erase后的迭代器是不允许使用的,但是g++的就会宽很多,当删除3后,元素4会往前移动,pos的位置还是有效的
接下来就看一下下面这个代码

#include <iostream>
#include <vector>
using namespace std;
int main()
{vector<int> v{1,2,3,4,5};//删除偶数vector<int>::iterator it = v.begin();while (it != v.end()){if ((*it) % 2 == 0){v.erase(it);}it++;}for (auto& e : v){cout << e << " ";}cout << endl;return 0;
}

首先对于环境而言是一样的,在VS下会崩溃,而Linux下能正常运行
在这里插入图片描述
在这里插入图片描述
我们来分析一下这个代码
在这里插入图片描述
可以发现,我们的it很巧合的把偶数元素删除了,同时也正好落到了_finish使用空间的尾end(),也判断循环结束了,我们接下里对代码稍作修改如下

#include <iostream>
#include <vector>
using namespace std;
int main()
{vector<int> v{ 1,2,3,4};//删除偶数vector<int>::iterator it = v.begin();while (it != v.end()){if ((*it) % 2 == 0){v.erase(it);}it++;}for (auto& e : v){cout << e << " ";}cout << endl;return 0;
}

我们的元素的数量变为只有四个,接下来再看一下它的执行逻辑
在这里插入图片描述
通过上面的图可以发现,我们的it直接和_finish(end())直接错过了,这样即使是Linux也无能为力了
在这里插入图片描述
直接发生段错误

从上述的例子中可以看到:SGI STL中,迭代器失效后,代码并不一定会崩溃,但是运行结果肯定不对,如果it不在begin和end范围内,肯定会崩溃的。
因此我们的insert和erase函数都会返回一个迭代器来供我们使用,我们修正一下上面的代码

#include <iostream>
#include <vector>
using namespace std;
int main()
{vector<int> v{ 1,2,3,4};//删除偶数vector<int>::iterator it = v.begin();while (it != v.end()){if ((*it) % 2 == 0){it=v.erase(it);//接受迭代器,返回的迭代器是it传入时的位置}else{it++;}}for (auto& e : v){cout << e << " ";}cout << endl;return 0;
}

我们的string其实也是一样的道理,只是对于string我们很少用迭代器
在这里插入图片描述
我们对str进行了提前扩容,造成了野指针问题,我们的string使用失效的迭代器也会崩溃

4.迭代器分类

在我们使用算法函数时,有些函数需要特定的迭代器,像我们的vector的迭代器本质就是原生指针,因此它是一个随机迭代器,我们可以看一下侯捷大佬的《STL源码剖析》里对迭代器的分类
在这里插入图片描述
在这里插入图片描述我们Forward迭代器就是单向迭代器,它是只支持重载++的迭代器,Bidrectional迭代器是双向迭代器,它支持++和–,而我们的Random是随机迭代器,它支持++和–,也支持+和-,同样支持[ ]
理论上来讲,模板语法上可以传任何类型参数,但是内部使用迭代器是有要求

🌸🌸C++STL之vector的知识大概就讲到这里啦,博主后续会继续更新更多C++的相关知识,干货满满,如果觉得博主写的还不错的话,希望各位小伙伴不要吝啬手中的三连哦!你们的支持是博主坚持创作的动力!💪💪

相关文章:

C++STL之vector(超详细)

CSTL之vector 1.vector基本介绍2.vector重要接口2.1.构造函数2.2.迭代器2.3.空间2.3.1.resize2.3.2.capacity 2.4.增删查找 3.迭代器失效4.迭代器分类 &#x1f31f;&#x1f31f;hello&#xff0c;各位读者大大们你们好呀&#x1f31f;&#x1f31f; &#x1f680;&#x1f68…...

ubuntu环境下安装electron环境,并快速打包

1.配置镜像源 关闭防火墙&#xff0c;命令&#xff1a;sudo ufw disable 1.1配置国内镜像源&#xff1a; vim /etc/apt/source.list deb https://mirrors.aliyun.com/ubuntu/ jammy main restricted universe multiversedeb-src https://mirrors.aliyun.com/ubuntu/ jammy main…...

【Pytorch】优化器(Optimizer)模块‘torch.optim’

torch.optim 是 PyTorch 中提供的优化器&#xff08;Optimizer&#xff09;模块&#xff0c;用于优化神经网络模型的参数&#xff0c;更新网络权重&#xff0c;使得模型在训练过程中最小化损失函数。它提供了多种常见的优化算法&#xff0c;如 梯度下降法&#xff08;SGD&#…...

API平台建设之路:从0到1的实践指南

在这个互联网蓬勃发展的时代&#xff0c;API已经成为连接各个系统、服务和应用的重要纽带。搭建一个优质的API平台不仅能为开发者提供便利&#xff0c;更能创造可观的商业价值。让我们一起探讨如何打造一个成功的API平台。 技术架构是API平台的根基。选择合适的技术栈对平台的…...

【Flink-scala】DataStream编程模型之窗口计算-触发器-驱逐器

DataStream API编程模型 1.【Flink-Scala】DataStream编程模型之数据源、数据转换、数据输出 2.【Flink-scala】DataStream编程模型之 窗口的划分-时间概念-窗口计算程序 文章目录 DataStream API编程模型前言1.触发器1.1 代码示例 2.驱逐器2.1 代码示例 总结 前言 本小节我想…...

信号灯集以及 P V 操作

一、信号灯集 1.1 信号灯集的概念 信号灯集是进程间同步的一种方式。 信号灯集创建后&#xff0c;在信号灯集内部会有很多个信号灯。 每个信号灯都可以理解为是一个信号量。 信号灯的编号是从0开始的。 比如A进程监视0号灯&#xff0c;B进程监视1号灯。 0号灯有资源&…...

在 Flutter app 中,通过视频 URL 下载视频到手机相册

在 Flutter app 中&#xff0c;通过视频 URL 下载视频到手机相册可以通过以下步骤实现&#xff1a; 1. 添加依赖 使用 dio 下载文件&#xff0c;结合 path_provider 获取临时存储路径&#xff0c;以及 gallery_saver 将文件保存到相册。 在 pubspec.yaml 中添加以下依赖&…...

Nature Methods | 人工智能在生物与医学研究中的应用

Nature Methods | 人工智能在生物与医学研究中的应用 生物研究中的深度学习 随着人工智能&#xff08;AI&#xff09;技术的迅速发展&#xff0c;尤其是深度学习和大规模预训练模型的出现&#xff0c;AI在生物学研究中的应用正在经历一场革命。从基因组学、单细胞组学到癌症生…...

Axure PR 9 随机函数 设计交互

​大家好&#xff0c;我是大明同学。 这期内容&#xff0c;我们将深入探讨Axure中随机函数的用法。 随机函数 创建随机函数所需的元件 1.打开一个新的 RP 文件并在画布上打开 Page 1。 2.在元件库中拖出一个矩形元件。 3.选中矩形元件&#xff0c;样式窗格中&#xff0c;将…...

【人工智能基础05】决策树模型

文章目录 一. 基础内容1. 决策树基本原理1.1. 定义1.2. 表示成条件概率 2. 决策树的训练算法2.1. 划分选择的算法信息增益&#xff08;ID3 算法&#xff09;信息增益比&#xff08;C4.5 算法&#xff09;基尼指数&#xff08;CART 算法&#xff09;举例说明&#xff1a;计算各个…...

【人工智能基础03】机器学习(练习题)

文章目录 课本习题监督学习的例子过拟合和欠拟合常见损失函数&#xff0c;判断一个损失函数的好坏无监督分类&#xff1a;kmeans无监督分类&#xff0c;Kmeans 三分类问题变换距离函数选择不同的起始点 重点回顾1. 监督学习、半监督学习和无监督学习的定义2. 判断学习场景3. 监…...

HarmonyOS(60)性能优化之状态管理最佳实践

状态管理最佳实践 1、避免在循环中访问状态变量1.1 反例1.2 正例 2、避免不必要的状态变量的使用3、建议使用临时变量替换状态变量3.1 反例3.2 正例 4、参考资料 1、避免在循环中访问状态变量 在应用开发中&#xff0c;应避免在循环逻辑中频繁读取状态变量&#xff0c;而是应该…...

数据库课程设计报告 超市会员管理系统

一、系统简介 1.1设计背景 受到科学技术的推动&#xff0c;全球计算机的软硬件技术迅速发展&#xff0c;以计算机为基础支撑的信息化如今已成为现代企业的一个重要标志与衡量企业综合实力的重要标准&#xff0c;并且正在悄无声息的影响与改变着国内外广泛的中小型企业的运营模…...

C++算法练习-day54——39.组合总和

题目来源&#xff1a;. - 力扣&#xff08;LeetCode&#xff09; 题目思路分析 题目&#xff1a;给定一个整数数组 candidates 和一个目标数 target&#xff0c;找出所有独特的组合&#xff0c;这些组合中的数字之和等于 target。每个数字在每个组合中只能使用一次。 思路&a…...

计算机毕业设计PySpark+Hadoop中国城市交通分析与预测 Python交通预测 Python交通可视化 客流量预测 交通大数据 机器学习 深度学习

温馨提示&#xff1a;文末有 CSDN 平台官方提供的学长联系方式的名片&#xff01; 温馨提示&#xff1a;文末有 CSDN 平台官方提供的学长联系方式的名片&#xff01; 温馨提示&#xff1a;文末有 CSDN 平台官方提供的学长联系方式的名片&#xff01; 作者简介&#xff1a;Java领…...

Linux的文件系统

这里写目录标题 一.文件系统的基本组成索引节点目录项文件数据的存储扇区三个存储区域 二.虚拟文件系统文件系统分类进程文件表读写过程 三.文件的存储连续空间存放方式缺点 非连续空间存放方式链表方式隐式链表缺点显示链接 索引数据库缺陷索引的方式优点&#xff1a;多级索引…...

【Vue3】从零开始创建一个VUE项目

【Vue3】从零开始创建一个VUE项目 手动创建VUE项目附录 package.json文件报错处理: Failed to get response from https://registry.npmjs.org/vue-cli-version-marker 相关链接&#xff1a; 【VUE3】【Naive UI】&#xff1c;NCard&#xff1e; 标签 【VUE3】【Naive UI】&…...

9)语法分析:半倒装和全倒装

在英语中&#xff0c;倒装是一种特殊的句子结构&#xff0c;其中主语和谓语&#xff08;或助动词&#xff09;的位置被颠倒。倒装分为部分倒装和全倒装两种类型&#xff0c;它们的主要区别在于倒装的程度和使用的场合。 1. 部分倒装 (Partial Inversion) 部分倒装是指将助动词…...

Scala关于成绩的常规操作

score.txt中的数据&#xff1a; 姓名&#xff0c;语文&#xff0c;数学&#xff0c;英语 张伟&#xff0c;87&#xff0c;92&#xff0c;88 李娜&#xff0c;90&#xff0c;85&#xff0c;95 王强&#xff0c;78&#xff0c;90&#xff0c;82 赵敏&#xff0c;92&#xff0c;8…...

使用Java实现度分秒坐标转十进制度的实践

目录 前言 一、度分秒的使用场景 1、表示方法 2、两者的转换方法 3、区别及使用场景 二、Java代码转换的实现 1、确定计算值的符号 2、数值的清洗 3、度分秒转换 4、转换实例 三、总结 前言 在地理信息系统&#xff08;GIS&#xff09;、导航、测绘等领域&#xff0c…...

(LeetCode 每日一题) 3442. 奇偶频次间的最大差值 I (哈希、字符串)

题目&#xff1a;3442. 奇偶频次间的最大差值 I 思路 &#xff1a;哈希&#xff0c;时间复杂度0(n)。 用哈希表来记录每个字符串中字符的分布情况&#xff0c;哈希表这里用数组即可实现。 C版本&#xff1a; class Solution { public:int maxDifference(string s) {int a[26]…...

【Web 进阶篇】优雅的接口设计:统一响应、全局异常处理与参数校验

系列回顾&#xff1a; 在上一篇中&#xff0c;我们成功地为应用集成了数据库&#xff0c;并使用 Spring Data JPA 实现了基本的 CRUD API。我们的应用现在能“记忆”数据了&#xff01;但是&#xff0c;如果你仔细审视那些 API&#xff0c;会发现它们还很“粗糙”&#xff1a;有…...

成都鼎讯硬核科技!雷达目标与干扰模拟器,以卓越性能制胜电磁频谱战

在现代战争中&#xff0c;电磁频谱已成为继陆、海、空、天之后的 “第五维战场”&#xff0c;雷达作为电磁频谱领域的关键装备&#xff0c;其干扰与抗干扰能力的较量&#xff0c;直接影响着战争的胜负走向。由成都鼎讯科技匠心打造的雷达目标与干扰模拟器&#xff0c;凭借数字射…...

(转)什么是DockerCompose?它有什么作用?

一、什么是DockerCompose? DockerCompose可以基于Compose文件帮我们快速的部署分布式应用&#xff0c;而无需手动一个个创建和运行容器。 Compose文件是一个文本文件&#xff0c;通过指令定义集群中的每个容器如何运行。 DockerCompose就是把DockerFile转换成指令去运行。 …...

大学生职业发展与就业创业指导教学评价

这里是引用 作为软工2203/2204班的学生&#xff0c;我们非常感谢您在《大学生职业发展与就业创业指导》课程中的悉心教导。这门课程对我们即将面临实习和就业的工科学生来说至关重要&#xff0c;而您认真负责的教学态度&#xff0c;让课程的每一部分都充满了实用价值。 尤其让我…...

Spring AI与Spring Modulith核心技术解析

Spring AI核心架构解析 Spring AI&#xff08;https://spring.io/projects/spring-ai&#xff09;作为Spring生态中的AI集成框架&#xff0c;其核心设计理念是通过模块化架构降低AI应用的开发复杂度。与Python生态中的LangChain/LlamaIndex等工具类似&#xff0c;但特别为多语…...

STM32HAL库USART源代码解析及应用

STM32HAL库USART源代码解析 前言STM32CubeIDE配置串口USART和UART的选择使用模式参数设置GPIO配置DMA配置中断配置硬件流控制使能生成代码解析和使用方法串口初始化__UART_HandleTypeDef结构体浅析HAL库代码实际使用方法使用轮询方式发送使用轮询方式接收使用中断方式发送使用中…...

零知开源——STM32F103RBT6驱动 ICM20948 九轴传感器及 vofa + 上位机可视化教程

STM32F1 本教程使用零知标准板&#xff08;STM32F103RBT6&#xff09;通过I2C驱动ICM20948九轴传感器&#xff0c;实现姿态解算&#xff0c;并通过串口将数据实时发送至VOFA上位机进行3D可视化。代码基于开源库修改优化&#xff0c;适合嵌入式及物联网开发者。在基础驱动上新增…...

uniapp 集成腾讯云 IM 富媒体消息(地理位置/文件)

UniApp 集成腾讯云 IM 富媒体消息全攻略&#xff08;地理位置/文件&#xff09; 一、功能实现原理 腾讯云 IM 通过 消息扩展机制 支持富媒体类型&#xff0c;核心实现方式&#xff1a; 标准消息类型&#xff1a;直接使用 SDK 内置类型&#xff08;文件、图片等&#xff09;自…...

如何配置一个sql server使得其它用户可以通过excel odbc获取数据

要让其他用户通过 Excel 使用 ODBC 连接到 SQL Server 获取数据&#xff0c;你需要完成以下配置步骤&#xff1a; ✅ 一、在 SQL Server 端配置&#xff08;服务器设置&#xff09; 1. 启用 TCP/IP 协议 打开 “SQL Server 配置管理器”。导航到&#xff1a;SQL Server 网络配…...