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

C++:模拟实现string

目录

一:string类

二:构造函数、拷贝构造函数及析构函数

1、构造函数

2、拷贝构造函数

3、析构函数

三、实现string中对容量操作的成员函数

1、size

2、capacity

3、reserve

4、resize

5、clear

6、empty

四、string类中对象的增删查改操作

1、push_back

2、append

3、c_str

4、find

5、substr

6、insert

7、erase

五、string中重要的运算符重载

1、赋值运算符的重载

2、流插入 <<

3、流提取 >>

4、下标访问 []

5、加等一个字符 +=

6、加等字符串 +=

7、大于 >

8、等于 ==

9、小于 <

10、大于等于 >=

11、小于等于 <=

12、不等于 !=

六、迭代器

最后完整代码

string.h

string.c

test.c


一:string类

首先先定义一个string类

class string
{
public:private:char* _str = nullptr;size_t _size = 0;size_t _capacity = 0;
};

string的底层是一个个字符,所以定义一个_str 记录字符,_size用来记录这个字符串的长度,_capacity用来记录开了多少空间。


二:构造函数、拷贝构造函数及析构函数

1、构造函数

string的构造函数分为无参构造和有参构造,通过无参构造的对象会默认生成一个空字符串,因此我们可以带一个缺省值,在没有参数传递时就直接构造一空字符串

string(const char* str = ""):_str(new char[strlen(str) + 1]), _size(strlen(str)), _capacity(strlen(str))
{strcpy(_str, str);  //将str中的内容拷贝给_str
}

在开空间时,我们需要多开一个空间,因为strlen算出的大小不包括 '\0' ,因此我们需要给 '\0' 留一个空间。


2、拷贝构造函数

拷贝构造函数是默认成员函数,如果不写编译器会自动生成,对于内置类型完成浅拷贝,对于自定义类型调用其构造函数完成拷贝。对于string来说,如果不自己写拷贝构造函数会导致浅拷贝问题。

浅拷贝会使得两个对象指向同一块空间,两个对象在析构时都会调用自己的析构函数,这样同一块空间就会被析构两次;浅拷贝一个对象的数据改变,另一个对象的数据也改变,因为它们指向同一块空间地址。 一个对象被删除后,另一个对象无效

//浅拷贝实例
class ShallowCopyExample {
public:int* data;ShallowCopyExample(int value) {data = new int(value);}// 默认的拷贝构造函数是浅拷贝ShallowCopyExample(const ShallowCopyExample& other) = default;~ShallowCopyExample() {delete data;}
};int main() {ShallowCopyExample obj1(10);ShallowCopyExample obj2 = obj1;  // 浅拷贝// 问题:obj1和obj2的data指针指向同一内存// 当其中一个对象析构后,另一个对象的指针就悬空了
}

拷贝构造函数

string(const string& str):_str(new char[str._capacity+1]),_size(str._size),_capacity(str._capacity)
{strcpy(_str, str._str);
}

上面的这种写法是比较常见的一种写法,但是我们还有一种更加简便的写法。我们可以通过已经实现了的构造函数传一个常量字符串,即下面的str._str,来创建一个临时对象,然后将这个临时对象的成员与自己交换,这样也完成了拷贝构造。

void swap(string& s)
{std::swap(_str, s._str);std::swap(_size, s._size);std::swap(_capacity, s._capacity);
}
string(const string& str):_str(nullptr), _size(0), _capacity(0)
{//创建一个临时对象string tmp(str._str);swap(tmp);
}

但是,为了写成这个拷贝构造函数我们还写了一个swap函数,这这么就简便了呢?

那是因为通过查阅标准库我们发现swap函数也是一个string类中提供了的函数,因此我们不仅简便了拷贝构造函数的写法,还又完成了一个函数的实现。并且,因为tmp是一个局部对象,因此在出作用域后就会自动调用析构函数,所以交换后还可以清理掉原来的空间,一举两得。

3、析构函数

我们可以使用delete直接释放掉_str的空间

~string()
{delete[] _str;_str = nullptr;_size = _capacity = 0;
}

三、实现string中对容量操作的成员函数

1、size

size返回字符串有效字符的长度。我们可以直接返回其成员变量中的_szie。

size_t size() const
{return _size;
}

2、capacity

capacity返回空间总大小。我们可以直接返回其成员变量中的_capacity。

size_t capacity() const
{return _capacity;
}

3、reserve

reserve为字符串预留空间

void reserve(size_t n)
{if (n > _capacity){//创建一个临时变量,开n + 1个空间char* tmp = new char[n + 1];strcpy(tmp, _str);delete[] _str; //将原空间删除_str = tmp; // 将临时变量的空间给str_capacity = n;  // 预留多少字符给_capacity}
}

4、resize

resize 的功能是将有效字符的个数改成 n 个,多出的空间用字符 ch 填充。

_size < n < _capacity  先预留n大小的空间,直接用字符 填充 n - size 之间的位置,记住要在最后加上'\0'。

_size > n 直接将 n 的位置置换成'\0'。

n > _capacity 先预留 n 大小的空间,剩下的空间用字符 ch 填充,记住要在最后加上'\0'。

void resize(size_t n, char ch)
{if (n > _size){//先检查要不要扩容reserve(n);for (size_t i = _size; i < n; i++){_str[i] = ch;}_size = n;_str[_size] = '\0';}else{_str[_size] = '\0';_size = n;}
}

5、clear

作用是清空有效字符

void clear()
{_str[0] = '\0';_size = 0;
}

6、empty

empty的作用是检测字符串释放为空字符串,是返回true,否则返回false。

bool empty() const
{return _size == 0;
}

四、string类中对象的增删查改操作

1、push_back

在字符串后面插字符c

void string::push_back(char ch)
{if (_size == _capacity){reserve(_capacity == 0 ? 4 : _capacity * 2);}_str[_size] = ch;_size++;_str[_size] = '\0';
}

2、append

在字符串后面追加一个字符串

void string::append(const char* str)
{//先计算追加字符的个数size_t len = strlen(str);//如果 len + _size > _capacity 就需要扩容if (_capacity < len + _size){//重新申请预留空间reserve(len + _size);}//从_str + _size出位置开始复制strcpy(_str + _size, str);_size += len;
}

3、c_str

返回一个C风格的字符串

char* string::c_str() const
{return _str;
}

C风格字符串和string类字符串的区别

void test2()
{string s1("hello");s1 += '\0';s1 += "dafdsaf";cout << s1 << endl;cout << s1.c_str() << endl;
}

上述代码的执行结果是:

C风格字符串以 \0 结尾, 但是string类字符串不一定以 \0 结尾,依赖size()/lenth()。

4、find

在字符串中寻找一个字符,返回第一次出现的下标

npos是string类的静态成员变量,静态成员变量要在类外定义的。我们一般将它设为公共权限,并赋值为-1。

size_t string::find(const char sub, size_t pos) const
{assert(pos < _size);for (size_t i = pos; i < _size; i++){if (_str[i] == sub)return i;}return npos;
}

在字符串中找字符串

size_t string::find(const char* sub, size_t pos) const
{assert(pos < _size);const char* ptr = strstr(_str + pos, sub);if (ptr == nullptr){return npos;}else{//指针-指针就是指针之间的距离 return ptr - _str;}
}

5、substr

它的作用是在str中从pos位置开始,截取n个字符,然后将其返回。如果不传len,则默认截取从pos开始到结尾的全部字符。 如果 pos + n > _size, 说明要截取的字符大于str的长度,则截取从pos开始到结尾的全部字符。

string substr(size_t pos = 0, size_t len = npos) const;string string::substr(size_t pos, size_t len) const
{assert(pos < _size);size_t reallen = len;//如果从pos开始截取n个字符大于_size的长度,则截取这之间的全部字符if (reallen == npos || reallen + pos > _size){reallen = _size - pos;}string sub;for (size_t i = pos; i < reallen + pos; i++){sub += _str[i];}return sub;
}

6、insert

在指定位置前插入一个字符

string& insert(size_t pos, char ch);string& string::insert(size_t pos, char ch)
{assert(pos <= _size);if (_size == _capacity){reserve(_capacity == 0 ? 4 : _capacity * 2);}size_t end = size() + 1;while (end > pos){//把pos后面的字符往后挪_str[end] = _str[end - 1];end--;}_str[pos] = ch;_size++;return *this;
}

在指定位置前插入一个字符串


string& string::insert(size_t pos, const char* ch)
{assert(pos <= _size);//计算要插入的长度size_t len = strlen(ch);//如果要插入的长度加上原本的长度大于_capacity就需要扩容if (_size + len > _capacity){reserve(_size + len);}size_t end = _size + len;while (pos + len <= end){_str[end] = _str[end - len];end--;}//从pos位置开始复制要插入长度个字符strncpy(_str + pos, ch, len);_size += len;return *this;
}

7、erase

从pos开始删除n个字符

void erase(size_t pos, size_t len = npos);void string::erase(size_t pos, size_t len)
{assert(pos < _size);if (len == npos || len >= _size){_str[pos] = '\0';_size = pos;}else{//从pos位置开始复制strcpy(_str + pos, _str + pos + len);//_size减了,对应_str字符数也少了_size -= len;}
}

五、string中重要的运算符重载

1、赋值运算符的重载

编译器默认生成的赋值重载也会导致浅拷贝,所以我们需要实现深拷贝。

string& string::operator==(const string& str)
{//如果两个不是指向同一块空间if (this != &str){//创建一个临时数组char* tmp = new char[str._capacity + 1];strcpy(tmp, str._str);delete[] _str;_str = tmp;_size = str._size;_capacity = str._capacity;}return *this;
}

和拷贝构造函数一样,我们也可以用简便写法来实现赋值运算符的重载

string& string::operator=(const string& str)
{if (this != &str){string tmp(str);swap(tmp);}return *this;
}

2、流插入 <<

流插入和流提取都要在类外定义

ostream& operator<<(ostream& out, const string& s)
{for (size_t i = 0; i < s.size(); i++){out << s[i];}return out;
}

3、流提取 >>

	istream& operator>>(istream& in, string& s){s.clear();char ch;ch = in.get();const size_t N = 32;char buff[N];size_t i = 0;while (ch != ' ' && ch != '\n'){buff[i++] = ch;if (i == N - 1){buff[i] = '\0';s += buff;i = 0;}ch = in.get();}buff[i] = '\0';s += buff;}

4、下标访问 []

普通对象:可读可写

char& string::operator[](size_t pos)
{assert(pos < _size);return _str[pos];
}

const对象:可读不可写

	char& string::operator[](size_t pos) const{assert(pos < _size);return _str[pos];}

5、加等一个字符 +=

我们可以直接复用push_back来实现一个字符的加等

string& string::operator+=(char str)
{push_back(str);return *this;
}

6、加等字符串 +=

我们可以直接复用append来实现字符串的加等

	string& string::operator+=(const char* str){append(str);return *this;}

7、大于 >

bool string::operator>(const string& s) const
{return strcmp(_str, s._str) > 0;
}

strcmp通过比较两个字符串,如果s1 > s2,返回大于1的值;如果s1 < s2,返回小于1的值;如果s1 == s2,返回0;

8、等于 ==

bool string::operator==(const string& s) const
{return strcmp(_str, s._str) == 0;
}

9、小于 <

bool string:: operator<(const string& s) const
{return !(_str > s._str) && !(_str == s._str);
}

10、大于等于 >=

bool string::operator>=(const string& s) const
{return !(_str < s._str);
}

11、小于等于 <=

bool string::operator<=(const string& s) const
{return !(_str > s._str);
}

12、不等于 !=

bool string::operator!=(const string& s) const
{return !(_str == s._str);
}

六、迭代器

迭代器作为STL的六大组件之一,它的作用十分重要。而在string中迭代器的本质就是一个char*或const char*的指针。

typedef char* iterator;
typedef const char* const_iterator;
iterator begin()
{return _str;
}
const_iterator begin() const
{return _str;
}
iterator end()
{return _str + _size;
}
const_iterator end() const
{return _str + _size;
}

最后完整代码

string.h

#pragma once#include <iostream>
#include <assert.h>
//#include <string>
#include <string.h>
using namespace std;namespace meng
{class string{public:typedef char* iterator;typedef const char* const_iterator;iterator begin(){return _str;}const_iterator begin() const{return _str;}iterator end(){return _str + _size;}const_iterator end() const{return _str + _size;}string& operator+=(char str);string& operator+=(const char* str);string& operator=(const string& str);char& operator[](size_t pos);char& operator[](size_t pos) const;bool operator>(const string& s) const;bool operator<(const string& s) const;bool operator==(const string& s) const;bool operator>=(const string& s) const;bool operator<=(const string& s) const;bool operator!=(const string& s) const;////string(const char* str = ""):_str(new char[strlen(str) + 1]), _size(strlen(str)), _capacity(strlen(str)){strcpy(_str, str);  //将str中的内容拷贝给_str}void swap(string& s){std::swap(_str, s._str);std::swap(_size, s._size);std::swap(_capacity, s._capacity);}string(const string& str):_str(nullptr), _size(0), _capacity(0){//创建一个临时对象string tmp(str._str);swap(tmp);}~string(){delete[] _str;_str = nullptr;_size = _capacity = 0;}size_t size() const{return _size;}size_t capacity() const{return _capacity;}void reserve(size_t n);void resize(size_t n, char ch);void clear(){_str[0] = '\0';_size = 0;}bool empty() const{return _size == 0;}void push_back(char ch);void append(const char* str);char* c_str() const;//找一个字符串size_t find(const char* sub, size_t pos = 0) const;size_t find(const char sub, size_t pos = 0) const;string substr(size_t pos = 0, size_t len = npos) const;//insert//在指定位置前插入一个字符string& insert(size_t pos, char ch);//插入一个字符串string& insert(size_t pos, const char* ch);void erase(size_t pos, size_t len = npos);private:char* _str = nullptr;size_t _size = 0;size_t _capacity = 0;static const size_t npos;};ostream& operator<<(ostream& out, const string& s);istream& operator>>(istream& in, string& s);
}

string.c

#define _CRT_SECURE_NO_WARNINGS#include "string.h"namespace meng
{const size_t string::npos = -1;//运算符的重载string& string::operator+=(char str){push_back(str);return *this;}string& string::operator+=(const char* str){append(str);return *this;}//string& string::operator=(const string& str)//{//	//如果两个不是指向同一块空间//	if (this != &str)//	{//		//创建一个临时数组//		char* tmp = new char[str._capacity + 1];//		strcpy(tmp, str._str);//		delete[] _str;//		_str = tmp;//		_size = str._size;//		_capacity = str._capacity;//	}//	return *this;//}string& string::operator=(const string& str){if (this != &str){string tmp(str);swap(tmp);}return *this;}char& string::operator[](size_t pos){assert(pos < _size);return _str[pos];}char& string::operator[](size_t pos) const{assert(pos < _size);return _str[pos];}bool string::operator>(const string& s) const{return strcmp(_str, s._str) > 0;}bool string:: operator<(const string& s) const{return !(_str > s._str) && !(_str == s._str);}bool string::operator==(const string& s) const{return strcmp(_str, s._str) == 0;}bool string::operator>=(const string& s) const{return !(_str < s._str);}bool string::operator<=(const string& s) const{return !(_str > s._str);}bool string::operator!=(const string& s) const{return !(_str == s._str);}ostream& operator<<(ostream& out, const string& s){for (size_t i = 0; i < s.size(); i++){out << s[i];}return out;}istream& operator>>(istream& in, string& s){s.clear();char ch;ch = in.get();const size_t N = 32;char buff[N];size_t i = 0;while (ch != ' ' && ch != '\n'){buff[i++] = ch;if (i == N - 1){buff[i] = '\0';s += buff;i = 0;}ch = in.get();}buff[i] = '\0';s += buff;}////void string::reserve(size_t n){if (n > _capacity){//创建一个临时变量,开n + 1个空间char* tmp = new char[n + 1];strcpy(tmp, _str);delete[] _str; //将原空间删除_str = tmp; // 将临时变量的空间给str_capacity = n;  // 预留多少字符给_capacity}}void string::resize(size_t n, char ch){if (n > _size){//先检查要不要扩容reserve(n);for (size_t i = _size; i < n; i++){_str[i] = ch;}_size = n;_str[_size] = '\0';}else{_str[_size] = '\0';_size = n;}}void string::push_back(char ch){if (_size == _capacity){reserve(_capacity == 0 ? 4 : _capacity * 2);}_str[_size] = ch;_size++;_str[_size] = '\0';}void string::append(const char* str){//先计算追加字符的个数size_t len = strlen(str);//如果 len + _size > _capacity 就需要扩容if (_capacity < len + _size){//重新申请预留空间reserve(len + _size);}//从_str + _size出位置开始复制strcpy(_str + _size, str);_size += len;}char* string::c_str() const{return _str;}size_t string::find(const char sub, size_t pos) const{assert(pos < _size);for (size_t i = pos; i < _size; i++){if (_str[i] == sub)return i;}return npos;}size_t string::find(const char* sub, size_t pos) const{assert(pos < _size);const char* ptr = strstr(_str + pos, sub);if (ptr == nullptr){return npos;}else{//指针-指针就是指针之间的距离 return ptr - _str;}}string string::substr(size_t pos, size_t len) const{assert(pos < _size);size_t reallen = len;//如果从pos开始截取n个字符大于_size的长度,则截取这之间的全部字符if (reallen == npos || reallen + pos > _size){reallen = _size - pos;}string sub;for (size_t i = pos; i < reallen + pos; i++){sub += _str[i];}return sub;}string& string::insert(size_t pos, char ch){assert(pos <= _size);if (_size == _capacity){reserve(_capacity == 0 ? 4 : _capacity * 2);}size_t end = size() + 1;while (end > pos){//把pos后面的字符往后挪_str[end] = _str[end - 1];end--;}_str[pos] = ch;_size++;return *this;}string& string::insert(size_t pos, const char* ch){assert(pos <= _size);//计算要插入的长度size_t len = strlen(ch);//如果要插入的长度加上原本的长度大于_capacity就需要扩容if (_size + len > _capacity){reserve(_size + len);}size_t end = _size + len;while (pos + len <= end){_str[end] = _str[end - len];end--;}//从pos位置开始复制要插入长度个字符strncpy(_str + pos, ch, len);_size += len;return *this;}void string::erase(size_t pos, size_t len){assert(pos < _size);if (len == npos || len >= _size){_str[pos] = '\0';_size = pos;}else{//从pos位置开始复制strcpy(_str + pos, _str + pos + len);//_size减了,对应_str字符数也少了_size -= len;}}}

test.c

#define _CRT_SECURE_NO_WARNINGS#include "string.h"void test()
{string str("hello world");for (auto e : str)cout << e << ' ';cout << endl;//string::iterator it = str.begin()auto it = str.begin();while (it != str.end()){cout << *it << ' ';++it;}cout << endl;for (auto e : str){e += 2;cout << e << ' ';}cout << endl;cout << str << endl;//string::reverse_iterator a = str.rbegin();auto a = str.rbegin();while (a != str.rend()){cout << *a << ' ';++a;}cout << endl;
}namespace meng
{void test1(){string s1("hello world");cout << s1.size() << " " << s1.capacity() << endl;s1.reserve(16);cout << s1.capacity() << endl;//s1.resize(20, 'h');//cout << s1.c_str() << endl;//cout << s1.size() << " " << s1.capacity() << endl;//cout << s1.empty() << endl;s1.push_back('h');cout << s1.c_str() << endl;cout << s1.size() << " " << s1.capacity() << endl;s1.append("xxxxx");cout << s1.size() << " " << s1.capacity() << endl;cout << s1.c_str() << endl;cout << s1.find("xxx", 0) << endl;cout << s1.find('o', 0) << endl;string s2 = s1.substr(4, 5);cout << s2.c_str() << endl;string s3 = s1.insert(3, 'a');cout << s3.c_str() << endl;string s4 = s1.insert(3, "aaaaaa");cout << s4.c_str() << endl;s4.erase(3, 6);cout << s4.c_str() << endl;string s5 = s1; //拷贝构造cout << s5.c_str() << endl;cout << s1 << endl;cout << s4 << endl;cout << (s4 == s1) << endl;cout << (s4 != s1) << endl;cout << (s4 > s1) << endl;cout << (s4 < s1) << endl;}}void test2()
{string s1("hello");s1 += '\0';s1 += "dafdsaf";cout << s1 << endl;cout << s1.c_str() << endl;
}int main()
{//test();meng::test1();//test2();return 0;
}

相关文章:

C++:模拟实现string

目录 一&#xff1a;string类 二&#xff1a;构造函数、拷贝构造函数及析构函数 1、构造函数 2、拷贝构造函数 3、析构函数 三、实现string中对容量操作的成员函数 1、size 2、capacity 3、reserve 4、resize 5、clear 6、empty 四、string类中对象的增删查改操作 …...

Python 小练习系列 | Vol.14:掌握偏函数 partial,用函数更丝滑!

&#x1f9e9; Python 小练习系列 | Vol.14&#xff1a;掌握偏函数 partial&#xff0c;用函数更丝滑&#xff01; 本节的 Python 小练习系列我们将聚焦一个 冷门但高能 的工具 —— functools.partial。它的作用类似于“函数的预设模板”&#xff0c;能帮你写出更加灵活、优雅…...

处理Excel的python库openpyxl、xlrd、xlwt、pandas有什么区别,搞懂它

openpyxl、xlrd、xlwt、pandas 都能处理 Excel 表格&#xff0c;但用途和适合的场景不同。今天做个总结&#xff1a; 库名功能支持格式读写支持样式备注openpyxl全面的.xlsx处理库.xlsx&#xff08;Excel2007&#xff09;✅✅✅首选xlrd读取.xls文件的老牌工具.xls&#xff08…...

【OSG学习笔记】Day 1: OSG初探——环境搭建与第一个3D窗口

什么是 OSG&#xff1f; 全称&#xff1a;OpenSceneGraph&#xff08;开源场景图&#xff09; 定位&#xff1a;一个基于 C/OpenGL 的高性能开源3D图形开发工具包&#xff0c;专注于实时渲染和复杂场景管理。 核心思想&#xff1a;通过 场景图&#xff08;Scene Graph&#xf…...

linux--------------进程控制(下)

一、进程等待 1.1 进程等待必要性 子进程退出后&#xff0c;若父进程不管不顾&#xff0c;可能会产生 “僵尸进程”&#xff0c;进而造成内存泄漏。进程一旦变为僵尸状态&#xff0c;即使使用 kill -9 也无法将其杀死&#xff0c;因为无法杀死一个已死的进程。父进程需要了解…...

【Axure元件分享】移动端滑动拨盘日期选择器

在移动端产品设计中&#xff0c;日期选择器是用户交互中常见的组件&#xff0c;尤其在预订、日程管理等场景中扮演着关键角色。本文将介绍一款基于Axure的移动端滑动拨盘日期选择器元件&#xff0c;该元件通过模拟拨盘滑动交互效果&#xff0c;为用户提供直观日期选择体验。 下…...

基于 JavaWeb 的 SpringBoot 在线课程会员系统设计和实现(源码+文档+部署讲解)

技术范围&#xff1a;SpringBoot、Vue、SSM、HLMT、Jsp、PHP、Nodejs、Python、爬虫、数据可视化、小程序、安卓app、大数据、物联网、机器学习等设计与开发。 主要内容&#xff1a;免费功能设计、开题报告、任务书、中期检查PPT、系统功能实现、代码编写、论文编写和辅导、论文…...

Linux入门

复习:https://blog.csdn.net/ 操作系统概述 硬件和软件 计算机由硬件和软件组成 硬件:计算机系统中由电子,机械和光电元件等组成的各种物理装置的总称 软件:用户和计算机硬件之间的接口和桥梁,用户通过软件与计算机进行交流 而操作系统就是软件的一类. 操作系统 主要负…...

金融壹账通推出大模型一体机,加速金融行业AI落地与应用

在当前数字化和人工智能技术迅猛发展的背景下,金融行业正面临着效率提升、风险管控和客户体验优化的多重挑战。为应对这些需求,金融壹账通近期推出了全新的“大模型一体机”解决方案。该方案集算力、模型、工具链和应用场景于一体,不仅具备小投入、低门槛和私有化部署的优势,还…...

迁移WordPress网站(大文件版本)

安装插件All-in-One WP Migration&#xff0c;备份并下载文件&#xff0c;可以参考我的另外一篇文章wordpress 利用 All-in-One WP Migration全站转移使用工具解压缩.wpress文件 工具名称&#xff1a;wpress-extractor&#xff0c;github下载地址 或者 我已经上传&#xff0c;也…...

Linux普通用户怎么切换为root用户

在 Linux 中&#xff0c;普通用户切换到 root 用户的常用命令有以下几种&#xff1a; 切到root用户 sudo -i&#xff08;当前用户的密码&#xff09; su -&#xff08;需要知道root 密码&#xff09; 1. su 命令&#xff08;需要知道 root 密码&#xff09; su - 或 su - roo…...

WinForm真入门(11)——ComboBox控件详解

WinForm中 ComboBox 控件详解‌ ComboBox 是 WinForms 中一个集文本框与下拉列表于一体的控件&#xff0c;支持用户从预定义选项中选择或直接输入内容。以下从核心属性、事件、使用场景到高级技巧的全面解析&#xff1a; 一、ComboBox 核心属性‌ 属性说明示例‌Items‌下拉…...

Spring 服务调用接口时,提示You should be redirected automatically to target URL:

问题 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN"><title>Redirecting...</title><h1>Redirecting...</h1><p>You should be redirected automatically to target URL: <a href"http://xxx/api/v1/branch…...

OpenCV--模板匹配

一、引言 在计算机视觉领域&#xff0c;模板匹配是一种用于在图像中查找特定目标的基本技术。OpenCV 作为广泛使用的计算机视觉库&#xff0c;提供了强大且易于使用的模板匹配功能。无论是在工业检测、图像识别还是机器人视觉等领域&#xff0c;模板匹配都发挥着重要作用。本文…...

【Ragflow】14.MinerU解析脚本,接入ragflow知识库

概述 前文写了下 MinerU 的解析效果&#xff0c;收到不少读者催更&#xff0c;想利用 MinerU 替换 Deepdoc 的原始的解析器。 我认为&#xff0c;开发新功能基本可遵循能用-好用-用好这三个阶段&#xff1a; 能用&#xff1a;先通过脚本实现该功能,主打的是能用就行 好用&am…...

【SpringCloud】从入门到精通(上)

今天主播我把黑马新版微服务课程MQ高级之前的内容都看完了&#xff0c;虽然在看视频的时候也记了笔记&#xff0c;但是看完之后还是忘得差不多了&#xff0c;所以打算写一篇博客再温习一下内容。 课程坐标:黑马程序员SpringCloud微服务开发与实战 微服务 认识单体架构 单体架…...

第一章:SQL 基础语法与数据查询

1. 什么是 SQL&#xff1f;​​ ​​SQL&#xff08;Structured Query Language&#xff09;​​ 是用于管理和操作关系型数据库的标准语言。核心功能&#xff1a; ​​数据查询​​&#xff08;SELECT&#xff09;​​数据定义​​&#xff08;CREATE、ALTER、DROP&#xff0…...

Openlayers:海量图形渲染之WebGL渲染

最近由于在工作中涉及到了海量图形渲染的问题&#xff0c;因此我开始研究相关的解决方案。我在网络上寻找相关的解决方案时发现许多的文章都提到利用Openlayers中的WebGLPointsLayer类&#xff0c;可以实现渲染海量的点&#xff0c;之后我又了解到利用WebGLVectorLayer类可以渲…...

任务调度和安全如何结合

联邦学习与隐私保护 分布式模型训练&#xff1a;各边缘节点本地训练调度模型&#xff0c;仅共享模型参数而非原始数据&#xff0c;避免隐私泄露&#xff08;参考[11]的联邦学习框架&#xff09;。差分隐私&#xff1a;在奖励计算或状态反馈中加入噪声&#xff0c;防止通过调度…...

ARP攻击 DAI动态ARP检测学习笔记(超详细)

一、概述 ARP(Address Resolution Protocol,地址解析协议)是将IP地址解析为以太网MAC地址(或称为物理地址)的协议,指导三层报文的转发。ARP有简单、易用的优点,但是也因为其没有任何安全认证机制而容易被攻击者利用。属于是又爱又恨的一种协议了。目前ARP攻击和ARP病毒已经成为…...

Springboot--Kafka客户端参数关键参数的调整方法

调整 Kafka 客户端参数需结合生产者、消费者和 Broker 的配置&#xff0c;以实现性能优化、可靠性保障或资源限制。以下是关键参数的调整方法和注意事项&#xff1a; 一、生产者参数调整 ‌max.request.size‌ ‌作用‌&#xff1a;限制单个请求的最大字节数&#xff08;包括消…...

NO.79十六届蓝桥杯备战|数据结构-扩展域并查集-带权并查集|团伙|食物链|银河英雄传说(C++)

扩展域并查集 普通的并查集只能解决各元素之间仅存在⼀种相互关系&#xff0c;⽐如《亲戚》题⽬中&#xff1a; a 和b 是亲戚关系&#xff0c;b 和c 是亲戚关系&#xff0c;这时就可以查找出a 和c 也存在亲戚关系。 但如果存在各元素之间存在多种相互关系&#xff0c;普通并查…...

蓝桥杯2022年第十三届省赛真题-统计子矩阵

题目链接&#xff1a; 代码思路&#xff1a; ①枚举上、下边界。 ②求每一列前缀和。 ②固定上下边界后&#xff0c;在通过双指针确定子矩阵的左右边界。双指针维护一个窗口 [l, r]&#xff0c;确保窗口中所有列的和(下面前缀和-上面前缀和)不超过 K。通过滑动窗口方式&…...

openEuler24.03 LTS下安装Spark

目录 安装模式介绍 下载Spark 安装Local模式 前提条件 解压安装包 简单使用 安装Standalone模式 前提条件 集群规划 解压安装包 配置Spark 配置Spark-env.sh 配置workers 分发到其他机器 启动集群 简单使用 关闭集群 安装YARN模式 前提条件 解压安装包 配…...

openEuler24.03 LTS下安装Flink

目录 Flink的安装模式下载Flink安装Local模式前提条件解压安装包启动集群查看进程提交作业文件WordCount持续流WordCount 查看Web UI配置flink-conf.yaml简单使用 关闭集群 Standalone Session模式前提条件Flink集群规划解压安装包配置flink配置flink-conf.yaml配置workers配置…...

Redis 持久化

一、持久化 redis 虽然是个内存数据库&#xff0c;但是 redis 支持RDB 和 AOF 两种持久化机制&#xff0c; 将数据写往磁盘&#xff0c;可以有效的避免因进程退出造成的数据丢失问题&#xff0c;当下次重启时利用之前持久化的文件即可实现数据恢复。 二、Redis 支持RDB 和 AOF …...

塔能科技:智能路灯物联运维产业发展现状与趋势分析

随着智慧城市建设的推进&#xff0c;智能路灯物联运维产业正经历快速发展&#xff0c;市场规模持续扩大。文章探讨了智能路灯物联运维的技术体系、市场机遇和挑战&#xff0c;并预测了未来发展趋势&#xff0c;为行业发展提供参考。 关键词 智能路灯&#xff1b;物联运维&#…...

前端知识点---闭包(javascript)

文章目录 1.怎么理解闭包?2.闭包的特点3.闭包的作用?4 闭包注意事项&#xff1a;5 形象理解 1.怎么理解闭包? 函数里面包着另一个函数&#xff0c;并且内部函数可以访问外部函数的变量。 <script>function outer(){let count 0return functioninner (){countconsole.l…...

单次 CMS Old GC 耗时长问题分析与优化

目录 一、现象说明 二、CMS GC 机制简述 三、可能导致长时间停顿的原因详细分析 &#xff08;一&#xff09;Full GC&#xff08;完全垃圾回收&#xff09; 1. 主要原因 2.参数调整 &#xff08;二&#xff09;Promotion Failure&#xff08;晋升失败&#xff09; 1. 主…...

Python星球日记 - 第16天:爬虫基础(仅学习使用)

&#x1f31f;引言&#xff1a; 上一篇&#xff1a;Python星球日记 - 第15天&#xff1a;综合复习&#xff08;回顾前14天所学知识&#xff09; 名人说&#xff1a;不要人夸颜色好&#xff0c;只留清气满乾坤&#xff08;王冕《墨梅》&#xff09; 创作者&#xff1a;Code_流苏…...

【回眸】Linux 内核 (十四)进程间通讯 之 信号量

前言 信号量概念 信号量常用API 1.创建/获取一个信号量 2.改变信号量的值 3. 控制信号量 信号量函数调用 运行结果展示 前言 上一篇文章介绍的共享内存有局限性,如:同步与互斥问题、内存管理复杂性问题、数据结构限制问题、可移植性差问题、调试困难问题。本篇博文介…...

Python 字典和集合(字典的变种)

本章内容的大纲如下&#xff1a; 常见的字典方法 如何处理查找不到的键 标准库中 dict 类型的变种set 和 frozenset 类型 散列表的工作原理 散列表带来的潜在影响&#xff08;什么样的数据类型可作为键、不可预知的 顺序&#xff0c;等等&#xff09; 字典的变种 这一节总结了…...

LeetCode】寻找重复子树:深度解析与高效解法

&#x1f4d6; 问题描述 给定一棵二叉树的根节点 root &#xff0c;返回所有重复的子树。若两棵树结构相同且节点值相同&#xff0c;则认为它们是重复的。对于同类重复子树&#xff0c;只需返回其中任意一棵的根节点。 &#x1f330; 示例解析 示例1 输入&#xff1a; 1/ …...

[蓝桥杯] 挖矿(CC++双语版)

题目链接 P10904 [蓝桥杯 2024 省 C] 挖矿 - 洛谷 题目理解 我们可以将这道题中矿洞的位置理解成为一个坐标轴&#xff0c;以题目样例绘出坐标轴&#xff1a; 样例&#xff1a; 输入的5为矿洞数量&#xff0c;4为可走的步数。第二行输入是5个矿洞的坐标。输出结果为在要求步数…...

Appium如何实现移动端UI自动化测试?

&#x1f345; 点击文末小卡片&#xff0c;免费获取软件测试全套资料&#xff0c;资料在手&#xff0c;涨薪更快 Appium是一个开源跨平台移动应用自动化测试框架。 既然只是想学习下Appium如何入门&#xff0c;那么我们就直奔主题。文章结构如下&#xff1a; 为什么要使用A…...

在集合中哪些可以为null,哪些不能为null;Java 集合中 null 值允许情况总结与记忆技巧

Java 集合中 null 值允许情况总结与记忆技巧 一、核心集合对 null 的支持情况 集合类型Key 是否可为 nullValue 是否可为 null原因/备注HashMap✅ 是✅ 是对 null key 有特殊处理&#xff08;存放在数组第 0 个位置&#xff09;LinkedHashMap✅ 是✅ 是继承自 HashMapTreeMap…...

Python 并发编程指南:协程 vs 多线程及其他模型比较

Python 并发编程指南&#xff1a;协程 vs 多线程及其他模型比较 并发编程是指在单个程序中同时处理多个任务的能力&#xff0c;这些任务可以交替进行&#xff08;同一时刻并不一定真的同时运行&#xff09;&#xff0c;而并行则强调在同一时刻真正同时运行多个任务&#xff08…...

WPS JS宏编程教程(从基础到进阶)-- 第五部分:JS数组与WPS结合应用

目录 摘要第5章 JS数组与WPS结合应用5-1 JS数组的核心特性核心特性解析5-2 数组的两种创建方式(字面量与扩展操作符)1. 字面量创建2. 扩展操作符创建5-3 数组创建应用:提取字符串中的数字需求说明代码实现5-4 用函数创建数组(new Array、Array.of、Array.from)1. new Arra…...

STM32定时器完全指南:从基础原理到高级应用 | 零基础入门STM32第九十六步

主题内容教学目的/扩展视频TIM定时器重点课程定时器&#xff0c;捕获器&#xff0c;比较器&#xff0c;PWM&#xff0c;单脉冲。高级TIM。定时器中断。了解TIM使用 师从洋桃电子&#xff0c;杜洋老师 &#x1f4d1;文章目录 一、定时器核心原理1.1 硬件架构解析1.2 核心参数公式…...

Kafka分区机制详解:原理、策略与应用

#作者&#xff1a;张桐瑞 文章目录 一、分区的作用二、分区策略&#xff08;一&#xff09;轮询策略&#xff08;二&#xff09;随机策略&#xff08;三&#xff09;按消息键保序策略 三、实际案例&#xff1a;消息顺序问题的解决四、其他分区策略&#xff1a;基于地理位置的分…...

最小K个数

文章目录 题意思路代码 题意 题目链接 思路 代码 class Solution { public:vector<int> smallestK(vector<int>& arr, int k) {priority_queue<int> Q;for (auto &index:arr){Q.push(index);if (Q.size() > k)Q.pop();}vector<int> ans…...

【STL】list介绍(附与vector的比较)

文章目录 1.关于list2.使用2.1 list的构造2.2 list 迭代器的使用2.3 list 容量操作2.3.1 size()2.3.2 empty()2.3.3 resize() 2.4 list 元素访问2.4.1 front()2.4.2 back() 2.5 list 修改操作2.5.1 push_front()2.5.2 pop_front()2.5.3 push_back()2.5.4 pop_back()2.5.5 inser…...

音视频生命探测仪,救援现场的“视听先锋”|鼎跃安全

地震等自然灾害的突发性和破坏性对人类生命构成严重威胁。据统计&#xff0c;地震后的“黄金72小时”内&#xff0c;被困者的存活率随时间的推移急剧下降&#xff0c;因此快速、精准的搜救技术至关重要。 传统搜救手段依赖人耳识别呼救声或手动挖掘&#xff0c;效率低且易造成二…...

Arch视频播放CPU占用高

Arch Linux配置视频硬件加速 - DDoSolitary’s Blog 开源神器&#xff1a;加速你的视频体验 —— libvdpau-va-gl-CSDN博客 VDPAU&#xff08;Video Decode and Presentation API for Unix&#xff09; VA-API&#xff08;Video Acceleration API&#xff09; OpenGL 我的电…...

Python技巧:二维列表 和 二维矩阵 的区别

np.vstack 是 NumPy 中的一个函数&#xff0c;用于将多个数组沿垂直方向&#xff08;行方向&#xff09;堆叠。它可以处理 二维列表 和 二维矩阵&#xff0c;但它们之间有一些关键区别。以下是详细说明&#xff1a; 1. 二维列表 定义: 二维列表是 Python 原生的数据结构&#x…...

Linux 命令清单(Linux Command List)

测试人员必备的 Linux 命令清单文件管理 ls —— 显示目录内容。 ls -l 使用 -l 选项查看详细信息。 cd —— 改变当前工作目录。 cd /path/to/directory mkdir —— 创建新目录。 mkdir new_directory rm —— 删除文件或目录。 rm filename rm -r directory 使用 …...

Wallaby‘s: Nightmare (v1.0.2)靶场渗透

Wallabys: Nightmare (v1.0.2) 来自 <Wallabys: Nightmare (v1.0.2) ~ VulnHub> 1&#xff0c;将两台虚拟机网络连接都改为NAT模式 2&#xff0c;攻击机上做namp局域网扫描发现靶机 nmap -sn 192.168.23.0/24 那么攻击机IP为192.168.23.182&#xff0c;靶场IP192.168.23…...

java基础 可拆分迭代器 Spliterator<T>

Spliterator Spliterator介绍核心方法tryAdvanceforEachRemainingtrySplitestimateSizetrySplit 结合并行流&#xff08;Parallel Stream&#xff09;关键注意事项总结 Spliterator介绍 Spliterator&#xff08;Splittable Iterator&#xff09;是 Java 8 引入的接口&#xff…...

【AI提示词】决策专家

提示说明 决策专家可以帮助你进行科学决策&#xff0c;尽可能避免错误&#xff0c;提升决策成功的概率。 提示词 # Role : 决策专家决策&#xff0c;是面对不容易判断优劣的几个选项&#xff0c;做出正确的选择。说白了&#xff0c;决策就是拿个主意。决策专家是基于科学决策…...

VectorBT量化入门系列:第二章 VectorBT核心功能与数据处理

VectorBT量化入门系列&#xff1a;第二章 VectorBT核心功能与数据处理 本教程专为中高级开发者设计&#xff0c;系统讲解VectorBT技术在量化交易中的应用。通过结合Tushare数据源和TA-Lib技术指标&#xff0c;深度探索策略开发、回测优化与风险评估的核心方法。从数据获取到策略…...