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

C++STL——容器-vector(含部分模拟实现,即地层实现原理)(含迭代器失效问题)

目录

容器——vector

1.构造

模拟实现

2.迭代器

模拟实现:

​编辑

3.容量

模拟实现:

 4.元素的访问

模拟实现

5.元素的增删查改

迭代器失效问题:

思考问题


【注】:这里的模拟实现所写的参数以及返回值,都是按照库里的来实现的。

大家都知道,万事开头难,但只要将开头做好,后面的就轻松多了。学习容器也是一样的,只要将第一个容器string学明白,底层实现了然于胸之后,再学习后面的容器之后,你会发现,换汤不换药,也就有一些不一样的地方而已。

        那么今天咱们重点要讲迭代器的失效问题。废话少说,让咱们开始吧。

容器——vector

        

这里涉及到了一个东西——模板,这个东西博主会在后面进行讲解,大家只要记住这是一个泛型编程,即这里面的class T,这个T可以是任何的类型,而后面有个Alloc,这个叫内存管理器,咱们不用去管他,这个东西,编译器会自动进行内存管理的。所以这里只要关注第一个参数即可。vector就类似于顺序表。只不过这个顺序表,是有类似于指向开头的指针 ,指向有效个数下一个位置的指针,有指向容量结尾的指针。比如:咱们将整形int 存入一个vector中,即可这样写:vector<int>。

即可,vector<int>算是一种类吧。

1.构造

这里面的所有的const allocator_type& alloc = allocator_type(),不用去管,这只是一种内存管理器,编译器会自动处理的,并且写参数的时候也不需要去写。那么第一个是无参构造,第二个是构造并初始化n个val,第三个是使用迭代器进行初始化构造(这是一种范围式的构造),第四个是拷贝构造(这是重点,后面会讲它的模拟实现)。来上代码:

OK,那么通过以上的代码,博友们大概就已经知道它的构造方式了。这里需要强调的一点是:这里的auto后面加不加&,看的是你模板T是什么类型,因为范围for本质(就是不加&)是赋值拷贝,既然是拷贝 ,就有空间的消耗,要是int型还好,要是string型的呢?那你这个空间的消耗可谓是巨大。所以加上了&:传引用,对于一些开空间消耗较大的T来说,可谓是福音啊。所以,建议还是都加上&吧。(当然,你要是根据具体情况来,那也可以)。

模拟实现

第一个没啥,就是为空,就不看他的模拟实现了。

第二个:

vector(int n, const T& val = T())

{

        reserve(n);

        for (int i = 0; i < n; i++)

        {

                push_back(val);

        }

}

这里的T()的意思是T类型的默认构造。这里还需要强调一个问题,也是困扰博主的一个问题,不过还好博主将它解决了:后面的代码中你会看见vector<T>&v或者T&v。那么什么时候用第一个呢?第一个是当你准备用这一整个类型的时候(比如范围for,你是不是得用v去拷贝另一个对象,这个时候v是对象,那么这个时候,v的类型是vector<int>,所以才会用到第一个),参数才会写第一个。而第二个的v是T类型的值,比如int类型的值,并不是对象,所以说第二个主要应用于类似于插入值的时候。没事,慢慢的从后面的代码中体会。

就拿这一个举例,这一个是不是要尾插一个值,所以说,这里是T&val,后面的T(),相当于给val初始化了。

第三个:

template <class InputIterator>

vector(InputIterator first, InputIterator last)

{

        while (first != last)

        {

                push_back(*first);

                ++first;

        }

}

这里如果说push_back,扩容了,那么这里可能会涉及到迭代器失效的问题(下面将),但这里假定它没有扩容。

第四个:

vector(const vector<T>& v)

{

        reserve(v.capacity());

        for (auto& e : v)

        {

                push_back(e);

        }

}

这里是拷贝构造,是不是将咱们上面提到的两个问题全都涉及到了,即&问题与参数vector<T>&问题。

再来一个列表初始化的模拟实现:

vector(initializer_list<T> il)

{

        reserve(il.size());

        for (auto& e : il)

        {

        push_back(e);

        }

}

列表初始化本质就是通过push_back来尾插数据。

2.迭代器

由于vector不支持重载流插入流提取,所以不可以像string类一样直接输出,它只能一个元素一个元素的输出,也跟string类一样,三种方法:

1.下标+[]:

for (size_t i = 0; i < v.size(); i++)

{

        cout << v[i] << " ";

}

        cout << endl;

2.迭代器:

bit::vector<int>::iterator it = v.begin();

while (it != v.end())

{

        cout << *it << " ";

        ++it;

}

        cout << endl;

3.范围for:

for (auto e : v)

{

        cout << e << " ";

}

        cout << endl;

这里vector的迭代器跟string的一样,因为都是迭代器嘛,但这里给上两个图,帮助大家理解:

 

模拟实现:

 给定三个位置,_start,一开始的元素位置,_finish有效数据个数的下一个位置,end_of_storage,容量到头的那个位置。

typedef T* iterator;

typedef const T* const_iterator;

iterator begin()

{

        return _start;

}

iterator end()

{

        return _finish;

}

const_iterator begin() const

{

        return _start;

}

const_iterator end() const

{

        return _finish;

}

3.容量

这里跟string类差不多,都是一样的,但这里有两个重点的,咱们模拟实现一下:1.size():获取数据个数.2.capacity():获取容量大小3.empty():判断是否为空。4.resize():改变vector的size。5.reserve(): 改变vector的capacity。

我记得string里面并没有说capacity()的增长速度,那么在这咱们来讲一下:

std::vector<int>::size_type sz;std::vector<int> foo;sz = foo.capacity();std::cout << "making foo grow:\n";for (int i=0; i<100; ++i) {foo.push_back(i);if (sz!=foo.capacity()) {sz = foo.capacity();std::cout << "capacity changed: " << sz << '\n';}}std::vector<int> bar;sz = bar.capacity();bar.reserve(100);   // this is the only difference with foo abovestd::cout << "making bar grow:\n";for (int i=0; i<100; ++i) {bar.push_back(i);if (sz!=bar.capacity()) {sz = bar.capacity();std::cout << "capacity changed: " << sz << '\n';}}

这是我直接截取的官方库里的代码,咱们来看逻辑分析:先定义一个sz用来存储capacity()的变化情况。 之后写一个for循环用来不断的尾插数据,再来判断容量等不等于之前的,再打印出容量,可以看出容量的变化方式,几乎是成2倍的速度增长的。再来看一下子扩容好100个空间的,那么这个可以看出容量几乎没什么变化,因为空间提前被开好了。虽然容量在g++上是按照2倍增长的,但是在vs上是按照1.5倍增长的,所以说为什么我在string这一篇文章中说,扩容多少是看编译器的,编译器不同,扩容的速率也是不同的。

ok,那么接下来看两个重点的,先来看第一个resize:

参数也是按照库里来写的。resize起到了对数据的判断是否要插入以及删除。以上就是resize的模拟实现。思路:如果说你要插入的数据个数n大于了这里的capacity,那么就需要扩容了,扩容之后,_start+n就是容量了(capacity),扩容马上讲。那么_finish不可以等于容量,且一定比容量小吧,之后在_finish这插入数据,之后++_finish。更新_finish的位置,直到n。如果说n比capacity小,说明要删除数据了。删除数据就直接 让有效数据的下一个位置更新到你要保存的元素的个数即可(即_start+n)。

第二个:reserve

 这儿的逻辑跟string的逻辑差不多,唯一的一个坑就是我在代码中注释的,所以为了解决这个问题,你直接用原来的size不就可以了吗,不用新的size,就可以避免_finish为0的问题。以上也是模拟实现。

模拟实现:

由于resize以及reserve的模拟实现咱们已经写过了,下面咱们写size的那几个:

size_t capacity() const

{

        return _end_of_storage - _start;

}

size_t size() const

{

        return _finish - _start;

}

 4.元素的访问

这里其实跟string差不多,咱们只讲一个,

模拟实现

T& operator[](size_t i)

{

        assert(i < size());

        return _start[i];

}

5.元素的增删查改

在这也会讲到咱们最重要的部分:迭代器的失效问题。

1.尾插

来看它的模拟实现:

这里需要先确定一下是否需要扩容,如果说需要扩容,那么就先扩容,之后往_finish处插入数据,之后更新_finish的位置即可。

2.pop_back:尾删

跟push_back的差不多。

3.insert:在position之前插入val

来看它的模拟实现:

这儿有一个迭代器失效问题,待会讲完erase一块讲。这个代码的逻辑:先判断pos必须在_start与_finish之间。需要扩容的时候记得扩容。之后定义一个迭代器,让_finish赋给它,之后一直到pos的位置,往后挪一位,之后在pos这个地方插入数据,更新_finish。不知道大家发没发现一个规律:就是比如说我在pos插入元素,那么我一开始定义的地方一定是尾部,然后往后挪动数据,直到pos位置空出一个位置即可。而对于删除pos位置的元素,一般都是从pos位置开始定义,然后往前挪数据,直到有效数据的最后位置。 

4.erase:删除position位置的数据

来看模拟实现:

 这个代码逻辑也很简单,从pos位置开始定义,一直往前挪动一个数据,直到尾部为止,别忘了更新_finish。

迭代器失效问题:

迭代器的主要作用就是让算法能够不用关心底层数据结构,其底层实际就是一个指针,或者是对 指针进行了封装,比如:vector的迭代器就是原生态指针T* 。因此迭代器失效,实际就是迭代器 底层对应指针所指向的空间被销毁了,而使用一块已经被释放的空间,造成的后果是程序崩溃(即

如果继续使用已经失效的迭代器,程序可能会崩溃)。类似于野指针,指向了一块不存在空间。

1.扩容导致的迭代器失效:

看图,再看咱们模拟实现的 insert,假设空间不够了,但还要插入数据,是不是得扩容啊?扩容一般都是异地扩容,但是异地扩容,你的_start,_finish,enf_of_storge都更新过去了,但是迭代器it呢?它没有更新啊同志们,它还指向了一块已经被释放的空间,你说这迭代器能不失效吗?解决办法也很简单,记住原来it的位置,将它映射到新开的空间上即可。insert的模拟实现已经给出了答案。但你也可以,提前先reserve好足够的空间(在定义迭代器之前先开好空间),这样就完美的避开了这个问题。

2.由于删除元素导致的迭代器失效

假定咱们删除了一个元素2对吧,那么2后面的元素的3会往前1移动,代替2的位置,但是呢,你可以认为这个迭代器比较傻,它只认它一开始指向的那个元素,如果那个元素没有了,那么它会认为那个元素所在的空间被销毁了,那么这个迭代器也就失效了。比如上图中的it迭代器,就是这个原理。那么以此类推,it后面的元素是不是都要往前移动啊,那么如果说it后面还有迭代器,那么自然it后面的迭代器全部失效。解决办法也很简单,就是再重新将被删元素的下一个空间重新赋值给it,那么被删元素的下一个空间其实就是it所指向的空间,因为被删元素的下一个元素往前挪动了一格嘛,所以说,这个空间就是it所指向的空间,就是原被删元素的空间。

那么失效后的迭代器,都不可再对他们进行++,--等操作,当然,在vs上会强制检查,但在其他编译器上,可能还可以正常运行,这也是看编译器的。

那么insert的返回值是插入那个元素的空间位置。而erase的返回值是被删元素的下一个元素的空间,其实都是it这个位置。

思考问题

vector v{ 1, 2, 3, 4 };

auto it = v.begin();

while (it != v.end())

{

        if (*it % 2 == 0)

        {

                v.erase(it);

                  ++it;

        }

      

}

那么看上面这个代码,对吗?为什么不对? 

肯定不对啊,1.首先是迭代器失效的问题,你erase后是不可以对迭代器进行加减操作的。

2.erase删除的迭代器如果是最后一个元素,删除之后it已经超过end,此时迭代器是无效的,++it导致程序崩溃。是因为进去循环的条件是it不等于_finish(这个循环式erase中的循环),而删除尾部元素的时候,it被定义为指向尾部的下一个元素,那么就可以进入循环,之后it会一直++,那这肯定不行,一直访问的是没有的空间。

3.就算你给erase重新赋值,但是又有一个问题:比如vector<int> v={1,2,2,3,4},有两个连续的偶数,你删除了第一个偶数之后,第二个偶数挪到了第一个偶数的位置,然后it++,会直接跳过第二个偶数,那这样第二个偶数就删不了了,不可以,所以,完美的解决办法就是,当它是偶数的时候,直接删,当它是奇数的时候,再++.即:

现在迭代器失效的问题,我已经全部讲清楚了,也讲的很透了。 

5.swap

void swap(vector<T>& v)

{

        std::swap(_start, v._start);

        std::swap(_finish, v._finish);

        std::swap(_end_of_storage, v._end_of_storage);

}

那么现在咱们再来看一下现代写法的赋值有多精妙。

// v1 = v3

vector<T>& operator=(vector<T> v)

{

        swap(v);

        return *this;

}

首先,先对v3进行传值传参,需要调用拷贝构造,那么拷贝构造就是再次构造出一个与v3一样大的空间,完了之后,交换v1与v(v3),那么咱们v3是想要的,而v1是不想要的,通过交换正好拿到了v3,那么v1也给了v,而v是一个局部变量啊,出了作用域就销毁了。所以说,v出了函数就销毁了,反正也不要了,是不是很nice呀,哈哈哈哈哈,确实,我也这么想的,当年创造这个写法的人肯定也是这么想的。 

OK,vector的内容就这些,由于咱们有了string的基础,所以学起来vector就是很简单了,除了一些特殊的坑外,其他的也没什么了。

以上内容均我个人理解,若有不对,还请各位大佬指出,谢谢啦!

本篇完...................

相关文章:

C++STL——容器-vector(含部分模拟实现,即地层实现原理)(含迭代器失效问题)

目录 容器——vector 1.构造 模拟实现 2.迭代器 模拟实现&#xff1a; ​编辑 3.容量 模拟实现&#xff1a; 4.元素的访问 模拟实现 5.元素的增删查改 迭代器失效问题&#xff1a; 思考问题 【注】&#xff1a;这里的模拟实现所写的参数以及返回值&#xff0c;都是…...

MoLe-VLA:通过混合层实现的动态跳层视觉-语言-动作模型实现高效机器人操作

25年3月来自南京大学、香港理工、北大和香港科技大学的论文“MoLe-VLA: Dynamic Layer-skipping Vision Language Action Model via Mixture-of-Layers for Efficient Robot Manipulation”。 多模态大语言模型 (MLLM) 在理解复杂语言和视觉数据方面表现出色&#xff0c;使通用…...

《数字图像处理》教材寻找合作者

Rafael Gonzalez和Richard Woods所著的《数字图像处理》关于滤波器的部分几乎全错&#xff0c;完全从零开始写&#xff0c;困难重重。关于他的问题已经描述在《数字图像处理&#xff08;面向新工科的电工电子信息基础课程系列教材&#xff09;》。 现寻找能够共同讨论、切磋、…...

uni-app 框架 调用蓝牙,获取 iBeacon 定位信标的数据,实现室内定位场景

背景&#xff1a;最近需要对接了一个 叫 iBeacon 定位信标 硬件设备&#xff0c;这个设备主要的作用是&#xff0c;在信号不好的地方&#xff0c;或者室内实现定位&#xff0c;准确的找到某个东西。就比如 地下停车场&#xff0c;商城里&#xff0c;我们想知道这个停车场的某个…...

Java面试黄金宝典29

1. 什么是普通索引和唯一性索引 定义&#xff1a; 普通索引&#xff1a;是最基本的索引类型&#xff0c;它为数据表中的某一列或多列建立索引&#xff0c;以加快数据的查询速度。它不限制索引列的值重复&#xff0c;允许存在多个相同的值。唯一性索引&#xff1a;在普通索引的基…...

C语言常见3种排序

主要是三种排序方法&#xff1a;冒泡排序、选择排序、插入排序。 文章目录 一、冒泡排序 1.代码&#xff1a; 2.工作原理&#xff1a; 3.具体过程&#xff1a; 二、选择排序 1.代码 2. 工作原理 3.具体过程&#xff1a; 三、插入排序 1.代码 2.工作原理 3.具体过程 总结 一、…...

Nyquist插件基础:LISP语法-自定义函数

1 Nyquist插件基础&#xff1a;LISP语法-自定义函数 在 Nyquist 里&#xff0c;自定义函数能够让你把特定的操作封装起来&#xff0c;实现代码复用和逻辑模块化。下面详细介绍如何在 Nyquist 中定义和使用自定义函数。 1.1.1 1. 基本函数定义 在 Nyquist 中使用 defun 来定义…...

Visual-RFT:视觉强化微调

文章目录 速览摘要1. 引言2. 相关工作大型视觉语言模型&#xff08;LVLMs&#xff09;强化学习 3. 方法3.1. 初步带可验证奖励的强化学习DeepSeek R1-Zero和GRPO 3.2. Visual-RFT3.2.1. 视觉感知中的可验证奖励检测任务中的IoU奖励分类任务中的CLS奖励 3.2.2 数据准备 4. 实验4…...

快速入手-基于DRF的过滤、分页、查询配置(十五)

1、过滤需要安装插件 pip install django-filter 2、注册 INSTALLED_APPS [ "django.contrib.admin", "django.contrib.auth", "django.contrib.contenttypes", "django.contrib.sessions", "django.contrib.messages",…...

最新Spring Security实战教程(八)Remember-Me实现原理 - 持久化令牌与安全存储方案

&#x1f337; 古之立大事者&#xff0c;不惟有超世之才&#xff0c;亦必有坚忍不拔之志 &#x1f390; 个人CSND主页——Micro麦可乐的博客 &#x1f425;《Docker实操教程》专栏以最新的Centos版本为基础进行Docker实操教程&#xff0c;入门到实战 &#x1f33a;《RabbitMQ》…...

gcc 链接顺序,静态库循环依赖问题

链接过程由链接器 ld 负责。通常 GCC 间接驱动之。 越底层的库&#xff0c;在链接命令行中的位置应越靠后。 文章目录 链接过程※ 但是对于静态库&#xff0c;链接器仅提取当前未解析符号所需的对象文件&#xff0c;未使用的对象文件会被丢弃。静态库&#xff08;.a&#xff09…...

linux内核漏洞检测利用exp提权

案例一dirtycow&#xff08;CVE-2016-5159&#xff09; 有个前置知识就是 获取liunx的内核 hostnamectl uname -a 然后这个内核漏洞进行提权的步骤也是和手工win进行提权差不多 也是需要使用辅助工具在本地进行辅助检测 然后去nomi-sec/PoC-in-GitHub&#xff1a; &#…...

【学Rust写CAD】21 2D 点(point.rs)

源码 //matrix/point.rs use std::ops::Mul; use super::algebraic_units::{Zero, One}; use super::generic::Matrix;/// 点坐标结构体 #[derive(Debug, Clone, Copy, PartialEq)] pub struct Point<X, Y>(Matrix<X, Y, One, Zero, Zero, One>);impl<X, Y>…...

Jmeter的压测使用

Jmeter基础功能回顾 一、创建Jmeter脚本 1、录制新建 &#xff08;1&#xff09;适用群体&#xff1a;初学者 2、手动创建 &#xff08;1&#xff09;需要了解Jmeter的常用组件 元件&#xff1a;多个类似功能组件的容器&#xff08;类似于类&#xff09; 各元件作用 组件…...

C语言--统计输入字符串中的单词个数

输入 输入&#xff1a;大小写字母以及空格&#xff0c;单词以空格分隔 输出&#xff1a;单词个数 代码 如果不是空格且inWord0说明是进入单词的第一个字母&#xff0c;则单词总数加一。 如果是空格&#xff0c;证明离开单词&#xff0c;inWord 0。 #include <stdio.h&g…...

《雷神之锤 III 竞技场》快速求平方根倒数的计算探究

1. 《雷神之锤 III 竞技场》快速求平方根导数源代码 此处先列出其源代码&#xff0c;这段代码的目标是计算一个浮点数平方根的导数&#xff0c;也就是如下形式&#xff1a; f ( x ) 1 x f(x) \frac{1}{\sqrt{x}} f(x)x ​1​这段代码可以说非常难以理解&#xff0c;尤其是 …...

深入解析 Java 8 Function 接口:函数式编程的核心工具

精心整理了最新的面试资料和简历模板&#xff0c;有需要的可以自行获取 点击前往百度网盘获取 点击前往夸克网盘获取 Java 8 引入的 java.util.function.Function 接口是函数式编程范式的核心组件之一&#xff0c;本文将全面解析其使用方法&#xff0c;并通过丰富的代码示例演…...

软件重构与项目进度的矛盾如何解决

软件重构与项目进度之间的矛盾可以通过明确重构目标与范围、采用渐进式重构策略、优化项目管理流程、提高团队沟通效率、建立重构意识文化等方式解决。其中&#xff0c;采用渐进式重构策略尤为关键。渐进式重构是指在日常开发过程中&#xff0c;以小步骤持续进行重构&#xff0…...

redis的geo结构实现[附近商铺]功能

先上结论 geo地理位置算出来是不准的 实现思路 redis6.2支持了经纬度数据格式 支持经纬度检索 需要将redis升级 否则会报错不支持命令 pom文件如果spring-data-redis是2.7.9的boot版本则要改一下支持geo: <dependency><groupId>org.springframework.boot</g…...

W3C XML Schema 活动

W3C XML Schema 活动 概述 W3C XML Schema(XML Schema)是万维网联盟(W3C)定义的一种数据描述语言,用于定义XML文档的结构和约束。XML Schema为XML文档提供了一种结构化的方式,确保数据的一致性和有效性。本文将详细介绍W3C XML Schema的活动,包括其发展历程、主要特点…...

深入解析C++类:面向对象编程的核心基石

一、类的本质与核心概念 1.1 类的基本定义 类是将**数据&#xff08;属性&#xff09;与操作&#xff08;方法&#xff09;**封装在一起的用户自定义类型&#xff0c;是面向对象编程的核心单元。 // 基础类示例 class BankAccount { private: // 访问控制string owner; …...

MySQL 复制与主从架构(Master-Slave)

MySQL 复制与主从架构&#xff08;Master-Slave&#xff09; MySQL 复制与主从架构是数据库高可用和负载均衡的重要手段。通过复制数据到多个从服务器&#xff0c;既可以实现数据冗余备份&#xff0c;又能分担查询压力&#xff0c;提升系统整体性能与容错能力。本文将详细介绍…...

2025年上软考——【数据库系统工程师】考前60天冲刺学习指南!!!

距离2025上半年“数据库系统工程师”考试已经不足两个月了&#xff0c;还没有准备好的小伙伴赶紧行动起来。为了帮助大家更好的冲刺学习&#xff0c;特此提供一份考前60天学习指南。本指南包括考情分析、学习规划、冲刺攻略三个部分&#xff0c;可以参考此指南进行最后的复习要…...

如果数据包的最后一段特别短,如何处理?

在处理TCP粘包/拆包时&#xff0c;如果最后一个数据段特别短&#xff08;例如仅包含部分包头部或部分数据体&#xff09;&#xff0c;需要通过合理的缓冲区和协议设计来确保数据完整性。以下是具体处理方案&#xff1a; 1. 缓冲区管理&#xff1a;保留不完整数据 核心思想&…...

vue修饰符

在 Vue 中&#xff0c;修饰符是一种特殊的后缀&#xff0c;用于改变指令的默认行为 stop <template><div><h2>vue修饰符</h2><div class"box" click"boxClikc"><button click"btnClick">按钮</button&…...

Redis-06.Redis常用命令-列表操作命令

一.列表操作命令 LPUSH key value1 [value2]&#xff1a; LPUSH mylist a b c d: LRANGE key start stop&#xff1a; LRANGE mylist 0 -1&#xff1a; lrange mylist 0 2&#xff1a; d c b RPOP KEY&#xff1a;移除并返回最后一个元素 RPOP list a LLEN key…...

LTSPICE仿真电路:(二十四)MOS管推挽驱动电路简单仿真

1.Mos管驱动电路基本的拓扑 前面在十一篇的时候学习了MOS管的简单的应用&#xff0c; 这一篇继续补充MOS管的驱动电路。 这个电路应该是最基本的电路仿真&#xff0c;先看电路以及仿真结果&#xff0c;以下仿真结果的电压皆为信号发生器提供的波形图。 看仿真结果比较明了&a…...

GFS论文阅读笔记

文章目录 摘要一、引言二、设计总览2.1、假设2.2、接口2.3、架构2.4 单Master2.5 Chunk大小2.6 元数据2.7 一致性模型 3 系统交互3.1 租约和变更顺序3.2 数据流3.3 原子性的操作&#xff1a;Record append3.4 快照-SNAPSHOT 4. master操作4.1 namespace的管理与锁定4.2 副本的分…...

6. 王道_网络协议

1 网络协议和网络模型 2 TCP/IP协议族概览 2.1 四层模型的各层实体 2.2 协议数据单元的转换 2.3 常见协议以及分层 2.4 ifconfig 2.5 本地环回设备 3 以太网 3.1 以太网和交换机 3.2 以太网帧 MAC地址大小 48位 6字节 IP地址 32位 4字节 port 16位 2字节 3.3 ARP协议 4 IP协…...

《K230 从熟悉到...》颜色识别

《K230 从熟悉到...》颜色识别 颜色识别的基本原理 《庐山派 K230 从熟悉到...》颜色识别 颜色识别是计算机视觉中的重要组件&#xff0c;它允许算法在图像中检测、识别和分类不同颜色。 颜色识别的基本原理 颜色识别的核心是通过分析图像中像素点的颜色信息&#xff0c;从…...

实时内核稳定性 - scheduling while atomic

scheduling while atomic问题 根因:未成对使用获取cpu_id的函数[ 291.881071][ 0] [XW]: type=0x00000003 cpuid=4 time=1725877230 subj...

数据编排与Dagster:解锁现代数据管理的核心工具

在数据驱动的时代&#xff0c;如何高效管理复杂的数据管道、确保数据质量并实现团队协作&#xff1f;本文深入探讨数据编排的核心概念&#xff0c;解析其与传统编排器的差异&#xff0c;并聚焦开源工具Dagster如何以“资产为中心”的理念革新数据开发流程&#xff0c;助力企业构…...

stc8g1k08a定时读取内部1.2v电压值发送到串口1

1189mv #include "stc8g.h"void t0_timer_init(){EA 1;//总中断控制位,启用中断//启用定时器0中断ET0 1;//允许t0中断AUXR | 0x80; //定时器时钟1T模式 t0不频 t1 12分频TMOD & 0xF0; //设置定时器模式TL0 0xCD; //设置定时初始值 205TH0 0xD4; …...

前端开发时的内存泄漏问题

目录 &#x1f50d; 什么是内存泄漏&#xff08;Memory Leak&#xff09;&#xff1f;&#x1f6a8; 常见的内存泄漏场景1️⃣ 未清除的定时器&#xff08;setInterval / setTimeout&#xff09;2️⃣ 全局变量&#xff08;变量未正确释放&#xff09;3️⃣ 事件监听未清除4️⃣…...

「青牛科技 」GC4931P/4938/4939 12-24V三相有感电机驱动芯片 对标Allegro A4931/瑞盟MS4931

芯片描述&#xff1a; • 芯片工作电压 4.7-36V &#xff08; GC4931P &#xff09; • 芯片工作电压 7.5-36V &#xff08; GC4938/4939 &#xff09; • 外置 mos 驱动&#xff0c; NN 结构&#xff0c;内置升压预驱 • QFN5X5-28 封装&#xff0c;带 ePAD 散热&#…...

2025 年山东危化品经营单位考试攻略分享​

山东的考试在全省统一标准。理论考试深入考查危化品相关标准规范&#xff0c;如《危险化学品重大危险源辨识》等。对于危化品储存设施的设计与维护知识要求较高。实际操作考核注重在山东化工园区常见的作业场景&#xff0c;如大型储罐区的操作。​ 报名准备材料与其他省份类似…...

RustDesk 开源远程桌面软件 (支持多端) + 中继服务器伺服器搭建 ( docker版本 ) 安装教程

在需要控制和被控制的电脑上安装软件 github开源仓库地址 https://github.com/rustdesk/rustdesk/releases 蓝奏云盘备份 ( exe ) https://geek7.lanzouw.com/iPf592sadqrc 密码:4esi 中继服务器设置 使用docker安装 sudo docker image pull rustdesk/rustdesk-server sudo…...

CMake 中的置变量

在 CMake 中&#xff0c;变量是存储和传递信息的重要方式。以下是一些常用的 CMake 变量&#xff0c;以表格形式列出&#xff0c;包括它们的名称、含义和常见用途&#xff1a; 变量名称含义常见用途CMAKE_CURRENT_SOURCE_DIR当前处理的 CMakeLists.txt 文件所在的源代码目录的…...

前后端数据序列化:从数组到字符串的旅程(附优化指南)

&#x1f310; 前后端数据序列化&#xff1a;从数组到字符串的旅程&#xff08;附优化指南&#xff09; &#x1f4dc; 背景&#xff1a;为何需要序列化&#xff1f; 在前后端分离架构中&#xff0c;复杂数据类型&#xff08;如数组、对象&#xff09;的传输常需序列化为字符…...

为什么你涨不了粉?赚不到技术圈的钱?

“你的代码如果能打造市值百亿的产品&#xff0c;为什么不能为你的未来加冕&#xff1f;” 这不仅是一句口号&#xff0c;而是一段激励人心的故事的起点。想象一下&#xff0c;一个普通的程序员&#xff0c;在无数个深夜独自敲击代码中&#xff0c;他的每一行代码都承载着对未…...

MATLAB之数据分析图系列 三

三维堆叠柱状图 Bar3StackPlot.m文件 clc; clear; close all; %三维堆叠柱状图 %% 数据准备 % 读取数据 load data.mat % 初始化 dataset X; s 0.4; % 柱子宽度 n size(dataset,3); % 堆叠组数%% 图片尺寸设置&#xff08;单位&#xff1a;厘米&#xff09; figureUnits c…...

【nvidia】Windows 双 A6000 显卡双显示器驱动更新问题修复

问题描述&#xff1a;windows自动更新nvidia驱动会导致只检测得到一个A6000显卡。 解决方法 下载 A6000 驱动 572.83-quadro-rtx-desktop-notebook-win10-win11-64bit-international-dch-whql.exehttps://download.csdn.net/download/qq_18846849/90554276 不要直接安装。如…...

使用Docker快速部署Dify

使用Docker快速部署Dify:一站式AI应用开发平台 Dify 是一款开源的AI应用开发平台,支持快速构建基于大模型的AI应用。通过Docker部署Dify,可以简化环境配置流程,实现高效部署和扩展。本教程将详细介绍如何通过Docker快速部署Dify。 前置条件 ​服务器/本地环境:Linux/Wind…...

Uniapp 实现微信小程序滑动面板功能详解

文章目录 前言一、功能概述二、实现思路三、代码实现总结 前言 Uniapp 实现微信小程序滑动面板功能详解 一、功能概述 滑动面板是移动端常见的交互组件&#xff0c;通常用于在页面底部展开内容面板。本文将介绍如何使用 Uniapp 开发一个支持手势滑动的底部面板组件&#xff0…...

PyQt5和OpenCV车牌识别系统

有需要请加文章底部Q哦 可远程调试 PyQt5和OpenCV车牌识别系统 一 介绍 此车牌识别系统基于PyQt5和OpenCV开发&#xff0c;蓝牌&#xff0c;新能源(绿牌)&#xff0c;黄牌&#xff0c;白牌均可以准确识别&#xff0c;支持中文识别&#xff0c;可以导出识别结果(Excel格式)。此…...

Redis如何在windows中简单安装?

Redis 在官网上有详细的介绍如何安装&#xff0c;但是看着也乱和麻烦。所以教大家直接用大佬整理好的。 Redis安装 ✨进入安装包地址✨安装Redis✨测试下 ✨进入安装包地址 安装包地址&#xff1a; https://github.com/tporadowski/redis/releases Redis安装包是在github上&am…...

在centos7上安装ragflow

在centos7上安装ragflow 前置条件&#xff0c;安装centos7&#xff0c;换yum源&#xff0c;安装docker&#xff0c;安装git 参考文章&#xff1a;利用vmware快速安装一个可以使用的centos7系统-CSDN博客 ragflow的部署参考文章&#xff1a; https://mp.weixin.qq.com/s/Hor…...

LabVIEW多线程

在 LabVIEW 中&#xff0c;多线程编程是提升程序执行效率的关键手段&#xff0c;尤其是在需要并行处理数据采集、控制执行和用户界面交互的场景下。LabVIEW 本身是基于数据流&#xff08;Dataflow&#xff09;的编程语言&#xff0c;天然支持多线程&#xff0c;但要高效利用多线…...

MySQL 错误 报错:Table ‘performance_schema.session_variables’ Doesn’t Exist

mysqldump -uroot -p ca>ca.sql Enter password: mysqldump: Couldnt execute SHOW VARIABLES LIKE gtid\_mode: Table performance_schema.session_variables doesnt exist 解决&#xff1a; USE performance_schema; CREATE TABLE session_variables (VARIABLE_NAME VAR…...

4月2号.

正则表达式的作用: 作用一: 示例: [1-9]表示0不在开头,\\d表示数字,{5,19}表示位数. 拓展: 正则表达式: System.out.println("a".matches(regex:"[a-z&[def]]")); //trueSystem.out.println("&".matches(regex:"[a-z&[def]]&…...