海淀周边网站建设/天津seo技术教程
目录
- 前言
- 一、项目结构
- 1. vector的简介
- 2. 项目结构
- 二、vector的底层结构
- 三、默认成员函数(Member functions)
- 1. 构造函数
- (1)无参构造函数
- (2)使用n个值来构造对象
- (3)使用一段迭代器区间来进行初始化
- (4)测试构造函数
- 2. 拷贝构造函数(现代写法)
- 3. 析构函数
- 4. 赋值运算符重载函数(现代写法)
- 四、迭代器(Iterators)
- 1. 普通对象的正向迭代器
- 2. const 对象的正向迭代器
- 五、容量接口(Capacity)
- 1. size()
- 2. capacity()
- 3. reserve()
- 4. resize()
- 六、元素访问接口(Element access)
- 1. operator[](size_t pos)
- (1)const T& operator[](size_t pos)
- (2)const T& operator[](size_t pos) const
- 2. at(size_t pos)
- (1)T& at(size_t pos)
- 3. front()
- 4. back()
- 七、修改接口(Modifiers)
- 1. push_back(const T& x)
- 2. pop_back()
- 3. iterator insert(iterator pos,T val = T()))
- 4. iterator erase(iterator pos)
- 八、vector中更深层次的深浅拷贝问题
前言
vector本质就是一个支持顺序存储数据,并且容量支持修改得到顺序表。但是vector的底层结构实现相比于之前实现的string来说略有不同。string中的底层结构是通过一个指针数组和两个变量来标识数组中数据的变化。vector是通过三个迭代器来标识上述过程。
一、项目结构
1. vector的简介
2. 项目结构
这个项目有两个文件,一个是test.cpp文件,另一个是vector.h文件。test.cpp文件主要是用来测试实现的vector的代码逻辑。vector.h文件主要是模拟实现vector的代码逻辑。
二、vector的底层结构
-
效果图:
-
代码实现
namespace hjt
{// 实现vectortemplate <class T>class vector{public:typedef T* iterator;typedef const T* const_iterator;private:iterator _start;// 指向存储的第一个有效数据iterator _finish;// 指向存储的最后一个有效数据的下一个位置iterator _endofstorage;// 指向能够存储的最后一个位置的下一个位置};
}
代码中是通过三个迭代器来实现底层的。
- _start:指向存储的第一个有效数据
- _finish:指向存储的最后一个有效数据的下一个位置
- _endofstorage: 指向能够存储的最后一个位置的下一个位置
其实这个实现方法和string中的实现方法其实差不多,相当于_start表示空间的起始地址,_finish表示有效数据的个数,_endofstorage表示vector的实际容量。
三、默认成员函数(Member functions)
1. 构造函数
(1)无参构造函数
- 代码
// 无参构造函数vector():_start(nullptr),_finish(nullptr),_endofstorage(nullptr){}
- 练习:
int main()
{hjt::vector<int> v1;hjt::vector<char> v2;hjt::vector<double> v3;hjt::vector<string> v4;return 0;
}
分析:v1表示一个存储int类型的vector对象,v2表示一个存储char类型的vector对象,v3表示一个存储double类型的vector对象,v4表示一个存储string类型对象的vector对象。
(2)使用n个值来构造对象
- 代码1:
// 构造函数:使用n个值来构造对象vector(size_t n, const T& val = T()):_start(nullptr), _finish(nullptr), _endofstorage(nullptr){while (n--){push_back(val);}}
- 代码2:
// 构造函数:使用n个值来构造对象vector(int n, const T& val = T()):_start(nullptr), _finish(nullptr), _endofstorage(nullptr){while (n--){push_back(val);}}
(3)使用一段迭代器区间来进行初始化
- 代码:
// 构造函数:使用一段迭代器区间来进行初始化template <class InputIterator>vector(InputIterator left, InputIterator right){while (left < right){push_back(*left);left++;}}
(4)测试构造函数
- 测试代码:
void test_vector1()
{// 测试构造函数hjt::vector<int> v1;v1.push_back(1);v1.push_back(2);v1.push_back(3);v1.push_back(4);v1.push_back(5);v1.push_back(6);v1.push_back(7);hjt::vector<int>::iterator vit = v1.begin();while (vit != v1.end()){cout << *vit << " ";vit++;}cout << endl;hjt::vector<int> v2(6, 6);hjt::vector<int>::iterator vit2 = v2.begin();while (vit2 != v2.end()){cout << *vit2 << " ";vit2++;}cout << endl;hjt::vector<int> v3(v1.begin(), v1.end());hjt::vector<int>::iterator vit3 = v3.begin();while (vit3 != v3.end()){cout << *vit3 << " ";vit3++;}cout << endl;}
运行结果:
2. 拷贝构造函数(现代写法)
- 代码:
// 拷贝构造函数vector(const vector<T>& v):_start(nullptr), _finish(nullptr), _endofstorage(nullptr){vector<T> tmp(v.begin(), v.end());swap(tmp);}
- 测试代码:
void test_vector2()
{// 测试拷贝构造函数hjt::vector<int> v;v.push_back(1);v.push_back(2);v.push_back(3);v.push_back(4);v.push_back(5);v.push_back(6);// 打印vfor (auto& e : v){cout << e << " ";}cout << endl;// 调用构造函数hjt::vector<int> v1(v);hjt::vector<int> v2 = v1;// 打印v1for (auto& e : v1){cout << e << " ";}cout << endl;// 打印v2for (auto& e : v2){cout << e << " ";}cout << endl;}
运行结果:
3. 析构函数
- 代码:
// 析构函数~vector(){if (_start){delete[]_start;_start = _finish = _endofstorage = nullptr;}}
4. 赋值运算符重载函数(现代写法)
- 代码:
// 赋值运算符重载函数vector<T>& operator=(vector<T> v){swap(v);return *this;}
- 测试代码:
void test_vector3()
{// 测试拷贝构造函数hjt::vector<int> v;v.push_back(1);v.push_back(2);v.push_back(3);v.push_back(4);v.push_back(5);v.push_back(6);// 打印vfor (auto& e : v){cout << e << " ";}cout << endl;// 调用赋值运算符重载函数hjt::vector<int> v1;v1 = v;hjt::vector<int> v2;v2 = v1;// 打印v1for (auto& e : v1){cout << e << " ";}cout << endl;// 打印v2for (auto& e : v2){cout << e << " ";}cout << endl;}
运行结果:
四、迭代器(Iterators)
1. 普通对象的正向迭代器
- 代码:
// 普通迭代器iterator begin(){return _start;}iterator end(){return _finish;}
- 代码:使用
2. const 对象的正向迭代器
- 代码:
// const迭代器const_iterator begin() const{return _start;}const_iterator end() const{return _finish;}
五、容量接口(Capacity)
1. size()
- 代码:
size_t size() const{return _finish - _start;}
2. capacity()
- 代码:
size_t capacity() const{return _endofstorage - _start;}
3. reserve()
- 代码:
// 扩容void reserve(size_t n){if (n > capacity()){size_t sz = size();T* tmp = new T[n];if (_start){memcpy(tmp, _start, sizeof(T) * size());delete[]_start;}_start = tmp;_finish = _start + sz;_endofstorage = _start + n;}}
4. resize()
- 测试代码:
int main()
{hjt::vector<int> v;v.push_back(1);v.push_back(2);v.push_back(3);v.push_back(4);v.push_back(5);v.push_back(6);for (auto& e : v){cout << e << " ";}cout << endl;cout << "size:" << v.size() << endl;cout << "capacity:" << v.capacity() << endl;v.resize(100,6);for (auto& e : v){cout << e << " ";}cout << endl;cout << "size:" << v.size() << endl;cout << "capacity:" << v.capacity() << endl;return 0;
}
运行结果:
- 测试代码2:
int main()
{hjt::vector<int> v;v.push_back(1);v.push_back(2);v.push_back(3);v.push_back(4);v.push_back(5);v.push_back(6);for (auto& e : v){cout << e << " ";}cout << endl;cout << "size:" << v.size() << endl;cout << "capacity:" << v.capacity() << endl;v.resize(3, 6);for (auto& e : v){cout << e << " ";}cout << endl;cout << "size:" << v.size() << endl;cout << "capacity:" << v.capacity() << endl;return 0;
}
运行结果:
- 测试代码3:
int main()
{hjt::vector<int> v;v.push_back(1);v.push_back(2);v.push_back(3);v.push_back(4);v.push_back(5);v.push_back(6);for (auto& e : v){cout << e << " ";}cout << endl;cout << "size:" << v.size() << endl;cout << "capacity:" << v.capacity() << endl;for (auto& e : v){cout << e << " ";}cout << endl;v.reserve(60);cout << "size:" << v.size() << endl;cout << "capacity:" << v.capacity() << endl;for (auto& e : v){cout << e << " ";}cout << endl;v.resize(50, 6);for (auto& e : v){cout << e << " ";}cout << endl;cout << "size:" << v.size() << endl;cout << "capacity:" << v.capacity() << endl;return 0;
}
运行结果:
六、元素访问接口(Element access)
1. operator[](size_t pos)
(1)const T& operator[](size_t pos)
- 代码:
T& operator[](size_t pos){return _start[pos];}
- 测试代码:
int main()
{hjt::vector<int> v;v.push_back(1);v.push_back(2);v.push_back(3);v.push_back(4);v.push_back(5);v.push_back(6);for (size_t i = 0; i < v.size(); i++){cout << v[i] << " ";}cout << endl;return 0;
}
运行结果:
(2)const T& operator[](size_t pos) const
- 代码:
const T& operator[](size_t pos) const{return _start[pos];}
- 测试代码:
2. at(size_t pos)
(1)T& at(size_t pos)
- 代码:
T& at(size_t pos){return _start[pos];}
- 测试代码:
int main()
{hjt::vector<int> v;v.push_back(1);v.push_back(2);v.push_back(3);v.push_back(4);v.push_back(5);v.push_back(6);for (size_t i = 0; i < v.size(); i++){cout << v.at(i) << " ";}cout << endl;return 0;
}
运行结果:
3. front()
- 代码:
// frontT& front() const{return *_start;}
4. back()
- 代码:
// back()T& back() const{return *(_finish - 1);}
测试:
int main()
{hjt::vector<int> v;v.push_back(1);v.push_back(2);v.push_back(3);v.push_back(4);v.push_back(5);v.push_back(6);cout << "front:" << v.front() << endl;cout << "back:" << v.back() << endl;
}
运行结果:
七、修改接口(Modifiers)
1. push_back(const T& x)
- 代码:
// 尾插void push_back(const T& x){if (_finish == _endofstorage){// 需要进行扩容reserve(capacity() == 0 ? 4 : capacity() * 2);}*_finish = x;_finish++;}
- 测试:
// 测试尾插
int main()
{hjt::vector<int> v;v.push_back(1);v.push_back(2);v.push_back(3);v.push_back(4);v.push_back(5);v.push_back(6);hjt::vector<int>::iterator vit = v.begin();while (vit != v.end()){cout << *vit << " ";vit++;}cout << endl;cout << v.size() << endl;cout << v.capacity() << endl;for (auto e : v){cout << e << " ";}cout << endl;return 0;
}
运行结果:
2. pop_back()
- 代码:
// 尾删void pop_back(){assert(_finish > _start);_finish--;}
- 测试代码:
int main()
{hjt::vector<int> v;v.push_back(1);v.push_back(2);v.push_back(3);v.push_back(4);v.push_back(5);v.push_back(6);hjt::vector<int>::iterator vit = v.begin();while (vit != v.end()){cout << *vit << " ";vit++;}cout << endl;v.pop_back();v.pop_back();v.pop_back();for (auto& e : v){cout << e << " ";}cout << endl;return 0;
}
运行结果:
没有数据继续删除:
3. iterator insert(iterator pos,T val = T()))
- 在实现insert函数的时候需要注意迭代器的问题,因为在实现insert的时候可能会进行扩容,根据扩容的底层原理,我们知道,扩容之后的空间和扩容前的空间是不一样的,扩容之后会将原来的空间进行释放,而原来的迭代器指向的是原来空间的位置,所以当原来空间释放之后,原来的迭代器就变成了一个野指针,也就是所谓的迭代器失效了,此时如果再去访问原来的迭代器就是访问野指针,程序就会崩溃。因此我们在实现insert的时候,如果需要进行扩容,则需要在扩容的时候将迭代器进行更新,防止出现野指针。
- 在使用insert函数的时候可能会出现迭代器意义变化的情况,比如:在1,2,3,4,5,6中的偶数前插入20,第一个偶数是2,此时调用insert函数插入20之后会返回一个迭代器,这个迭代器指向的是新插入的20,而不是原来指向的2,所以这种情况下调用insert函数之后,需要更新迭代器的位置到当前位置的下一个位置,这样才能够使迭代器保持原来的意义。
- 代码:
// insert()iterator insert(iterator pos, T val = T()){assert(pos >= _start && pos <= _finish);if (_finish == _endofstorage){// 扩容// 如果需要进行扩容,注意更新迭代器,否则会导致迭代器失效size_t n = pos - _start;reserve(capacity() == 0 ? 4 : capacity() * 2);pos = _start + n;}// 挪动数据iterator end = _finish - 1;while (end >= pos){*(end + 1) = *end;end--;}// 插入数据*pos = val;_finish++;return pos;}
- 测试代码1:
void test_vector4()
{// 测试inserthjt::vector<int> v;v.push_back(1);v.push_back(2);v.push_back(3);v.push_back(4);v.push_back(5);v.push_back(6);// 打印vfor (auto& e : v){cout << e << " ";}cout << endl;// 头插10v.insert(v.begin(), 10);// 打印vfor (auto& e : v){cout << e << " ";}cout << endl;// 在6前面插入10hjt::vector<int>::iterator pos = find(v.begin(), v.end(), 6);if (pos != v.end()){// 找到了,位置为:posv.insert(pos, 10);}// 打印vfor (auto& e : v){cout << e << " ";}cout << endl;// 尾插10v.insert(v.end(), 10);// 打印vfor (auto& e : v){cout << e << " ";}cout << endl;
}
运行结果:
- 测试代码2:在偶数前插入66
void test_vector5()
{// 测试inserthjt::vector<int> v;v.push_back(1);v.push_back(2);v.push_back(3);v.push_back(4);v.push_back(5);v.push_back(6);// 打印vfor (auto& e : v){cout << e << " ";}cout << endl;// 在偶数前面插入20hjt::vector<int>::iterator vit = v.begin();while (vit != v.end()){if (*vit % 2 == 0){vit = v.insert(vit, 20);vit++;}vit++;}// 打印vfor (auto& e : v){cout << e << " ";}cout << endl;
}
}
运行结果:
4. iterator erase(iterator pos)
在删除函数中,我们一般不考虑缩容方案,所以一般不会出现野指针越界的问题,但是很容易会发生迭代器的意义发生变化的问题。比如:删除1,2,3,4,5,6中所有的偶数的时候,第一个偶数是2,当删除2之后,erase函数会返回一个迭代器,这个迭代器指向的是删除元素的下一个位置,在外面如果迭代器继续遍历下一个位置,那么就会将之前删除元素的下一个元素跳过,所以可能引发程序的逻辑异常。解决方案有两种:
- 在遍历的过程中,如果发生删除,则迭代器不需要指向下一个位置(erase函数已经更新),没有发生删除时才指向下一个位置。
- 在遍历的过程中,无论是否发生删除,每次都向前走一步,但是如果发生删除,迭代器需要先向后走一步。
- 代码:
// eraseiterator erase(iterator pos){assert(pos >= _start && pos < _finish);// 挪动数据iterator begin = pos + 1;while (begin < _finish){*(begin - 1) = *begin;begin++;}_finish--;return pos;}
- 测试代码1:
void test_vector6()
{// 测试erasehjt::vector<int> v;v.push_back(1);v.push_back(2);v.push_back(3);v.push_back(4);v.push_back(5);v.push_back(6);// 打印vfor (auto& e : v){cout << e << " ";}cout << endl;// 头删v.erase(v.begin());// 打印vfor (auto& e : v){cout << e << " ";}cout << endl;// 删除5hjt::vector<int>::iterator pos = find(v.begin(), v.end(), 5);if (pos != v.end()){v.erase(pos);}// 打印vfor (auto& e : v){cout << e << " ";}cout << endl;// 尾删v.erase(v.end() - 1);// 打印vfor (auto& e : v){cout << e << " ";}cout << endl;
}
运行结果:
- 测试代码2:删除所有偶数
void test_vector7()
{// 测试erasehjt::vector<int> v;v.push_back(1);v.push_back(2);v.push_back(3);v.push_back(4);v.push_back(5);v.push_back(6);// 打印vfor (auto& e : v){cout << e << " ";}cout << endl;// 删除所有偶数hjt::vector<int>::iterator vit = v.begin();while (vit != v.end()){if (*vit % 2 == 0){vit = v.erase(vit);vit--;}vit++;}// 打印vfor (auto& e : v){cout << e << " ";}cout << endl;
}
运行结果:
八、vector中更深层次的深浅拷贝问题
在学习vector中更深层次的深浅拷贝问题之前,我们首先来学习一道经典的题目:构造一个杨辉三角。
- 杨辉三角
- 题目:
- 提交代码:
class Solution {
public:vector<vector<int>> generate(int numRows) {// 确定容器vector<vector<int>> vv;// 确定容器的大小:根据杨辉三角的行数进行确定vv.resize(numRows);// 根据杨辉三角的每一行中的元素个数确定容器中每个vector存放多少个intfor(size_t i = 0;i<vv.size();i++){vv[i].resize(i+1,0);}// 将每一行中的第一个元素和最后一个元素初始化成1for(size_t i = 0;i<vv.size();i++){for(size_t j = 0;j<vv[i].size();j++){if(j == 0||j == vv[i].size()-1){vv[i][j] = 1;}}}// 处理不是1的元素for(size_t i = 0;i<vv.size();i++){for(size_t j = 0;j<vv[i].size();j++){if(vv[i][j]!=1){vv[i][j] = vv[i-1][j-1]+vv[i-1][j];}}}return vv;}
};
- 提交结果:
解题思路:
本题其实是需要一个二维数组,所以我们采用vector<vector>的类型的容器来存储杨辉三角。首先需要根据用户输入的杨辉三角的行数来确定容器的大小,接下来根据杨辉三角每一行的元素个数确定,vector<vector>中的每一个vector存放多少个int,这个过程使用一个for循环+v.resize()进行开空间和初始化。接下来将每一行中的第一个元素和最后一个元素赋值成1,最后处理最后其他元素。
对于vector<vector>类型的遍历方法:采用两重循环,比如:上面的二重循环中,第一层循环第一次i = 0,所以vv[i] = vv[0]也就是找到vv中的第一个vector,接下来进入第二层循环,这个循环是从j = 0开始,知道j<vv[i].size()结束,也就是会将这个vector中的所有int类型的数据遍历完才会结束,当第一个vector遍历结束时,第一个内层for循环结束,所以接下来i = 1,vv[i] = vv[1],开始找到vv中的第二个vector重复上述过程。
当我们在VS中使用我们自己的vector的时候发生了下面现象:
- 代码1:构造一个5行的杨辉三角
class Solution {
public:hjt::vector<hjt::vector<int>> generate(int numRows) {// 确定容器hjt::vector<hjt::vector<int>> vv;// 确定容器的大小:根据杨辉三角的行数进行确定vv.resize(numRows);// 根据杨辉三角的每一行中的元素个数确定容器中每个vector存放多少个intfor (size_t i = 0; i < vv.size(); i++){vv[i].resize(i + 1, 0);}// 将每一行中的第一个元素和最后一个元素初始化成1for (size_t i = 0; i < vv.size(); i++){for (size_t j = 0; j < vv[i].size(); j++){if (j == 0 || j == vv[i].size() - 1){vv[i][j] = 1;}}}// 处理不是1的元素for (size_t i = 0; i < vv.size(); i++){for (size_t j = 0; j < vv[i].size(); j++){if (vv[i][j] != 1){vv[i][j] = vv[i - 1][j - 1] + vv[i - 1][j];}}}return vv;}
};void test_vector8()
{hjt::vector<hjt::vector<int>> vv = Solution().generate(5);for (auto& e : vv){for (auto& e1 : e){cout << e1 << " ";}cout << endl;}cout << endl;}
运行结果:
分析结果:通过上面的运行结果:我们想要构造一个5行的杨辉三角,结果,前四行全部是随机值,然后第五行是正常的。
- 代码2:构造一个4行的杨辉三角
void test_vector9()
{hjt::vector<hjt::vector<int>> vv = Solution().generate(4);for (auto& e : vv){for (auto& e1 : e){cout << e1 << " ";}cout << endl;}cout << endl;}
运行结果:
分析:当我们构造的是一个4行的杨辉三角时,程序竟然能够正常给我们构造出来,从4到5的区别就是需要一个扩容的过程,显然,需要vector<vector>不需要进行扩容时,程序就能够正常帮助我们构造出杨辉三角,所以显然是我们实现的扩容函数中的逻辑出现问题。
通过仔细分析:我们在扩容函数中拷贝原来空间中的数据到新空间时,使用的是memcpy()函数,memcpy()函数使用的是浅拷贝机制,所以,假如原来空间中有四个vector,那么memcpy()函数就会将原来的四个vector中的_start,_finish,_endofstorage指针分别拷贝到新空间中对应的vector中的_start,_finish,_endofstorage,所以,原来的四个vector中的_start,_finish,_endofstorage指针和新空间中对应的vector中的_start,_finish,_endofstorage分别指向的是同一块空间的同一个位置,在扩容的时候,我们知道,我们会将原来空间进行释放,所以原来的数据将全部丢失,对应的指针全部变成野指针,所以就会出现上面的现象,前四行的数据是随机值,然后访问野指针的时候出现数组越界,所以程序崩溃。
正确的处理方法:实现深拷贝
- 扩容函数代码:
void reserve(size_t n){if (n > capacity()){// 需要进行扩容size_t sz = size();// 需要先保存有效数据个数,以便后面更新_finishiterator tmp = new T[n];if (_start){for (size_t i = 0; i < size(); i++){*(tmp + i) = *(_start + i);}delete[] _start;}_start = tmp;_finish = _start + sz;_endofstorage = _start + n;}}
运行结果:
相关文章:

【C++之容器篇】造轮子:模拟实现vector类
目录前言一、项目结构1. vector的简介2. 项目结构二、vector的底层结构三、默认成员函数(Member functions)1. 构造函数(1)无参构造函数(2)使用n个值来构造对象(3)使用一段迭代器区间来进行初始化(4)测试构造函数2. 拷贝构造函数(现代写法)3. 析构函数4.…...

C++中的右值引用与移动构造函数
1.右值引用右值引用是 C11 引入的与 Lambda 表达式齐名的重要特性之一。它的引入解决了 C 中大量的历史遗留问题, 消除了诸如 std::vector、std::string 之类的额外开销, 也才使得函数对象容器 std::function 成为了可能。1.1左值、右值的纯右值、将亡值…...

Swift如何使用依赖注入进行解藕
Swift 中可以使用依赖注入(Dependency Injection)来解耦组件之间的依赖关系。依赖注入是一种设计模式,指的是在运行时,将一个组件所依赖的其他组件通过构造函数或者属性注入的方式传递给该组件。 例如,有两个组件 A 和…...

合宙ESP32S3-CORE开发板|保姆级|Arduino IDE|windows11|esp32S3支持库|helloword例程:Arduino 环境搭建
Arduino主页网址: Software | Arduino 以windows11版本为例: Arduino IDE最新版本为2.0.3 左边的按钮是直接下载(免捐赠): 下载安装完成后,更改软件默认语言: 默认的库是不支持ESP32的&#…...

CMake中target_precompile_headers的使用
CMake中的target_precompile_headers命令用于添加要预编译的头文件列表,其格式如下: target_precompile_headers(<target><INTERFACE|PUBLIC|PRIVATE> [header1...][<INTERFACE|PUBLIC|PRIVATE> [header2...] ...]) # 1 target_preco…...

SpringCloud和微服务介绍
SpringCloud介绍 SpringCloud是在SpringBoot的基础上构建的,用于简化分布式系统构建的工具集。 该工具集为微服务架构中所涉及的配置管理,服务发现,智能路由,断路器,微代理和控制总线等操作提供了一种简单的开发方式。 SpringCloud中包含了多个子项目: Spring …...

Qt源码编译过程中配置文件中的选项说明
文章目录选项说明默认值顶级安装目录-prefix 部署目录,如目标设备上所示。/usr/local/Qt-$QT_VERSION-extprefix 安装目录,如主机上所示。SYSROOT/PREFIX-hostprefix [dir]主机上运行的生成工具的安装目录。如果未给定[dir],则将使用当前构建…...

Mysql 增删改查(一) —— 查询(条件查询where、分页limits、排序order by、分组 group by)
查询 select 可以认为是四个基本操作中使用最为频繁的操作,然而数据量比较大的时候,我们不可能查询所有内容,我们一般会搭配其他语句进行查询: 假如要查询某一个字段的内容,可以使用 where假如要查询前几条记录&#…...

VScode 结合clangd 构建linux源代码阅读环境
1、背景介绍上一篇文章:VScode 结合Global构建linux源代码阅读环境 ,介绍了在VS Code工具中通过remote-ssh远程登陆到Linux远程服务器,使用Global构建linux源代码阅读环境,对linux kernel代码进行解析,实现全局搜索、自…...

web应用 —— JavaScript
Web应用(acwing) 三、JavaScript 1.JS的调用方式与执行顺序 ①使用方法 HTML页面中任意位置加上<script type"module"></script>标签即可 常见使用方式: 直接在<script type"module"></script>标签内写JS代码。直…...

SSM整合SpringSecurity简单使用
一、SpringSecurity 1.1 什么是SpringSecurity Spring Security 的前身是 Acegi Security ,是 Spring 项目组中用来提供安全认证服务的框架。(官网地址) Spring Security 为基于J2EE企业应用软件提供了全面安全服务。特别是使用领先的J2EE解决方案-Spring框架开发…...

Java零基础教程——数据类型
目录数据类型数据类型的分类运算符算术运算符符号做连接符的识别自增、自减运算符赋值运算符关系运算符逻辑运算符短路逻辑运算符三元运算符运算符优先级数据类型 数据类型的分类 引用数据类型(除基本数据类型之外的,如String ) 基本数据类…...

【Linux 信号】信号的产生方式、信号的捕捉的全过程
信号的处理方式是远远比信号的产生当闹钟响了就知道时间到了,说明对应信号处理方法比信号产生更早操作系统的信号处理方法在编写操作系统的时候就已经编写好了signal函数1.1所有的信号1.2 signal函数的概念和简单使用捕捉信号就是自定义对应的信号的处理方法9号信号…...

代码随想录第58天(动态规划):● 392.判断子序列 ● 115.不同的子序列
一、判断子序列 题目描述: 思路和想法: 这道题目还是最长公共子序列的拓展,只是这里进行删除的一定是t字符串,当不相等时,dp[i][j] dp[i][j - 1];其余基本一致。当最长公共子序列个数等s.size()时&#x…...

代码随想录第55天(动态规划):● 309.最佳买卖股票时机含冷冻期 ● 714.买卖股票的最佳时机含手续费
一、最佳买卖股票时机含冷冻期 题目描述: 思路和想法: 这道题相较于之前的题目,注重对状态的分析,这里分为四个状态。 (1)状态一,买入状态 dp[i][0] 操作一:前一天就是持有状态(状…...

字符串装换整数(atoi)-力扣8-java
一、题目描述请你来实现一个 myAtoi(string s) 函数,使其能将字符串转换成一个 32 位有符号整数(类似 C/C 中的 atoi 函数)。函数 myAtoi(string s) 的算法如下:读入字符串并丢弃无用的前导空格检查下一个字符(假设还未…...

毕业5年,从月薪3000到年薪40w,我掌握了那些核心技能?(建议收藏)
大家好,我是静静~~是一枚一线大厂的测试开发工程师很多读者私信问我,自己时间不短了,随着工作年限的不断增长,感觉自己的技术水平与自己的工作年限严重不符。想跳槽出去换个新环境吧,又感觉自己的能力达不到心仪公司的…...

C++中的并行与并发
1.1 并行基础std::thread 用于创建一个执行的线程实例,所以它是一切并发编程的基础,使用时需要包含 <thread> 头文件, 它提供了很多基本的线程操作,例如 get_id() 来获取所创建线程的线程 ID,使用 join() 来加入…...

h2database源码解析-如何更新一条行记录
这里的更新包括两种操作:删、改。更新操作涉及的内容在其他文章里面已经做过介绍了,本文主要是介绍更新的代码流程,以了解更新操作都做了哪些事情。如果有未介绍过的知识点会详细介绍。 目录改(update)如何判读是否加了行锁删(delete)改(upda…...

FyListen——生命周期监听器(设计原理之理解生命周期)
FyListen——生命周期监听器(设计原理之理解生命周期) FyListen 的核心原理有两个: 通过子Fragment对Activity、Fragment进行生命周期监听Java8 接口特性 default 1. 什么是上下文Context 这是一个装饰器模式, ContextImpl 是 …...

Element UI框架学习篇(六)
Element UI框架学习篇(六) 1 删除数据 1.1 前台核心函数 1.1.1 elementUI中的消息提示框语法 //①其中type类型和el-button中的type类型是一致的,有info灰色,success绿色,danger红色,warning黄色,primary蓝色 //②message是你所要填写的提示信息 //③建议都用,因为比双引号…...

Python如何安装模块,python模块安装失败的原因以及解决办法
前言 今天来给刚开始学习python的朋友讲解一下 如何安装python模块, python模块安装失败的原因以及解决办法 很多朋友拿到代码之后,就开始复制粘贴 --> 然后右键进行运行 结果就是报错说 没有这个模块 得安装啥的 Python模块安装 一. 打开命令提示符 win …...

《NFL橄榄球》:洛杉矶闪电·橄榄1号位
洛杉矶闪电(英语:Los Angeles Chargers),又译“洛杉磯衝鋒者”。是一支位于加利福尼亚州洛杉矶郡英格尔伍德的职业美式橄榄球球队,现为美国橄榄球联合会西区成员之一。该队曾于1961年搬迁到圣地亚哥而改叫圣地亚哥电光…...

4.7 Python设置代码格式
随着你编写的程序越来越长,有必要了解一些代码格式设置约定。请花时让你的代码尽可能易于阅读;让代码易于阅读有助于你掌握程序是做什么的,也可以帮助他人理解你编写的代码。为确保所有人编写的代码的结构都大致一致,Python程序员都遵循一些格…...

Zabbix 构建监控告警平台(五)
Zabbix 自动发现Zabbix 自动注册1.Zabbix 自动发现 1.1前言 为了满足监控企业成千上万台服务器,因此我们需要使用Zabbix批量监控来实现。自动发现和自动注册。 1.2zabbix-server (一)1、创建自动发现规则 在“配置”->“自动发现”->“…...

2023关键词:挑战
未失踪人口回归… 好久不见,不经意间拖更2个多月。今天周末,外面淅淅沥沥下着小雨,这种窝在床上的时刻最适合写点东西了。 但是建议大家在办公或者写博客的时候尽量还是端正坐姿,我就是因为喜欢这样靠在床背上,长时间…...

Wifi wpa_supplicant 到驱动的联系
同学,别退出呀,我可是全网最牛逼的 WIFI/BT/GPS/NFC分析博主,我写了上百篇文章,请点击下面了解本专栏,进入本博主主页看看再走呗,一定不会让你后悔的,记得一定要去看主页置顶文章哦。 从framework到wpa_supplicant的适配层,其中framework部分需要了注意的是wifiservic…...

【状态估计】基于二进制粒子群优化 (BPSO) 求解最佳 PMU优化配置研究【IEEE30、39、57、118节点】(Matlab代码实现)
💥💥💞💞欢迎来到本博客❤️❤️💥💥 🏆博主优势:🌞🌞🌞博客内容尽量做到思维缜密,逻辑清晰,为了方便读者。 ⛳️座右铭&a…...

python 将 .pdf 文件转为 .md
环境准备 pip install aspose-words 代码 doc aw.Document(r"pdf 文件路径\xxx.pdf") doc.save("Output.md") 来源:https://products.aspose.com/words/zh/python-net/conversion/...

【C语言】操作符详解
每天一篇博客,卷死各位。 文章目录前言1. 算术操作符2. 移位进制位的表示移位操作符1. 》--左移操作符2. 《--右移操作符3.位操作符4.赋值操作符5.单目操作符6.关系操作符7. 逻辑操作符8.条件操作符9.逗号操作符总结前言 在c语言学习中操作符尤为重要,而…...