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 …...

铭豹扩展坞 USB转网口 突然无法识别解决方法
当 USB 转网口扩展坞在一台笔记本上无法识别,但在其他电脑上正常工作时,问题通常出在笔记本自身或其与扩展坞的兼容性上。以下是系统化的定位思路和排查步骤,帮助你快速找到故障原因: 背景: 一个M-pard(铭豹)扩展坞的网卡突然无法识别了,扩展出来的三个USB接口正常。…...
零门槛NAS搭建:WinNAS如何让普通电脑秒变私有云?
一、核心优势:专为Windows用户设计的极简NAS WinNAS由深圳耘想存储科技开发,是一款收费低廉但功能全面的Windows NAS工具,主打“无学习成本部署” 。与其他NAS软件相比,其优势在于: 无需硬件改造:将任意W…...

UDP(Echoserver)
网络命令 Ping 命令 检测网络是否连通 使用方法: ping -c 次数 网址ping -c 3 www.baidu.comnetstat 命令 netstat 是一个用来查看网络状态的重要工具. 语法:netstat [选项] 功能:查看网络状态 常用选项: n 拒绝显示别名&#…...

前端导出带有合并单元格的列表
// 导出async function exportExcel(fileName "共识调整.xlsx") {// 所有数据const exportData await getAllMainData();// 表头内容let fitstTitleList [];const secondTitleList [];allColumns.value.forEach(column > {if (!column.children) {fitstTitleL…...
蓝桥杯 2024 15届国赛 A组 儿童节快乐
P10576 [蓝桥杯 2024 国 A] 儿童节快乐 题目描述 五彩斑斓的气球在蓝天下悠然飘荡,轻快的音乐在耳边持续回荡,小朋友们手牵着手一同畅快欢笑。在这样一片安乐祥和的氛围下,六一来了。 今天是六一儿童节,小蓝老师为了让大家在节…...

以光量子为例,详解量子获取方式
光量子技术获取量子比特可在室温下进行。该方式有望通过与名为硅光子学(silicon photonics)的光波导(optical waveguide)芯片制造技术和光纤等光通信技术相结合来实现量子计算机。量子力学中,光既是波又是粒子。光子本…...
return this;返回的是谁
一个审批系统的示例来演示责任链模式的实现。假设公司需要处理不同金额的采购申请,不同级别的经理有不同的审批权限: // 抽象处理者:审批者 abstract class Approver {protected Approver successor; // 下一个处理者// 设置下一个处理者pub…...
A2A JS SDK 完整教程:快速入门指南
目录 什么是 A2A JS SDK?A2A JS 安装与设置A2A JS 核心概念创建你的第一个 A2A JS 代理A2A JS 服务端开发A2A JS 客户端使用A2A JS 高级特性A2A JS 最佳实践A2A JS 故障排除 什么是 A2A JS SDK? A2A JS SDK 是一个专为 JavaScript/TypeScript 开发者设计的强大库ÿ…...

使用LangGraph和LangSmith构建多智能体人工智能系统
现在,通过组合几个较小的子智能体来创建一个强大的人工智能智能体正成为一种趋势。但这也带来了一些挑战,比如减少幻觉、管理对话流程、在测试期间留意智能体的工作方式、允许人工介入以及评估其性能。你需要进行大量的反复试验。 在这篇博客〔原作者&a…...
Go语言多线程问题
打印零与奇偶数(leetcode 1116) 方法1:使用互斥锁和条件变量 package mainimport ("fmt""sync" )type ZeroEvenOdd struct {n intzeroMutex sync.MutexevenMutex sync.MutexoddMutex sync.Mutexcurrent int…...