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

STL详解 - vector的模拟实现

目录

一、整体设计

1.1 核心结构

1.2 迭代器实现

二、核心接口实现

2.1 构造函数系列

🌴默认构造

🌴迭代器范围构造

🌴元素填充构造

2.2 拷贝控制

🌵拷贝构造函数

🌵赋值运算符(现代写法)

2.3 析构函数

三、容量管理

 3.1 size

3.2 capacity 

3.3 reserve 扩容

3.4 resize 调整大小

四、辅助函数

4.1 下标访问

4.2 empty 

五、 插入与删除

5.1 insert 插入

5.2 push_back

5.3 pop_back

5.4 erase 删除

六、源码

七、测试示例


一、整体设计

1.1 核心结构

vector 的核心是通过动态内存管理实现一个动态数组。它维护了三个指针:

  • _start:指向数组的起始位置。

  • _finish:指向数组的当前结束位置(即最后一个元素的下一个位置)。

  • _endofstorage:指向分配的内存的结束位置(即最大容量)。

通过这三个指针,vector 可以动态调整数组的大小,同时支持高效的随机访问和插入/删除操作。

template<class T>
class vector 
{
private:T* _start = nullptr;      // 数据起始位置T* _finish = nullptr;     // 数据结束位置T* _endofstorage = nullptr; // 容量结束位置
};

1.2 迭代器实现

        通过原生指针实现随机访问迭代器:提供 begin end 方法,支持迭代器访问 vector 的元素。

typedef T* iterator;
typedef const T* const_iterator;iterator begin()
{return _start;
}
iterator end()
{return _finish;
}// const版本
const_iterator begin() const
{return _start;
}
const_iterator end() const
{return _finish;
}

二、核心接口实现

2.1 构造函数系列

🌴默认构造

默认构造函数初始化一个空的 vector,所有指针都初始化为 nullptr。 

vector() // 使用编译器生成的默认构造
{
}

🌴迭代器范围构造

通过迭代器范围构造一个 vector,逐个将元素插入到新 vector 中。模板参数支持各类迭代器,包括原生指针。

template<class InputIterator>
vector(InputIterator first, InputIterator last)
{while (first != last){push_back(*first);// 逐个插入元素++first;}
}

🌴元素填充构造

构造一个包含 n 个元素的 vector,每个元素初始化为 val。通过 reserve 分配足够的内存,并逐个插入元素。

vector(size_t n, const T& val = T())
{reserve(n);for (size_t i = 0; i < n; i++){push_back(val);}
}

注意:需额外提供int版本避免类型推导冲突:

vector(int n, const T& val = T()) 
{reserve(n);for (size_t i = 0; i < n; i++){push_back(val);}
}

2.2 拷贝控制

🌵拷贝构造函数

拷贝构造函数通过 reserve 分配与原 vector 相同的容量,并逐个复制元素。这样可以确保新 vector 的容量和内容与原 vector 一致。

vector(const vector<T>& v) 
{reserve(v.capacity());for (auto e : v) // 范围for遍历{  push_back(e);   // 深拷贝每个元素}
}

🌵赋值运算符(现代写法)

赋值运算符通过 swap 实现,先将右值的 vector 与当前 vector 交换,然后返回当前 vector 的引用。这种方式称为 "拷贝并交换",可以避免自我赋值的问题。

vector<T>& operator=(vector<T> v) // 传值拷贝临时对象
{ swap(v);            // 交换资源return *this;       // 自动释放原内存
}

swap 函数用于交换两个 vector 的内容。通过交换指针,可以高效地完成交换操作,而无需复制数据。 

void swap(vector<T> v)
{std::swap(_start, v._start);std::swap(_finish, v._finish);std::swap(_endofstorage, v._endofstorage);
}

2.3 析构函数

析构函数释放分配的内存,并将指针置为 nullptr,避免悬空指针。

~vector()
{delete[] _start;// 释放数组空间_start = _finish = _endofstorage = nullptr;// 置空防野指针
}

三、容量管理

3.1 size

返回当前 vector 的大小,即 _finish - _start

size_t size() const
{return _finish - _start;
}

3.2 capacity 

返回 vector 的当前容量,即 _endofstorage - _start

size_t capacity() const
{return _endofstorage - _start;
}

3.3 reserve 扩容

reserve 用于分配至少 n 个元素的内存。如果当前容量不足,则分配新的内存,将旧数据复制到新内存中,然后释放旧内存。

关键点必须逐个拷贝元素保证深拷贝,直接内存拷贝(memcpy)会导致浅拷贝问题。

void reserve(size_t n) 
{if (n > capacity()) {size_t old_size = size();  // 保存原元素个数T* tmp = new T[n];         // 申请新空间// 深拷贝旧元素(不能用memcpy)for (size_t i = 0; i < old_size; ++i) {tmp[i] = _start[i];  // 调用T的赋值运算符}delete[] _start;  // 释放旧空间// 更新指针_start = tmp;_finish = tmp + old_size;_endofstorage = tmp + n;}
}

3.4 resize 调整大小

resize 用于调整 vector 的大小。如果新大小大于当前大小,则分配更多内存并填充默认值;如果新大小小于当前大小,则直接调整 _finish 指针。

void resize(size_t n, const T& val = T()) 
{if (n > size())  // 扩容部分{     reserve(n);while (_finish < _start + n) {*_finish = val;  // 填充默认值++_finish;}} else // 缩容部分{              _finish = _start + n; // 逻辑缩容,物理容量不变}
}

四、辅助函数

4.1 下标访问

operator[] 提供随机访问功能,通过索引访问 vector 的元素。

T& operator[](size_t pos)
{assert(pos < size());// 越界检查return _start[pos];
}
const T& operator[](size_t pos) const
{assert(pos < size());// 越界检查return _start[pos];
}

4.2 empty 

empty 判断 vector 是否为空,即 _start _finish 是否相等。

void empty()
{return _start == _finish;
}

五、 插入与删除

5.1 insert 插入

insert 在指定位置插入一个元素。如果内存不足,则通过 reserve 扩容。插入时需要将插入点之后的元素向后移动,为新元素腾出空间。

迭代器失效处理扩容后需重新计算pos位置

void insert(iterator pos, const T& val) 
{assert(pos >= _start && pos <= _finish);// 空间不足时扩容if (_finish == _endofstorage) {size_t len = pos - _start;  // 保存相对位置reserve(capacity() == 0 ? 4 : capacity() * 2);pos = _start + len;         // 解决迭代器失效}// 后移元素iterator it = _finish - 1;while (it >= pos) {*(it + 1) = *it;  // 从后向前搬移--it;}*pos = val;     // 插入新元素++_finish;      // 更新大小
}

5.2 push_back

push_back 是在 vector 的末尾插入一个元素,可以复用 insert 实现。

void push_back(const T& val)
{//if (_finish == _endofstorage)//{//	reserve(capacity() == 0 ? 4 : capacity() * 2);//}//*_finish = val;//_finish++;insert(end(), val);// 复用insert逻辑
}

5.3 pop_back

pop_back 删除 vector 的最后一个元素,可以复用 erase 实现。

void pop_back()
{//assert(!empty());//--_finish;erase(--end());// 复用erase逻辑
}

5.4 erase 删除

erase 删除指定位置的元素。删除时需要将删除点之后的元素向前移动,填补空缺。

void erase(iterator pos) 
{assert(pos >= _start && pos < _finish);// 前移元素iterator it = pos + 1;while (it < _finish) {*(it - 1) = *it;  // 从前向后搬移++it;}--_finish;  // 更新大小
}

六、源码

#pragma once#include <assert.h>
#include <iostream>
using namespace std;namespace lv
{template<class T>class vector{public:// 定义迭代器类型typedef T* iterator;typedef const T* const_iterator;// 返回迭代器,指向 vector 的起始位置iterator begin(){return _start;}// 返回迭代器,指向 vector 的结束位置(即最后一个元素的下一个位置)iterator end(){return _finish;}// 常量版本的 begin 和 end,用于 const 对象const_iterator begin() const{return _start;}const_iterator end() const{return _finish;}// 默认构造函数,初始化一个空的 vectorvector(){_start = nullptr;_finish = nullptr;_endofstorage = nullptr;}// 拷贝构造函数,通过 reserve 分配与原 vector 相同的容量,并逐个复制元素vector(const vector<T>& v){reserve(v.capacity());for (auto e : v){push_back(e);}}// 交换两个 vector 的内容,通过交换指针实现高效交换void swap(vector<T> v){std::swap(_start, v._start);std::swap(_finish, v._finish);std::swap(_endofstorage, v._endofstorage);}// 赋值运算符,通过 "拷贝并交换" 的方式实现,避免自我赋值问题vector<T>& operator=(vector<T> v){swap(v);return *this;}// 通过迭代器范围构造 vector,逐个插入元素template<class InputIterator>vector(InputIterator first, InputIterator last){while (first != last){push_back(*first);++first;}}// 构造一个包含 n 个元素的 vector,每个元素初始化为 valvector(size_t n, const T& val = T()){reserve(n);for (size_t i = 0; i < n; i++){push_back(val);}}// 析构函数,释放分配的内存,并将指针置为 nullptr~vector(){delete[] _start;_start = _finish = _endofstorage = nullptr;}// 返回 vector 的当前大小(即元素个数)size_t size() const{return _finish - _start;}// 返回 vector 的当前容量(即分配的内存量)size_t capacity() const{return _endofstorage - _start;}// 通过索引访问 vector 的元素,带断言检查索引是否越界T& operator[](size_t pos){assert(pos < size());return _start[pos];}// 常量版本的 operator[],用于 const 对象const T& operator[](size_t pos) const{assert(pos < size());return _start[pos];}// 分配至少 n 个元素的内存,如果当前容量不足,则重新分配内存并复制旧数据void reserve(size_t n){if (n > capacity()){size_t old_size = size();T* tmp = new T[n];for (size_t i = 0; i < old_size; ++i){tmp[i] = _start[i];}delete[] _start;_start = tmp;_finish = tmp + old_size;_endofstorage = tmp + n;}}// 调整 vector 的大小,如果新大小大于当前大小,则分配更多内存并填充默认值void resize(size_t n, const T& val = T()){if (n > size()){reserve(n);while (_finish < _start + n){*_finish = val;++_finish;}}else{_finish = _start + n;}}// 在指定位置插入一个元素,如果内存不足则扩容void insert(iterator pos, const T& val){assert(pos >= _start);assert(pos <= _finish);if (_finish == _endofstorage){size_t len = pos - _start;reserve(capacity() == 0 ? 4 : capacity() * 2);pos = _start + len;}iterator it = _finish - 1;while (it >= pos){*(it + 1) = *it;--it;}*pos = val;++_finish;}// 在 vector 的末尾插入一个元素,通过调用 insert 实现void push_back(const T& val){insert(end(), val);}// 删除 vector 的最后一个元素,通过调用 erase 实现void pop_back(){erase(--end());}// 删除指定位置的元素,将删除点之后的元素向前移动void erase(iterator pos){assert(pos >= _start);assert(pos < _finish);iterator it = pos + 1;while (it < _finish){*(it - 1) = *it;++it;}--_finish;}// 判断 vector 是否为空,即 start 和 finish 是否相等void empty(){return _start == _finish;}private:// 指向 vector 起始位置的指针iterator _start = nullptr;// 指向 vector 结束位置的指针(即最后一个元素的下一个位置)iterator _finish = nullptr;// 指向分配内存结束位置的指针(即最大容量)iterator _endofstorage = nullptr;};// 打印 vector 的内容void print_vector(const vector<int>& v){auto it = v.begin();while (it < v.end()){cout << *it << " ";it++;}cout << endl;}// 测试 vector 的功能void test_vector1(){//......}
}

七、测试示例

#include <iostream>
#include <cassert>
using namespace std;void test_vector()
{// 测试默认构造函数和基本的 push_back 操作{vector<int> v;assert(v.empty());assert(v.size() == 0);assert(v.capacity() == 0);v.push_back(1);v.push_back(2);v.push_back(3);assert(v.size() == 3);assert(v.capacity() >= 3);assert(v[0] == 1);assert(v[1] == 2);assert(v[2] == 3);}// 测试拷贝构造函数{vector<int> v1;v1.push_back(10);v1.push_back(20);v1.push_back(30);vector<int> v2(v1);assert(v2.size() == 3);assert(v2[0] == 10);assert(v2[1] == 20);assert(v2[2] == 30);}// 测试赋值运算符{vector<int> v1;v1.push_back(100);v1.push_back(200);vector<int> v2;v2 = v1;assert(v2.size() == 2);assert(v2[0] == 100);assert(v2[1] == 200);}// 测试迭代器构造函数{vector<int> v1;v1.push_back(1);v1.push_back(2);v1.push_back(3);vector<int> v2(v1.begin(), v1.end());assert(v2.size() == 3);assert(v2[0] == 1);assert(v2[1] == 2);assert(v2[2] == 3);}// 测试插入操作{vector<int> v;v.push_back(1);v.push_back(2);v.push_back(3);v.insert(v.begin() + 1, 10);assert(v.size() == 4);assert(v[0] == 1);assert(v[1] == 10);assert(v[2] == 2);assert(v[3] == 3);v.insert(v.begin(), 20);assert(v.size() == 5);assert(v[0] == 20);assert(v[1] == 1);assert(v[2] == 10);assert(v[3] == 2);assert(v[4] == 3);}// 测试删除操作{vector<int> v;v.push_back(1);v.push_back(2);v.push_back(3);v.push_back(4);v.erase(v.begin() + 1);assert(v.size() == 3);assert(v[0] == 1);assert(v[1] == 3);assert(v[2] == 4);v.pop_back();assert(v.size() == 2);assert(v[0] == 1);assert(v[1] == 3);}// 测试 resize 和 reserve{vector<int> v;v.push_back(1);v.push_back(2);v.resize(5);assert(v.size() == 5);assert(v[0] == 1);assert(v[1] == 2);assert(v[2] == 0); // 默认值assert(v[3] == 0);assert(v[4] == 0);v.resize(3);assert(v.size() == 3);assert(v[0] == 1);assert(v[1] == 2);assert(v[2] == 0);v.reserve(10);assert(v.capacity() >= 10);}// 测试边界条件{vector<int> v;assert(v.empty());assert(v.size() == 0);try{v[0]; // 应该抛出断言错误assert(false);}catch (...){assert(true);}v.push_back(1);v.erase(v.begin());assert(v.empty());}cout << "All tests passed!" << endl;
}

相关文章:

STL详解 - vector的模拟实现

目录 一、整体设计 1.1 核心结构 1.2 迭代器实现 二、核心接口实现 2.1 构造函数系列 &#x1f334;默认构造 &#x1f334;迭代器范围构造 &#x1f334;元素填充构造 2.2 拷贝控制 &#x1f335;拷贝构造函数 &#x1f335;赋值运算符&#xff08;现代写法&#xf…...

C++第三方库【JSON】nlohman/json

文章目录 优势使用API从文件中读取json从json文本创建json对象直接创建并操作json对象字符串 <> json对象文件流 <> json对象从迭代器读取像使用STL一样的访问STL容器转化为 json数组STL容器 转 json对象自定义类型转化为 json对象 限制 优势 直观的语法&#xff…...

超细的ollama下载以及本地部署deepseek项目

Ollama 是一个开源的本地化大语言模型&#xff08;LLM&#xff09;运行和部署工具&#xff0c;专注于让开发者能够快速、高效地在本地运行和管理各种开源大语言模型&#xff08;如 LLaMA、Mistral、GPT 系列等&#xff09;。它提供了一个统一的接口&#xff0c;简化了模型下载、…...

【Sequelize】关联模型和孤儿记录

一、关联模型的核心机制 1. 关联类型与组合规则 • 基础四类型&#xff1a; • hasOne&#xff1a;外键存储于目标模型&#xff08;如用户档案表存储用户ID&#xff09; • belongsTo&#xff1a;外键存储于源模型&#xff08;如订单表存储用户ID&#xff09; • hasMany&…...

Sentinel实战教程:流量控制与Spring Boot集成

Sentinel实战教程:流量控制与Spring Boot集成 1. Sentinel简介与核心概念 1.1 什么是Sentinel? Sentinel是阿里巴巴开源的流量控制组件,主要用于微服务架构中的流量防护。它通过限流、熔断、热点防护等机制,帮助系统在高并发场景下保持稳定运行。 1.2 核心功能与术语 流…...

编程技能:调试01,调试介绍

专栏导航 本节文章分别属于《Win32 学习笔记》和《MFC 学习笔记》两个专栏&#xff0c;故划分为两个专栏导航。读者可以自行选择前往哪个专栏。 &#xff08;一&#xff09;WIn32 专栏导航 上一篇&#xff1a;编程基础&#xff1a;位运算07&#xff0c;右移 回到目录 下一…...

循环神经网络 - 扩展到图结构之递归神经网络

本文我们来学习递归神经网络(Recursive Neural Network&#xff0c;RecNN)&#xff0c;其是循环神经网络在有向无循环图上的扩展 。 递归神经网络是一类专门设计来处理具有层次结构或树形结构的数据的神经网络模型。它与更常见的循环神经网络&#xff08;Recurrent Neural Net…...

【Kubernetes基础--Pod深入理解】--查阅笔记2

深入理解Pod 为什么要有个Pod1. 容器协作与资源共享2. 简化调度和资源管理3. 设计模式支持 Pod 基本用法Pod 容器共享 VolumePod 的配置管理ConfigMap 概述创建 ConfigMap 资源对象在 Pod 中使用 ConfigMap使用 ConfigMap 的限制条件 为什么要有个Pod Pod 的引入并非技术冗余&…...

【euclid】10.3 2D变换模块(transform2d.rs)bytemuck trait

这段代码是一个 Rust 的 unsafe trait 实现&#xff0c;用于标记 Transform2D 类型在特定条件下可以安全地被视为由全零字节组成的有效实例。让我们详细解释每个部分&#xff1a; 代码分解&#xff1a; #[cfg(feature "bytemuck")] unsafe impl<T: Zeroable, S…...

Maven超级详细安装部署

1.到底什么是Maven&#xff1f;搞清楚这个 Maven 是一个项目管理工具&#xff0c;主要用于 Java 项目的构建、依赖管理和文档生成。 它基于项目对象模型&#xff08;POM&#xff09;&#xff0c;通过 pom.xml 文件定义项目的配置。 &#xff08;简单说破&#xff1a;就是工程…...

C# + Python混合开发实战:优势互补构建高效应用

文章目录 前言&#x1f94f;一、典型应用场景1. 桌面应用智能化2. 服务端性能优化3. 自动化运维工具 二、四大技术实现方案方案1&#xff1a;进程调用&#xff08;推荐指数&#xff1a;★★★★☆&#xff09;方案2&#xff1a;嵌入Python解释器&#xff08;推荐指数&#xff1…...

云服务模式全知道:IaaS、PaaS、SaaS与DaaS深度解析

云服务模式详解&#xff1a;IaaS、PaaS、SaaS与DaaS 在当今数字化快速发展的时代&#xff0c;云计算已经成为企业和开发者不可或缺的一部分。它提供了灵活的资源和服务&#xff0c;使得用户可以根据自己的需求选择最合适的解决方案。本文将详细介绍四种主要的云服务模式&#…...

电机控制-隆博戈观测器(Luenberger state observer)

本文围绕基于无传感器控制策略的状态观测器展开&#xff0c;介绍其在电机领域的应用、原理、性能表现及无传感器驱动的优劣&#xff1a; 应用场景&#xff1a;适用于燃油泵、风扇等大量固定转速和低成本应用场景。工作原理&#xff1a;状态观测器利用完整的电机微分模型&#…...

RK3506+net9+VS2022跨平台调试C#程序

下载GetVsDbg.sh &#xff0c;这脚本会下载一个压缩包&#xff0c;然后解压缩&#xff0c;设置x权限等等。但是目标板子连不上&#xff0c;就想办法获取到下载路径&#xff0c;修改这个脚本&#xff0c;显示这个下载链接后&#xff0c;复制一下&#xff0c;用电脑下下来 修改好…...

【16】数据结构之基于树的排序算法篇章

目录标题 选择排序简单选择排序树形选择排序 堆排序堆的定义Heap小跟堆大根堆堆的存储堆的代码设计堆排序的代码设计 排序算法综合比较 选择排序 基本思想&#xff1a;从待排序的序列中选出最大值或最小值&#xff0c;交换该元素与待排序序列的头部元素&#xff0c;对剩下的元…...

华熙生物亮相消博会,这次又带来了什么样的变化?

首先&#xff0c;从展示层面来看&#xff0c;华熙生物在消博会上构建科技桥梁&#xff0c;展台主视觉展示糖生物学发展历程与自身发展交织历程&#xff0c;这象征着中国生物科技企业从产业突围到定义全球标准的蜕变。这一展示不仅提升了华熙生物的品牌形象&#xff0c;更向外界…...

python自动化浏览器标签页的切换

#获取全部标签页的句柄返回句柄的列表 handleswebdriver.window_handles#获取全部标签页的句柄返回句柄的列表 print(len(handles)) 切换标签页 handleswebdriver.window_handles webdriver.switch_to.window(handles[index])#切换到第几个标签页就写几 关闭标签页 关闭标…...

大象机器人推出myCobot 280 RDK X5,携手地瓜机器人共建智能教育机

摘要 大象机器人全新推出轻量级高性能教育机械臂 myCobot 280 RDK X5&#xff0c;该产品集成地瓜机器人 RDK X5 开发者套件&#xff0c;深度整合双方在硬件研发与智能计算领域的技术优势&#xff0c;实现芯片架构、软件算法、硬件结构的全栈自主研发。作为国内教育机器人生态合…...

Redis 数据类型全解析:从基础到实战应用

精心整理了最新的面试资料和简历模板&#xff0c;有需要的可以自行获取 点击前往百度网盘获取 点击前往夸克网盘获取 Redis 作为高性能的键值对存储系统&#xff0c;其丰富的数据类型是实现复杂业务逻辑的核心优势。本文将深入解析 Redis 六大核心数据类型及扩展类型&#xff…...

第一天 unity3D 引擎入门

一、为什么选择Unity进行3D开发&#xff1f; Unity作为全球使用最广泛的游戏引擎&#xff0c;在2022年的开发者调查中占据了62%的市场份额。它不仅支持3D/2D游戏开发&#xff0c;更在VR/AR、工业仿真、影视动画等领域大放异彩。对于初学者而言&#xff0c;Unity的独特优势在于…...

【初阶数据结构】——算法复杂度

一、前言 1、数据结构是什么&#xff1f; 数据结构(Data Structure)是计算机存储、组织数据的⽅式&#xff0c;指相互之间存在⼀种或多种特定关系的数 据元素的集合。没有⼀种单⼀的数据结构对所有⽤途都有⽤&#xff0c;所以我们要学各式各样的数据结构&#xff0c; 如&…...

MySQL:存储函数和存储过程

系列文章目录 1.MySQL编程基础 2.程序控制流语句 3.存储过程 4.游标 5.嵌入式SQL 文章目录 系列文章目录前言一、程序控制流语句&#xff1a;二、存储函数&#xff1a; 1.存储函数的特点&#xff1a;2.存储函数的定义&#xff1a;3.调用存储函数 三、存储过程&#xff1a;…...

常见的 API 设计风格

在软件开发中&#xff0c;常见的 API 设计风格主要有以下几种&#xff0c;每种风格适用于不同的场景和需求&#xff1a; 1. RESTful API (主流) 特点&#xff1a; 基于 HTTP 协议&#xff0c;使用标准方法&#xff08;GET/POST/PUT/DELETE&#xff09;资源导向&#xff08;UR…...

Google-A2A协议全面解析:一文掌握Agent-to-Agent协议的核心与应用

前言&#xff1a; 在当今人工智能技术飞速发展的时代&#xff0c;智能体&#xff08;Agent&#xff09;已悄然融入我们生活的各个角落。无论是个人智能助手&#xff0c;还是企业的自动化工具&#xff0c;各类AI代理的应用愈发广泛。但目前这些智能体之间大多处于孤立状态&…...

Linux-服务器添加审计日志功能

#查看audit软件是否在运行(状态为active而且为绿色表示已经在运行) systemctl start auditd #如果没有在运行的话,查看是否被系统禁用 (audit为0表示被禁用) cat /proc/cmdline | grep -w "audit=0" #修改/etc/default/grub里面audit=0 改为audit=1 #更新GRUB…...

基于机器视觉的多孔零件边缘缺陷检测(源码C++、opencv、凸包、凸缺陷检测)

&#x1f451;主页&#xff1a;吾名招财 &#x1f453;简介&#xff1a;工科学硕&#xff0c;研究方向机器视觉&#xff0c;爱好较广泛… ​&#x1f4ab;签名&#xff1a;面朝大海&#xff0c;春暖花开&#xff01; 基于机器视觉的多孔零件边缘缺陷检测&#xff08;源码C、ope…...

汇川PLC通信

汇川PLC通信协议及读写 引言 汇川PLC&#xff08;Programmable Logic Controller&#xff0c;可编程逻辑控制器&#xff09;广泛应用于工业自动化领域。汇川PLC支持多种通信协议&#xff0c;包括Modbus、Ethernet/IP、PPI等。本文将详细介绍汇川PLC的通信协议&#xff0c;并通…...

如何使用AI辅助开发CSS3 - 通义灵码功能全解析

一、引言 CSS3 作为最新的 CSS 标准&#xff0c;引入了众多新特性&#xff0c;如弹性布局、网格布局等&#xff0c;极大地丰富了网页样式的设计能力。然而&#xff0c;CSS3 的样式规则繁多&#xff0c;记忆所有规则对于开发者来说几乎是不可能的任务。在实际开发中&#xff0c…...

MySQL入门:数据表的创建

​今天我们来介绍一下除HTML外的另一种语言&#xff1a;MySQL语言&#xff1b; MySQL&#xff1a;即一种用于管理和处理关系数据库的标准语言。要用于执行查询、更新、管理数据库中的数据以及定义和操作数据库结构。 接下来我会逐一介绍它的作用以及其中数据表&#xff0c;数据…...

数据库的基本原则

数据库的核心原则 原子性与持久性&#xff1a;原子性&#xff08;Atomicity&#xff09;确保一个事务中的所有操作要么全部完成&#xff0c;要么完全不执行&#xff0c;不会出现部分完成的情况。持久性&#xff08;Durability&#xff09;则保证一旦事务提交成功&#xff0c;即…...