C++【string类,模拟实现string类】
🌟个人主页:落叶
🌟当前专栏: C++专栏
目录
为什么学习string类
C语言中的字符串
标准库中的string类
auto和范围for
auto关键字
迭代器
范围for
string类的常用接口说明和使用
1. string类对象的常见构造
2.string类对象的容量操作
3.string类对象的访问及遍历操作
4. string类对象的修改操作
【push_back】在字符串后尾插字符c
【append】在字符串后追加一个字符串
【find + npos(重 点)】从字符串pos位置开始往后找字符c,返回该字符在字符串中的 位置
【rfind】从字符串pos位置开始往前找字符c,返回该字符在字符串中的 位置。
【erase】从字符串中删除字符
5.string类非成员函数
【operator+】尽量少用,因为传值返回,导致深拷贝效率低
【operator>> (重点)】输入运算符重载
【operator<< (重点)】输出运算符重载
【getline (重点)】获取一行字符串
【relational operators (重点)】大小比较
string类的模拟实现
经典的string类问题
浅拷贝
深拷贝
浅拷贝(Shallow Copy)
深拷贝(Deep Copy)
写时拷贝(了解)
为什么学习string类
C语言中的字符串
C语言中,字符串是以'\0'结尾的一些字符的集合,为了操作方便,C标准库中提供了一些str系列 的库函数,但是这些库函数与字符串是分离开的,不太符合OOP的思想,而且底层空间需要用户 自己管理,稍不留神可能还会越界访问。
标准库中的string类
在使用string类时,必须包含#include头文件以及using namespace std;
auto和范围for
auto关键字
在这里补充2个C++11的小语法,方便我们后面的学习。
- 在早期C/C++中auto的含义是:使用auto修饰的变量,是具有自动存储器的局部变量,后来这个 不重要了。C++11中,标准委员会变废为宝赋予了auto全新的含义即:auto不再是一个存储类型 指示符,而是作为一个新的类型指示符来指示编译器,auto声明的变量必须由编译器在编译时期 推导而得。
- 用auto声明指针类型时,用auto和auto*没有任何区别,但用auto声明引用类型时则必须加&
- 当在同一行声明多个变量时,这些变量必须是相同的类型,否则编译器将会报错,因为编译器实际 只对第一个类型进行推导,然后用推导出来的类型定义其他变量。
- auto不能作为函数的参数,可以做返回值,但是建议谨慎使用
- auto不能直接用来声明数组
auto声明的变量编译器会推导而得类型。
这个typeid是获取变量的真实的类型,
我们可以看到类型是对得上的。
不能没有值
// 编译报错:rror C3531: “e”: 类型包含“auto”的符号必须具有初始值设定项auto e;
auto不能作为函数的参数,可以做返回值,但是建议谨慎使用
auto不能用来声明数组
当在同一行声明多个变量时,这些变量必须是相同的类型,否则编译器将会报错,因为编译器实际 只对第一个类型进行推导,然后用推导出来的类型定义其他变量。
迭代器
https://legacy.cplusplus.com/reference/string/string/begin/
迭代器类似于指针,它指向容器中的一个元素,并且可以通过递增或递减来移动到下一个或前一个元素。迭代器提供了一组操作,如解引用(*),递增(++),递减(--),比较(==, !=)等。
add.begin()是指向第一个元素,
add.end()是指向最后一个元素,
通过i遍历每个字符
在这个例子中,add.begin
()
返回一个指向vec
第一个元素的迭代器,add.end()
返回一个指向add最后一个元素之后位置的迭代器。循环中,i
被用来遍历add中的元素,*i
用来访问当前元素的值。
迭代器使得算法可以与容器解耦,提高了代码的复用性和灵活性。
范围for
- 对于一个有范围的集合而言,由程序员来说明循环的范围是多余的,有时候还会容易犯错误。因此 C++11中引入了基于范围的for循环。for循环后的括号由冒号“ :”分为两部分:第一部分是范围 内用于迭代的变量,第二部分则表示被迭代的范围,自动迭代,自动取数据,自动判断结束。
- 范围for可以作用到数组和容器对象上进行遍历
- 范围for的底层很简单,容器遍历实际就是替换为迭代器,这个从汇编层也可以看到。
范围for底层就是迭代器,范围for可以作用到数组和容器对象上进行遍历。
为什么要在auto后面加引用呢?
通过引用遍历可以避免不必要的拷贝构造函数的调用,从而提高性能。
这样做有几个优点:
性能优化:如果容器中的元素很大,或者元素是复杂类型(如类对象),通过引用遍历可以避免不必要的拷贝构造函数的调用,从而提高性能。
修改元素:如果需要在循环中修改容器中的元素,必须通过引用来遍历它们。如果不使用引用,循环变量将是容器中元素的一个副本,对
副本的修改不会影响到原始容器中的元素。
举个例子,auto&
告诉编译器,num
是一个引用 add容器中的实际元素,而不是一个副本。因此,如果对 num
的修改会直接 add中的元素。
string类的常用接口说明和使用
在C++中,std::string
类是标准库的一部分,它提供了一个方便的接口来处理字符串。std::string
位于 <string>
头文件中,并且是 std
命名空间的一部分。
#include<string>
1. string类对象的常见构造
https://legacy.cplusplus.com/reference/string/string/string/
(constructor)函数名称 | 功能说明 |
string() (重点) | 构造空的string类对象,即空字符串 |
string(const char* s) (重点) | 用C-string来构造string类对象 |
string(size_t n, char c) | string类对象中包含n个字符c |
string(const string&s) (重点) | 拷贝构造函数 |
#include<iostream>
using namespace std;
#include<string>int main()
{string s1; //构造空的string对象string s2("hello");//用字符串构造string对象string s3(10, 'w');//用10个w构造string对象string s4(s2); //拷贝构造函数return 0;
}
2.string类对象的容量操作
函数名称 | 功能说明 |
size(重点) | 返回字符串有效字符长度 |
capacity | 返回空间总大小 |
empty (重点) | 检测字符串释放为空串,是返回true,否则返回false |
clear (重点) | 清空有效字符 |
reserve (重点) | 为字符串预留空间** |
resize (重点) | 将有效字符的个数该成n个,多出的空间用字符c填充 |
size我们可以看到字符串有效字符长度是5
https://legacy.cplusplus.com/reference/string/string/size/
capacity返回空间总大小
https://legacy.cplusplus.com/reference/string/string/capacity/
明明只有4个字符,空间大小怎么会是15呢?
因为底层有个16大小的数组存放数据,
当我们给满16个字符,会自动扩容到32大小的空间。
empty(重点)检测字符串释放为空串,是返回true,否则返回false
https://legacy.cplusplus.com/reference/string/string/empty/
是空字符串返回true就是1,不是空字符串返回false就是0
clear (重点)清空有效字符
https://legacy.cplusplus.com/reference/string/string/clear/
我们可以看到清空了有效字符,但是空间大小不变。
reserve (重点)为字符串预留空间**
https://legacy.cplusplus.com/reference/string/string/reserve/
reserve 也就是扩容空间的意思。
数据很多的话,我们可以提前扩容空间避免多次2倍扩容。
resize (重点)将有效字符的个数改成n个,多出的空间用\0填充
https://legacy.cplusplus.com/reference/string/string/resize/
字符不变,多出来的空间都用\0填充。
这里是3,abc保留,cdef被清除。
注意: 1. size()与length()方法底层实现原理完全相同,引入size()的原因是为了与其他容器的接 口保持一致,一般情况下基本都是用size()。
2. clear()只是将string中有效字符清空,不改变底层空间大小。
3. resize(size_t n) 与 resize(size_t n, char c)都是将字符串中有效字符个数改变到n个,不 同的是当字符个数增多时:resize(n)用0来填充多出的元素空间,resize(size_t n, char c)用字符c来填充多出的元素空间。注意:resize在改变元素个数时,如果是将元素个数 增多,可能会改变底层容量的大小,如果是将元素个数减少,底层空间总大小不变。
4. reserve(size_t res_arg=0):为string预留空间,不改变有效元素个数,当reserve的参 数小于string的底层空间总大小时,reserver不会改变容量大小。
3.string类对象的访问及遍历操作
函数名称 | 功能说明 |
operator[] (重 点) | 返回pos位置的字符,const string类对象调用 |
begin+ end | begin获取一个字符的迭代器 + end获取最后一个字符下一个位 置的迭代器 |
rbegin + rend | begin获取一个字符的迭代器 + end获取最后一个字符下一个位 置的迭代器 |
范围for | C++11支持更简洁的范围for的新遍历方式 |
operator[] (重 点)返回pos位置的字符,const string类对象调用】
https://legacy.cplusplus.com/reference/string/string/operator[]/
rbegin + rend begin获取一个字符的迭代器 + end获取最后一个字符下一个位 置的迭代器。
https://legacy.cplusplus.com/reference/string/string/rbegin/
正向迭代器是iterator,反向迭代器是reverse_iterator。
reverse_iterator
是标准库提供的一种迭代器适配器,它允许我们以逆序的方式遍历容器。reverse_iterator
的设计是为了简化反向遍历容器的过程,使得我们可以像使用普通迭代器一样使用它,但方向相反。
以下是使用 reverse_iterator
的几个主要原因:
1.简化代码:使用
reverse_iterator
可以避免手动计算容器的结束位置和开始位置之间的偏移量,从而简化代码。2.一致性:它提供了一种与普通迭代器使用方式一致的方法来反向遍历容器,使得代码更加直观和易于理解。
3.与算法兼容:许多标准库算法都设计为与迭代器一起工作。通过使用
reverse_iterator
,我们可以将这些算法应用于容器的反向遍历,而无需修改算法本身。4.安全性:使用
reverse_iterator
可以减少由于手动计算迭代器位置而可能引入的错误。
4. string类对象的修改操作
函数名称 | |
push_back | 在字符串后尾插字符c |
append | 在字符串后追加一个字符串 |
operator+= (重 点) | 在字符串后追加字符串str |
c_str(重点) | 返回C格式字符串 |
find + npos(重 点) | 从字符串pos位置开始往后找字符c,返回该字符在字符串中的 位置 |
rfind | 从字符串pos位置开始往前找字符c,返回该字符在字符串中的 位置 |
substr | 在str中从pos位置开始,截取n个字符,然后将其返回 |
erase | 从字符串中删除字符 |
【push_back】在字符串后尾插字符c
https://legacy.cplusplus.com/reference/string/string/push_back/
【append】在字符串后追加一个字符串
https://legacy.cplusplus.com/reference/string/string/append/
abcdefg插入了1111的后面
【operator+= (重 点)】 在字符串后追加字符串str
https://legacy.cplusplus.com/reference/string/string/operator+=/
可以+=字符串和字符
也可以+=一个对象
【c_str(重点)】返回C格式字符串
https://legacy.cplusplus.com/reference/string/string/c_str/
可以返回字符串
【find + npos(重 点)】从字符串pos位置开始往后找字符c,返回该字符在字符串中的 位置
https://legacy.cplusplus.com/reference/string/string/find/
在字符串中查找内容
下面我们可以看到,从0下标位置开始查找9这个字符,找到了返回9的下标,没有找到返回-1
没有找到交换返回-1
【rfind】从字符串pos位置开始往前找字符c,返回该字符在字符串中的 位置。
https://legacy.cplusplus.com/reference/string/string/rfind/
我们不写下标,默认从最后一个下标开始往前查找。
找到了返回下标,没有找到返回-1。
【substr 】 在str中从pos位置开始,截取n个字符,然后将其返回
https://legacy.cplusplus.com/reference/string/string/substr/
从3下标开始截取4个字符,给s2。
我们也可以用find查找a这个下标, 然后通过i下标这个位置截取3个字符。
【erase】从字符串中删除字符
https://legacy.cplusplus.com/reference/string/string/erase/
下面我们可以看到,从下标1删除到下标5,就只剩下a和g了。
5.string类非成员函数
函数 | 功能说明 |
operator+ | 尽量少用,因为传值返回,导致深拷贝效率低 |
operator>> (重点) | 输入运算符重载 |
operator<< (重点) | 输出运算符重载 |
getline (重点) | 获取一行字符串 |
relational operators (重点) | 大小比较 |
【operator+】尽量少用,因为传值返回,导致深拷贝效率低
https://legacy.cplusplus.com/reference/string/string/operator+/
我们可以看到s1是您好,s2是落叶,加起来就是您好落叶。
我们也可以加字符串
【operator>> (重点)】输入运算符重载
https://legacy.cplusplus.com/reference/string/string/operator%3E%3E/
可以往s1对象,输入字符串,
但是遇到空格就会停止
【operator<< (重点)】输出运算符重载
https://legacy.cplusplus.com/reference/string/string/operator%3C%3C/
【getline (重点)】获取一行字符串
https://legacy.cplusplus.com/reference/string/string/getline/
这个它遇到空格不会停止,会继续往后读取字符串,也会把空格给读取了。
【relational operators (重点)】大小比较
https://legacy.cplusplus.com/reference/string/string/operators/
计算比较大小,如果大于为真,返回1,为假返回0。
string类的模拟实现
经典的string类问题
上面已经对string类进行了简单的介绍,大家只要能够正常使用即可。在面试中,面试官总喜欢让 学生自己来模拟实现string类,最主要是实现string类的构造、拷贝构造、赋值运算符重载以及析 构函数。大家看下以下string类的实现是否有问题?
// 为了和标准库区分,此处使用String
class String
{
public:/*String():_str(new char[1]){*_str = '\0';}*///String(const char* str = "\0") 错误示范//String(const char* str = nullptr) 错误示范String(const char* str = ""){// 构造String类对象时,如果传递nullptr指针,可以认为程序非if (nullptr == str){assert(false);return;}_str = new char[strlen(str) + 1];strcpy(_str, str);}~String(){if (_str){delete[] _str;_str = nullptr;}}
private:char* _str;
};
// 测试
void TestString()
{String s1("hello bit!!!");String s2(s1);
}
说明:上述String类没有显式定义其拷贝构造函数与赋值运算符重载,此时编译器会合成默认 的,当用s1构造s2时,编译器会调用默认的拷贝构造。最终导致的问题是,s1、s2共用同一块内 存空间,在释放时同一块空间被释放多次而引起程序崩溃,这种拷贝方式,称为浅拷贝。
浅拷贝
浅拷贝:也称位拷贝,编译器只是将对象中的值拷贝过来。如果对象中管理资源,最后就会导致 多个对象共享同一份资源,当一个对象销毁时就会将该资源释放掉,而此时另一些对象不知道该 资源已经被释放,以为还有效,所以当继续对资源进项操作时,就会发生发生了访问违规。
就像一个家庭中有两个孩子,但父母只买了一份玩具,两个孩子愿意一块玩,则万事大吉,万一 不想分享就你争我夺,玩具损坏。
可以采用深拷贝解决浅拷贝问题,即:每个对象都有一份独立的资源,不要和其他对象共享。父 母给每个孩子都买一份玩具,各自玩各自的就不会有问题了。
深拷贝
如果一个类中涉及到资源的管理,其拷贝构造函数、赋值运算符重载以及析构函数必须要显式给 出。一般情况都是按照深拷贝方式提供。
浅拷贝(Shallow Copy)
浅拷贝通常指的是对象之间的简单位拷贝(bitwise copy),这意味着新对象和原对象将共享相同的资源。在C++中,如果你没有显式地定义拷贝构造函数和赋值运算符,编译器会为你生成默认的版本,这些默认版本执行的是浅拷贝。
对于
std::string
来说,浅拷贝是不存在的,因为std::string
内部管理着自己的动态内存。当你进行拷贝构造或赋值操作时,std::string
会执行深拷贝。这意味着新创建的字符串对象拥有自己独立的内存空间,与原字符串对象不共享任何资源。深拷贝(Deep Copy)
深拷贝指的是创建一个新对象,并且递归地复制原对象中的所有元素,使得新对象和原对象完全独立。在
std::string
的情况下,每次你进行拷贝构造或赋值操作时,都会执行深拷贝
stringl类模拟实现【代码】
string.h
#define _CRT_SECURE_NO_WARNINGS 1#pragma once
#include<iostream>
#include<assert.h>
using namespace std;namespace bit
{class string{public://迭代器typedef char* iterator;static const int npos;string(const char* str = "");string(const string& s);~string();///扩容void reserve(size_t n);//尾插字符void push_back(char ch);//尾插字符串void append(const char* str);string& operator+=(char ch);string& operator+=(const char* str);//传统string& operator=(const string& s);//现代string& operator=(string s);//清除字符void clear(){_str[0] = '\0';_size = 0;}//首字符iterator begin(){return _str;}//最后的iterator end(){return _str + _size;}//返回_strchar* c_str() const{return _str;}//size_t size()const{return _size;}size_t capacity()const{return _capacity;}//指定位置修改字符char& operator[](size_t index){assert(index < _size);return _str[index];}//指定位置修改字符const char& operator[](size_t index)const{assert(index < _size);return _str[index];}////查询字符size_t find(char ch, size_t pos = 0);//查询字符串size_t find(const char* str, size_t pos = 0);//指定位置插入字符string& insert(size_t pos, char c);//指定位置插入字符串string& insert(size_t pos, const char* str);// 删除pos位置上的元素,并返回该元素的下一个位置string& erase(size_t pos, size_t len);//调整字符串大小void resize(size_t n, char c = '\0');//判断字符串是不是空bool empty()const;//字符串交换void swap(string& s){std::swap(_str, s._str);std::swap(_size, s._size);std::swap(_capacity, s._capacity);}void swap(string& s, string& s1){s.swap(s1);}//流插入friend ostream& operator<<(ostream& _cout, const bit::string& s);//流提取friend istream& operator>>(istream& _cin, bit::string& s);private:char* _str;size_t _size;size_t _capacity;};//判断大于-小于-大于等于 - 小于等于 - 等于 - 不等于bool operator<(const string& lhs, const string& rhs);bool operator>(const string& lhs, const string& rhs);bool operator<=(const string& lhs, const string& rhs);bool operator>=(const string& lhs, const string& rhs);bool operator==(const string& lhs, const string& rhs);bool operator!=(const string& lhs, const string& rhs);
}
string.cpp
#include"string.h"namespace bit
{const int string::npos = -1;//构造string::string(const char* str):_size(strlen(str)){_capacity = _size;_str = new char[_size + 1];strcpy(_str, str);}深拷贝-(传统写法)//string::string(const string& s)//{// _str = new char[s._capacity + 1];// strcpy(_str, s._str);// _size = s._size;// _capacity = s._capacity;//}//深拷贝-(现代写法)string::string(const string& s){string tmp(s._str);swap(tmp);}//析构string::~string(){delete[] _str;_str = nullptr;_size = 0;_capacity = 0;}/////扩容void string::reserve(size_t n){cout << "reserve:"<< n << endl;if (n > _capacity){char* tmp = new char[n + 1];strcpy(tmp, _str);delete[] _str;_str = tmp;_capacity = n;}}//尾插字符void string::push_back(char ch){if (_size == _capacity){reserve(_capacity == 0 ? 4 : _capacity * 2);}_str[_size] = ch;_size++;}//尾插字符串void string::append(const char* str){size_t len = strlen(str);if ((_size + len) > _capacity){size_t tmp = _capacity * 2;if (tmp < (_size + len)){tmp = (_size + len);}reserve(tmp);}strcpy(_str + _size, str);_size += len;}string& string::operator+=(char ch){push_back(ch);return *this;}string& string::operator+=(const char* str){append(str);return *this;}赋值-(传统写法)//string& string::operator=(const string& s)//{// if (this != &s)// {// delete[] _str;// _str = new char[s._capacity + 1];// strcpy(_str, s._str);// _size = s._size;// _capacity = s._capacity;// }// return *this;//}//赋值-(现代写法) string& string::operator=(string s){swap(s);return *this;}//查询字符size_t string::find(char ch, size_t pos){assert(pos < _size);for (size_t i = pos; i < _size; i++){if (ch == _str[i]){return i;}}return npos;}//查询字符串size_t string::find(const char* str, size_t pos){assert(pos < _size);const char* tmp = strstr(_str + pos, str);if (tmp == __nullptr){return npos;}return tmp - _str;}//在字符串里插入字符string& string::insert(size_t pos, char ch){assert(pos < _size);if (_size == _capacity){reserve(_capacity == 0 ? 4 : _capacity * 2);}//循环移动字符int i = _size;while ((int)pos <= i){_str[i + 1] = _str[i];i--;}//在pos位置插入字符_str[pos] = ch;_size++;return *this;}//指定位置插入字符串string& string::insert(size_t pos, const char* str){size_t len = strlen(str);if ((_size + len) > _capacity){size_t tmp = _capacity * 2;if (tmp < (_size + len)){tmp = (_size + len);}reserve(tmp);}//循环往后移动字符size_t i = _size + len;while (pos < i){_str[i] = _str[i - len];i--;}//循环把str的字符一个一个,赋值给_str[pos+i]的位置for (size_t i = 0; i < len; i++){_str[pos + i] = str[i];}_size + len;return *this;}//指定位置删除字符串string& string::erase(size_t pos, size_t len){if (len >= _size - pos){_str[pos] = '\0';_size = pos;}else{size_t i = pos + len;while (i <= _size){_str[i - len] = _str[i];i++;}_size = _size - len;}return *this;}//判断大于-小于-大于等于 - 小于等于 - 等于 - 不等于bool operator<(const string& lhs, const string& rhs){return strcmp(lhs.c_str(), rhs.c_str()) < 0;}bool operator>(const string& lhs, const string& rhs){return !(lhs <= rhs);}bool operator<=(const string& lhs, const string& rhs){return (lhs < rhs) || (lhs == rhs);}bool operator>=(const string& lhs, const string& rhs){return !(lhs < rhs);}bool operator==(const string& lhs, const string& rhs){return strcmp(lhs.c_str(), rhs.c_str()) == 0;}bool operator!=(const string& lhs, const string& rhs){return !(lhs == rhs);}//调整字符串大小void string::resize(size_t n, char c){_str[n] = c;}//删除pos位置上的元素,并返回该元素的下一个位置bool string::empty()const{if (_size != 0){return false;}else{return true;}}//流插入ostream& operator<<(ostream& _cout, const bit::string& s){for (size_t i = 0; i < s._size; i++){_cout << s._str[i];}return _cout;}//流提取istream& operator>>(istream& _cin, bit::string& str){str.clear();int i = 0;char buff[256];char ch;ch = _cin.get();while (ch != ' ' && ch != '\n'){buff[i++] += ch;if (i == 255){buff[i] = '\0';str += buff;i = 0;}ch = _cin.get();}if (i > 0){buff[i] = '\0';str += buff;}return _cin;}}
test.cpp【测试】
#include"string.h"//int main()
//{
// bit::string n("asdasdf");
// n += 'w';
// cout << n.c_str() << endl;
//}//int main()
//{
// bit::string n("asfsddfgdf");
// //迭代器
// bit::string::iterator i = n.begin();
// while (i != n.end())
// {
// cout << *i << endl;
// i++;
// }
//}//int main()
//{
// bit::string n("qweeqqqw");
// //n.clear();
// //cout << n.c_str() << endl;
// n.insert(0, "11111111");
// cout << n.c_str() << endl;
//}//int main()
//{
// bit::string n("11223344556677");
// /*n.erase(4, 99);*/
// n[2] = 'x';
// cout << n.c_str() << endl;
//}//int main()
//{
// bit::string n("11223344556677");
// bit::string s1(n);
// cout << (n < s1) << endl;
// cout << (n > s1) << endl;
// cout << (n <= s1) << endl;
// cout << (n >= s1) << endl;
// cout << (n == s1) << endl;
// cout << (n != s1) << endl;
//
//}//int main()
//{
// bit::string n("11223344556677");
// /*n.resize(8,'y');
// n.resize(8);
// cout << n.c_str() << endl;*/
//
// cout << n.empty() << endl;
//}//int main()
//{
// string n("1122");
// string s1("qqwee");
// n.swap(s1);
// cout << n << endl;
// cout << s1 << endl;
//}int main()
{bit::string n("112233");bit::string n1 = n;//bit::string s1("qweqwer");//n.swap(s1);//cout << n << endl;//cout << s1 << endl;/*cin >> n;cout << n << endl;*///getline(cin, n);//n = n1;//swap(n, n1);//swap(n,n1);//cout << n << endl;cout << n1 << endl;
}
写时拷贝(了解)
写时拷贝就是一种拖延症,是在浅拷贝的基础之上增加了引用计数的方式来实现的。
引用计数:用来记录资源使用者的个数。在构造时,将资源的计数给成1,每增加一个对象使用该 资源,就给计数增加1,当某个对象被销毁时,先给该计数减1,然后再检查是否需要释放资源, 如果计数为1,说明该对象时资源的最后一个使用者,将该资源释放;否则就不能释放,因为还有 其他对象在使用该资源。
写时拷贝
写时拷贝在读取是的缺陷
相关文章:

C++【string类,模拟实现string类】
🌟个人主页:落叶 🌟当前专栏: C专栏 目录 为什么学习string类 C语言中的字符串 标准库中的string类 auto和范围for auto关键字 迭代器 范围for string类的常用接口说明和使用 1. string类对象的常见构造 2.string类对象的容量操作 3…...

Jupyter lab 打开时默认使用 Notebook 而不是浏览器
Jupyter lab 打开时默认使用 Notebook 而不是浏览器 正文 正文 今天遇到了一个特别有意思的事情,这里我们以 Windows \textrm{Windows} Windows 系统举例。 我们知道通常我们需要使用如下代码在 Terminal \textrm{Terminal} Terminal 中打开 Jupyter lab \textr…...
【linux】ubunda repo是什么
Ubuntu repo(repository,简称repo)是一个软件仓库,它是存储和分发软件包的服务器或一组服务器。通俗地说,Ubuntu repo就像一个巨大的在线软件商店,用户可以从中下载和安装各种软件。 主要特点 软件集合&a…...

【MySQL】深层理解索引及特性(重点)--下(12)
索引(重点) 1. 索引的作用2. 索引操作2.1 主键索引2.1.1 主键索引的特点2.1.2 创建主键索引 2.2 唯一键索引2.2.1 唯一键索引的特点2.2.2 唯一索引的创建 2.3 普通索引2.3.1 普通索引的特点2.3.2 普通索引的创建 2.4 全文索引2.4.1 全文索引的作用2.4.2 …...

无人机声学侦测算法详解!
一、算法原理 无人机在飞行过程中,其电机工作、旋翼震动以及气流扰动等都会产生一定程度的噪声。这些噪声具有独特的声学特征,如频率范围、时域和频域特性等,可以用于无人机的检测与识别。声学侦测算法利用这些特征,通过一系列步…...
git 提交仓库
创建 git 仓库: mkdir pySoundImage cd pySoundImage git init touch README.md git add README.md git commit -m “first commit” git remote add origin https://gitee.com/hunan-co-changsha-branch/pytest.git git push -u origin master 已有仓库ÿ…...

基于大语言模型(LLM)自主Agent 智能体综述
近年来,LLM(Large Language Model)取得了显著成功,并显示出了达到人类智能的巨大潜力。基于这种能力,使用LLM作为中央控制器来构建自助Agent,以获得类人决策能力。 Autonomous agents 又被称为智能体、Agent。指能够通过感知周围环境、进行规划以及执行动作来完成既定任务。…...
使用命令行管理 Windows 环境变量
1. 使用命令提示符 (CMD) 1.1. 设置环境变量 添加或修改临时环境变量(当前会话有效) set MY_VARvalue添加或修改用户环境变量 setx MY_VAR "value"添加或修改系统环境变量(需要管理员权限): setx /M MY…...

AUTODL配置百度网盘数据传输
AUTODL使用 1.配置百度网盘开放平台 2.接入并创建应用 3.创建应用 4.添加授权...
LeetCode46. 全排列(2024秋季每日一题 57)
给定一个不含重复数字的数组 nums ,返回其 所有可能的全排列 。你可以 按任意顺序 返回答案。 示例 1: 输入:nums [1,2,3] 输出:[[1,2,3],[1,3,2],[2,1,3],[2,3,1],[3,1,2],[3,2,1]] 示例 2: 输入:nums …...

SpringBoot新闻稿件管理系统:架构与实现
3系统分析 3.1可行性分析 通过对本新闻稿件管理系统实行的目的初步调查和分析,提出可行性方案并对其一一进行论证。我们在这里主要从技术可行性、经济可行性、操作可行性等方面进行分析。 3.1.1技术可行性 本新闻稿件管理系统采用SSM框架,JAVA作为开发语…...
MinIO讲解和java应用案例示范
一、MinIO 基本概念 1.1 什么是 MinIO? MinIO 是一个高性能的对象存储服务器,专为云原生应用设计。它支持 Amazon S3 API,因此可以与现有的 S3 客户端和工具集成。MinIO 主要用于存储非结构化数据,如图片、视频、备份文件和日志…...
区块链技术与应用 【全国职业院校技能大赛国赛题目解析】第1套 区块链系统设计与运维部分
模块一:区块链产品方案设计及系统运维(35分) 选手完成本模块的任务后,将任务中设计结果、运行代码、运行结果等截图粘贴至客户端桌面【区块链技术应用赛\重命名为工位号\模块一提交结果.docx】中对应的任务序号下。 前述: 我们收到答案后,将针对比赛的答案和样题进行解…...

yaml文件编写
Kubernetes 支持YAML和JSON格式管理资源 JSON 格式:主要用于 api 接口之间消息的传递 YAML 格式;用于配置和管理,YAML是一种简洁的非标记性语言,内容格式人性化容易读懂 一,yaml语法格式 1.1 基本语法规则 使用空格进行缩进(不使用制表符࿰…...

TOEIC 词汇专题:娱乐休闲篇
TOEIC 词汇专题:娱乐休闲篇 在娱乐和休闲活动中,我们会接触到许多特定的词汇。这些词汇涉及到活动入场、观众互动、评论等各个方面,帮助你在相关场景中更加自如。 1. 入场和观众 一些常用词汇帮助你轻松应对观众与入场管理相关的场景&#…...
驱动TFT-1.44寸屏(ST7735)显示器
目录 一、驱动芯片介绍 二、驱动方式 三、主函数main运行 四、完整代码下载 TFT1.44寸屏,搭配ST7735驱动芯片,是一种专为小型电子设备设计的彩色液晶显示解决方案。该屏幕采用薄膜晶体管(TFT)技术,能够实现高亮度、…...

鸿蒙HarmonyOS NEXT一多适配技术方案
鸿蒙一多是什么 HarmonyOS 系统面向多终端提供了“一次开发,多端部署”(后文中简称为“一多”)的能力,让开发者可以基于一种设计,高效构建多端可运行的应用。 一套代码工程,一次开发上架,多端按…...
golang 中map使用的一些坑
golang 中map使用的一些坑 1、使用map[string]interface{},类型断言[]int失败 接收下游的数据是用json转为map[string]any go a : "{\"a\":\"1\",\"b\":[123]}" var marshal map[string]any json.Unmarshal([]byte(a), &…...
cordova 离线打包Android -Linux
背景 已有 cordova 运行环境的docker镜像; 需要在离线环境下执行 cordova 从创建项目到构建安装包一系列命令,最终生成 apk 文件。 方案 先在有网环境(最好与离线环境的OS一致)走一遍 cordova 创建打包工程、添加插件、添加平…...

【python】OpenCV—findContours(4.3)
文章目录 1、功能描述2、代码实现3、完整代码4、结果展示5、涉及到的库函数5.1、cv2.Canny5.2 cv2.boxPoints 6、参考 1、功能描述 找出图片中的轮廓,拟合轮廓外接椭圆和外接矩阵 2、代码实现 导入必要的库,固定好随机种子 import cv2 as cv import …...

iPhone密码忘记了办?iPhoneUnlocker,iPhone解锁工具Aiseesoft iPhone Unlocker 高级注册版分享
平时用 iPhone 的时候,难免会碰到解锁的麻烦事。比如密码忘了、人脸识别 / 指纹识别突然不灵,或者买了二手 iPhone 却被原来的 iCloud 账号锁住,这时候就需要靠谱的解锁工具来帮忙了。Aiseesoft iPhone Unlocker 就是专门解决这些问题的软件&…...
电脑插入多块移动硬盘后经常出现卡顿和蓝屏
当电脑在插入多块移动硬盘后频繁出现卡顿和蓝屏问题时,可能涉及硬件资源冲突、驱动兼容性、供电不足或系统设置等多方面原因。以下是逐步排查和解决方案: 1. 检查电源供电问题 问题原因:多块移动硬盘同时运行可能导致USB接口供电不足&#x…...

从零开始打造 OpenSTLinux 6.6 Yocto 系统(基于STM32CubeMX)(九)
设备树移植 和uboot设备树修改的内容同步到kernel将设备树stm32mp157d-stm32mp157daa1-mx.dts复制到内核源码目录下 源码修改及编译 修改arch/arm/boot/dts/st/Makefile,新增设备树编译 stm32mp157f-ev1-m4-examples.dtb \stm32mp157d-stm32mp157daa1-mx.dtb修改…...
数据库分批入库
今天在工作中,遇到一个问题,就是分批查询的时候,由于批次过大导致出现了一些问题,一下是问题描述和解决方案: 示例: // 假设已有数据列表 dataList 和 PreparedStatement pstmt int batchSize 1000; // …...
MySQL中【正则表达式】用法
MySQL 中正则表达式通过 REGEXP 或 RLIKE 操作符实现(两者等价),用于在 WHERE 子句中进行复杂的字符串模式匹配。以下是核心用法和示例: 一、基础语法 SELECT column_name FROM table_name WHERE column_name REGEXP pattern; …...
浅谈不同二分算法的查找情况
二分算法原理比较简单,但是实际的算法模板却有很多,这一切都源于二分查找问题中的复杂情况和二分算法的边界处理,以下是博主对一些二分算法查找的情况分析。 需要说明的是,以下二分算法都是基于有序序列为升序有序的情况…...

Qemu arm操作系统开发环境
使用qemu虚拟arm硬件比较合适。 步骤如下: 安装qemu apt install qemu-system安装aarch64-none-elf-gcc 需要手动下载,下载地址:https://developer.arm.com/-/media/Files/downloads/gnu/13.2.rel1/binrel/arm-gnu-toolchain-13.2.rel1-x…...
【学习笔记】erase 删除顺序迭代器后迭代器失效的解决方案
目录 使用 erase 返回值继续迭代使用索引进行遍历 我们知道类似 vector 的顺序迭代器被删除后,迭代器会失效,因为顺序迭代器在内存中是连续存储的,元素删除后,后续元素会前移。 但一些场景中,我们又需要在执行删除操作…...

Scrapy-Redis分布式爬虫架构的可扩展性与容错性增强:基于微服务与容器化的解决方案
在大数据时代,海量数据的采集与处理成为企业和研究机构获取信息的关键环节。Scrapy-Redis作为一种经典的分布式爬虫架构,在处理大规模数据抓取任务时展现出强大的能力。然而,随着业务规模的不断扩大和数据抓取需求的日益复杂,传统…...

沙箱虚拟化技术虚拟机容器之间的关系详解
问题 沙箱、虚拟化、容器三者分开一一介绍的话我知道他们各自都是什么东西,但是如果把三者放在一起,它们之间到底什么关系?又有什么联系呢?我不是很明白!!! 就比如说: 沙箱&#…...