「C++ STL篇 1-0」string类的使用

目录

〇、概念

一、string类的构造函数

二、赋值运算符重载

三、有关容量的操作

四、string对象的访问

五、遍历string对象的字符数组

六、string对象的修改

七、string对象的常用操作

八、字符串和数字间的转换

拓展】

练习】

源代码】



〇、概念

1. string类是什么?

string类的底层是一个支持动态增长的char数组,它用new来动态分配内存,因此string也被称为变长字符串。

 

string的底层是一个叫 basic_string 的类模板,模板中存的是char。


事实上string库中还用basic_string类模板实现了存储宽字符的wstring,存储16位字符的 u16string(C++11后支持),和存储32位字符的 u32string(C++11后支持):

2. string类的官方文档

        博主在文章中只是讲述了有关string类的常用函数,对于一些不常用,可以查看官方文档: string类的官方文档

3. 导入string类 

要使用官方的string类:

  • 首先我们要引入头文件:#include<string>
  • 其次展开命名空间std中的string类:using std::string;

        严格来说string是属于C++ std标准库的,不在STL中,但是两者有许多相似之处,就放在一起总结了。


一、string类的构造函数

0. 全部构造函数

以下为C++98中string的所有构造函数

1. 常用的四个构造函数

string() (重点)构造空的string类对象,即空字符
string(const char* s) (重点)用字符数组来构造string对象
string(const string & s) (重点)拷贝构造函数
string(size_t n, char c)用n个c字符来构造string对象
string a;  //注意空字符串的创建不是string a(); 这是在声明一个返回值为string 的无参函数。
string b("abc"); //使用字面字符串来构造对象
string c(b);     //拷贝构造
string d(3, 'a');cout << a << endl;
cout << b << endl;
cout << c << endl;
cout << d << endl;

        唯一要注意的一点是创建空字符串不是string a(); 这是在声明一个返回值为string 的无参函数。是string a;

2. 可能用到的构造函数

string (const string& str, size_t pos, size_t len = npos);从str的下标 pos 处开始复制 len 个字符,不设置len默认复制到结尾
string e("1abcdefg", 1);     //abcdefg (从下标1开始复制)
string f(e, 1);              //bcdefg  (从下标1开始复制)
string g("1abcdefg", 1, 5);  //abcde   (从下标1开始复制5个字符)
string h(e, 0, 3);           //abc     (从下标0开始复制3个字符)

         唯一要注意的一点是:第二、三个参数的意义是,从下标pos处开始复制len个字符。不是复制它们之间的字符。不传第三个参数则默认复制到结尾。

拓1:string::npos


  • npos是std命名空间中string类下的一个静态成员变量。(std::string::npos)
  • npos用来表示一个非常非常大的数值(约为42亿9千万),因为size_t是无符号的整型,如果将-1的补码转化为无符号的整型将非常非常大,所以一般用string::npos来表示直到字符串的结尾。 

二、赋值运算符重载

1. 三个赋值运算符重载函数 

有三个重载,分别接受字符串,字符数组,字符作为参数。

以上三个运算符重载又互相构成函数重载。 

2. 使用赋值运算符重载函数

string& operator= (const string & str);使用string对象赋值
string& operator= (const char* s);使用字面字符串/字符数组赋值
string& operator= (char c);使用单个字符赋值
string a("abcd");
string b("bcde");
string c = b; // 注意这是在调用构造和拷贝构造函数
a = b;
cout << a << endl;
a = "fghi";
cout << a << endl;
a = 'j';
cout << a << endl;

        唯一一点要注意的就是要区分是在调用构造函数还是在赋值,上面代码中的第三行就是在调用构造函数。


拓2:构造还是赋值?

string a = b; // 注意这是在调用构造而不是赋值
string b("bcde");
a = b; // 这里才是赋值

        要注意第一行代码可不是在赋值,而是在通过隐式类型转换调用构造函数(先构造,再拷贝,编译器可能优化为直接构造)


        如何区分是构造还是赋值?就看对象有没有创建出来,如上面第一行代码中的对象a正在创建,所以这是在调用构造函数;而第三行中使用的是已经创建好的a对象,所以是在赋值,调用了赋值运算符重载函数。

三、有关容量的操作

1. 有关容量的操作函数

2. 常用的容量操作函数

size_t size() const noexcept;返回字符串有效字符长度

size_t length() const noexcept;

返回字符串有效字符长度
size_t capacity() const noexcept;返回字符串占用空间总大小(字节)
bool empty() const noexcept;检测字符串是否为空串,是返回true,否则返回false
void clear() noexcept;清空字符串
void reserve (size_t n = 0);为字符串预留空间
void resize (size_t n);设置有效字符长度,用'\0'填充多出来的位置

void resize (size_t n, char c);

设置有效字符长度,用指定字符填充多出来的位置

a. 获取字符串有效字符长度

        推荐使用size(),少用length()。虽然设计方面两个函数是一样的,但为了在学习后面的容器时不产生混乱(其它容器中都有size()来计算元素个数,但不一定有length()),使用推荐使用size()

b. 获取字符串占用空间总大小

        stirng对象中的字符数组的空间大小不一定等于有效字符长度size,因为扩容是有消耗的,所以一般扩容不是一个一个一个扩,而是以1.5或2倍大小来扩容,我们可以通过capacity()来获取stirng对象中的字符数组的空间大小。

c. 判空和清空字符串

  • empty()通过检查有效字符长度来判断string对象是否为空,为空返回true。
  • clear()通过将有效字符长度置为0来清空字符串。

d. 为字符串预留空间

        当string对象的有效字符长度size等于容量capacity时会触发扩容,扩容是有消耗的,如果我们提前知道有效字符长度size,就可以通过reserve()来提前开好一片空间,就不需要频繁的扩容了。

        当所给值小于容器当前的 capacity时,什么也不做(不会缩小容量)。

e. 设置有效字符长度

         resize()通过设置有效字符长度size,来更新字符串的长度,如果新长度比当前字符串有效长度长,默认用'\0'填充。(string对象的打印不是遇到'\0'终止,但'\0'不会被显示)


        我们也可以通过resize()的第二个参数来指定,当新长度比当前字符串有效长度长时的填充字符。

四、string对象的访问

1. string对象的三种访问方法

string对象主要三种访问方法:[ ]、at()、string::iterator


  • [ ]没什么好说的,重载[ ]让string类能像数组一样使用。
  • 成员函数at()用来返回指定下标处的字符,类似于Java中的charAt(),让string类符合封装的思想,但几乎不怎么用。
  • string::iterator就是迭代器,string类的迭代器可以当作指针来用,begin(),end()返回的就是数组下标0和下标size处的迭代器。

2. operator [ ] 和 at()

        operator [ ] 和 at() 返回的都是string对象的字符数组的i下标处的引用,所以可以用来修改string对象的字符数组。


  • 重载[ ]让string类能像数组一样使用

  • 成员函数at()用来返回指定下标处的字符 


string a("abcdefghijklmn");cout << "使用[]遍历string对象的字符串" << endl;
for (int i = 0; i < a.size(); i++)
{//operator [ ]是string对象的字符数组的i下标处的引用。a[i]++;cout << a[i];
}	
putchar(10);cout << "使用at()遍历string对象的字符串" << endl;
for (int i = 0; i < a.size(); i++)
{// at() 返回的也是string对象的字符数组的i下标处的引用a.at(i)++;cout << a.at(i);
}
putchar(10);

3. string::iterator

        string类的迭代器可以当作指针来用,begin(),end()相当于指向字符串开头和结尾('\0'处)的指针。通过+/- 能获取下一个或上一个地址。通过*(解引用)能取出地址中的内容。


五、遍历string对象的字符数组

        上面的三种访问方式都可以用来遍历string对象。这里因为[]和at()区别不大,所以就演示使用[ ] 和 stirng::iterator 来遍历string对象。

1. 使用[ ]遍历string对象的字符数组

重载[ ]让string对象的访问和数组没有区别:

//operator [ ] 和 at() 返回的都是string对象的字符数组的i下标处的引用,所以可以用来修改string对象的字符数组。
a = "abcdefg";
for (int i = 0; i < a.size(); ++i)
{a[i] += 1;cout << a[i];
}

2. 使用迭代器来遍历string对象的字符数组

string的迭代器可以当指针使用:

a = "abcdefg";
string::iterator it = a.begin();
while (it != a.end())
{cout << *it; //string的迭代器可以当指针使用。++it;
}


使用迭代器来遍历string对象的最大优势在于:可以使用范围for。

上面代码中auto后面的e是临时变量,不会对原字符串造成改变


只有auto + &才能修改原字符串

六、string对象的修改

0. string类中有关修改的函数

1. 追加

追加:
operator +=() (常用)在字符串后追加字符串/string对象/字符。
push_back()在字符串后尾插字符,只能尾插一个字符。
append()(常用)在字符串后追加一个字符串

a. operator +=()

        重载+=让我们可以在字符串后随意追加字符串/string对象/字符,一般情况下有operator +=即可。


string a("abcdefg");
a += "higk";
a += 'l';
string b("mn");
a += b;
cout << a << endl;

b. append()

        append()主要用于一些特殊情况:追加某个字符串的一部分、追加某个字符n次。


string a = "abcdefghijklmno";
a.append("lmn");
string c("opq");
a.append(c);
cout << a << endl;a.append("rstuvw", 3); // 尾插一个字符串,取其前n个字符
cout << a << endl;
a.append("rstuvwxyz123", 3, 8); // 尾插一个字符串,从下标n开始,取其前i个字符
cout << a << endl;
a.append(3, ' '); //尾插n个相同的字符
cout << a << endl;

2. 插入

一般来说insert只用于要在字符串中间插入内容时。用的比较少。

插入:
insert在指定下标处插入一个字符串。
string a = "abcdefghijklmnopqrstuvwxyz  ";
a.insert(0, "123"); // 在n下标处插入一个字符串
cout << a << endl;
a.insert(3, "456789", 3); // 在n下标处插入,一个字符串的前n个字符
cout << a << endl;
a.insert(6, "7891011", 3, 5); //在n下标处插入,一个字符串从下标n开始的n个字符
cout << a << endl;

3. 删除

删除:
erase删除指定位置开始的n个字符。
a = "ab123456789cdefghigklmnopqrstuvwxyz111";
a.erase(2, 9); //删除从指定下标开始的n个字符。
cout << a << endl;
a.erase(25);    //删除从指定下标后的所有字符。
cout << a << endl;
int n = 3;
a.erase(a.begin() + n);    //删除下标为n的字符
cout << a << endl;

七、string对象的常用操作

0. string对象的操作函数

其中copy()完全可以使用 operator =() 来替代,compare()也可以使用operator >()来替代。


常用的操作函数只有四个:

c_str()返回C格式字符串(char* )
find()从前往后查找子串,返回起始位置的下标
rfind() 从后往前查找子串,返回起始位置的下标
substr()截取子串,并返回一个string对象

1. c_str()

        返回一个 const char* 指针,该指针指向一个和string对象有效内容相同的char数组,且是以'\0'结尾。该函数的作用是获取一个适用于C语言库函数的C风格字符串

string a;
a = "abcdefgdefg";
cout << a.c_str() << endl;      // 返回一个char*指向的字符数组

2. find() 和 rfind()

        都是用来查找子串的不过find()是从前往后找,rfind()是从后往前找。找到了就立即返回子串起始位置的下标,没找到就返回string::npos(约为42亿9千万)。

string a = "abcdefgdefg";
cout << a.find("defg") << endl; //查找子串,返回起始位置的下标
if(a.find("defgl") == string::npos) //找不到返回string::npos(约为42亿9千万);cout << "未找到该子串" << endl;cout << a.find("def", 3) << endl;//查找子串,从主串的第n个位置开始找。
cout << a.find("def", 4) << endl;//查找子串,从主串的第n个位置开始找。
cout << a.rfind("def", 4) << endl;//从主串的第n个位置开始从后往前查找子串。

3. substr() 

从下标pos开始,截取len个字符,不传len就默认截取到结尾。然后返回一个string对象。      


string a = "abcdefgdefg";
cout << a.substr(1) << endl;        //从下标1的字开始截取到结尾
cout << a.substr(1).size() << endl; cout << a.substr(0, 3) << endl;     //从下标0的字开始截取3个字符

八、字符串和数字间的转换

以下函数都是string的非成员函数,不能通过对象来调用。

to_string()将数字转为字符串
stoi()将string对象转为整数 (只能接受string对象)
stod()将string对象转为浮点数 (只能接受string对象)
atoi()将字面字符串转为整数 (只能接受常量字符串)
atof()将字面字符串转为浮点数(只能接受常量字符串)
		//to_string()函数:将数字转为字符串cout << "---------------------------" << endl;double a = 1234.5678;string s = std::to_string(a);cout << s << endl;//stoi():将字符串转为整数int b = stoi(s);cout << b << endl;//stod():将字符串转为浮点数double c = std::stod(s);printf("%lf\n", c);  //注意cout默认输出两位小数,所以在输出浮点数时最好使用printf()//atoi():将字面字符串转为整数const char* ss = "2345678";b = atoi(ss);cout << b << endl;//atof():将字面字符串转为浮点数c = atof("1234.5678");printf("%f\n", c);

拓展】

1:operator +

重载+ 让string对象能自由的拼接字符/字符串/其他string对象:

string firstlevel("com");
string secondlevel("cplusplus");
string scheme("http://");
string hostname;
string url;hostname = "www." + secondlevel + '.' + firstlevel;
url = scheme + hostname;std::cout << "网址:" + url + '\n';

2:重载比较运算符

重载比较运算符 让string对象能和 字符串字符串/其他string对象 进行字典序比较(逐个按ASCII码比较):

string s1 = "abcd";
string s2 = "abcde";
cout << (s1 == "a") << endl;cout << (s1 > s2) << endl;
cout << (s1 >= "abcd") << endl;cout << (s1 < s2) << endl;
cout << (s1 <= s2) << endl;

3:按行输入

        cin >> 是以空格进行分隔的,当我们希望输入一句英文时,使用cin >> 却只能接收到一个单词。所以这个时候我们就需要使用按行输入了:getline()


  • 第一个参数是istream对象,传入std::cin即可。
  • 第二个参数是用来接收的string对象。
  • 第三个参数是控制输入结束的字符,不传该参数就默认以回车结束。

string str;
getline(cin, str, '.'); //按行输入,指定以.结束。
cout << str << endl;

4:判断字符是字母还是数字

  • isalpha() :用来判断一个字符是不是字母。

  • isdigit() :用来判断一个字符是不是数字。


        如果记不住,自己写一个也很快,判断是否是字母就比较字符是否大于等于'a'/'A',小于等于'z'/'Z',判断是否是字母就比较字符是否大于等于'0',小于等于'9' 。或用它们的ASCII码:48 65 97 。


练习】

1:将字符串中的空格替换为%20

	{// 法一:倒着找到后先删除后插入string s1("hello world lin");for (int i = s1.size(); i >= 0; i--){if (s1[i] == ' '){s1.erase(i, 1);s1.insert(i, "%20");}}// 法二:开一个新字符串string s2;for (int i = 0; i < s1.size(); i++){if (s1[i] == ' ')s2 += "20%";elses2 += s1[i];}cout << s1 << endl;cout << s2 << endl;}

2:获取文件后缀

	{// 用find找子串,用substr获取子串。string file_path = "test.cpp.zip.tar";size_t index = file_path.find(".");size_t index1 = file_path.rfind("."); // 从结尾开始找string suffix = file_path.substr(index);string suffix1 = file_path.substr(index1);cout << "使用find获取文件所有后缀:" << suffix << endl;cout << "使用rfind获取文件真后缀:" << suffix1 << endl;}

源代码】

#include<iostream>
#include<string>
using std::cin;
using std::cout;
using std::endl;
using std::string;int main()
{std::ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);// string类的构造函数{//string() (重点)	构造空的string类对象,即空字符//string(const char* s) (重点)	用字符数组来构造string类对象//string(const string & s) (重点)	拷贝构造函数//string(size_t n, char c)	用n个c字符来构造string类对cout << "----------string类的构造函数---------" << endl;string a; //string a(); 不是在调用构造器创建一个空的string对象,而是在声明一个返回值为string的无参函数。string b("abcd");  //使用字符数组构造string c(b);  //拷贝构造string d(3, 'a');const char* e = "abcdefg";string f(e);char g[] = { 'a', 'b' }; //char数组结尾一定要加一个'\0'string h(g);cout << a << endl;cout << b << endl;cout << c << endl;cout << d << endl;cout << e << endl;cout << f << endl;cout << g << endl;cout << h << endl;}// 赋值运算符重载{//string& operator= (const string & str);//string & operator= (const char* s);//string& operator= (char c);cout << "----------赋值运算符重载---------" << endl;string a("abcdefg");string b = a;  //区分构造和赋值,这里b还没有创建所以调用的是构造函数b = a;  //这里b已经创建,所以调用的是赋值运算符重载cout << b << endl;b = "abcd";cout << b << endl;b = 'a';cout << b << endl;}// 有关容量的操作{//	size(重点)	返回字符串有效字符长度//	length	        返回字符串有效字符长度//	capacity	    返回空间总大小//	empty(重点)	检测字符串是否为空串,是返回true,否则返回false//	clear(重点)	清空有效字符//	reserve(重点)	为字符串预留空间//	resize(重点)	设置字符串长度,用指定字符填充多出来的位置cout << "-----------有关容量的操作---------" << endl;string a("abcdefg");cout << a.size() << endl;cout << a.length() << endl;cout << a.capacity() << endl;// 判空:根据size()判断cout << a.empty() << endl;// 不同于字符数组是以'\0'来判断结尾,stirng对象判断字符串的结尾是根据size属性。// 清空字符串:修改size()a.clear();cout << "a.clear();" << endl;cout << a.size() << endl;cout << a.empty() << endl;// 为stirng对象预留空间,修改capacity = n + 1;a.reserve(30);cout << "a.reserve(30);" << endl;cout << a.capacity() << endl;cout << a.size() << endl;// 设置string对象的有效长度,多出来的长度默认用'\0'填充cout << a << " 的长度: " << a.size() << endl;a.resize(10);cout << "a.resize(20);" << endl;cout << a << " 的长度: " << a.size() << endl;a.resize(20, '.');cout << "a.resize(20, '.');" << endl;cout << a << " 的长度: " << a.size() << endl;cout << "string对象是以size来判断结尾的,看不到的字符可能是'\0'";}//访问string对象的字符数组{cout << "---------访问string对象的字符数组--------" << endl;string a;a = "abcd";cout << a << endl; //重载<< 让我们能自己打印string对象的内容。cout << a[0] << endl;cout << a.at(1) << endl;cout << *a.begin() << endl;cout << *(a.begin() + 2) << endl;string::iterator it = a.end()-1;cout << *it << endl;}//遍历string对象的字符数组{cout << "---------遍历string对象的字符数组--------" << endl;string a("abcdefghijklmn");cout << "operator [ ]和at() 返回的是string对象的字符数组的i下标处的引用。" << endl;cout << "使用[]遍历string对象的字符串" << endl;for (int i = 0; i < a.size(); i++){//operator [ ]返回的是string对象的字符数组的i下标处的引用。a[i]++;cout << a[i];}	putchar(10);cout << "使用at()遍历string对象的字符串" << endl;for (int i = 0; i < a.size(); i++){// at() 返回的也是string对象的字符数组的i下标处的引用a.at(i)++;cout << a.at(i);}putchar(10);cout << "使用迭代器遍历string对象的字符串" << endl;for (string::iterator i = a.begin(); i != a.end(); i++){(*i)++; //++的优先级大于*,所以要使用()cout << *i;}putchar(10);string::iterator it = a.begin();while (it != a.end()){(*it)++;cout << *it;it++;    //如果会忘记写it++,建议使用for循环}putchar(10);cout << "使用范围for+迭代器遍历string对象的字符串" << endl;//不使用&的范围for是无法修改原数组的cout << "a. 使用范围for访问,不用加&" << endl;for (auto e : a){e++; //这里的e不过是一个临时变量。cout << e;}putchar(10);cout << a << endl;//使用&的范围for才能修改原数组的cout << "b. 使用范围for修改,要加&" << endl;for (auto& e : a){e++;cout << e;}putchar(10);cout << a << endl;}//string对象的修改{cout << "-----------string对象的修改-----------" << endl;//追加//operator+=(重点)	在字符串后追加字符串/string对象/字符//push_back	        在字符串后尾插字符//append(重点)     	在字符串后追加一个字符串cout << "-----------追加-----------" << endl;string a("abc");a += 'd';a += "efg";string b("hij");a += b;cout << a << endl;a.push_back('k'); // 只能尾插一个字符。//a.push_back("lmn");a.append("lmn");string c("opq");a.append(c);cout << a << endl;a.append("rstuvw", 3); // 尾插一个字符串,取其前3个字符cout << a << endl;a.append("rstuvwxyz123", 3, 6); // 尾插一个字符串,从下标3开始,取其前6个字符cout << a << endl;a.append(3, ' '); //尾插3个' '字符cout << a << endl;//插入 insertcout << "-----------插入-----------" << endl;a = "abcdefghijklmnopqrstuvwxyz  ";a.insert(0, "123"); // 在0下标处插入一个字符串cout << a << endl;a.insert(3, "456789", 3); // 在3下标处插入,一个字符串的前3个字符cout << a << endl;a.insert(6, "4567891011", 3, 5); //在6下标处插入,一个字符串从下标3开始的5个字符cout << a << endl;//删除 erasecout << "-----------删除-----------" << endl;a = "12345678910abcdefghijklmnopqrstuvwxyz   .";a.erase(37, 3); //删除下标37开始的3个字符cout << a << endl;a.erase(10); //删除下标10后的所有字符cout << a << endl;a.erase(a.begin() + 9); //删除下标为9的字符cout << a << endl;}//string对象的常用操作{//c_str(重点) 返回C格式字符串//find(重点)	  从前往后查找子串,返回起始位置的下标//rfind	      从后往前查找子串,返回起始位置的下标//substr	  截取子串,并返回一个string对象cout << "---------------------------" << endl;string a;a = "abcdefgdefg";cout << a.c_str() << endl;cout << a.find("defg") << endl; //找到就返回在主串中起始位置的下标if (a.find("defgh") == string::npos) //找不到返回string::npos(约为42亿9千万)cout << "未找到" << endl;cout << a.rfind("defg") << endl; //从后往前找。cout << a.rfind("defg", 3) << endl; //从第4个字符开始,从后往前找。cout << a.rfind("defg", 2) << endl; //从第3个字符开始,从后往前找。a = "abcdefgdefg";cout << a.substr(1) << endl;        //从下标1的字开始截取到结尾cout << a.substr(1).size() << endl; cout << a.substr(0, 3) << endl;     //从下标0的字开始截取3个字符}//string对象和数字间的转换{//to_string()函数:将数字转为字符串cout << "---------------------------" << endl;double a = 1234.5678;string s = std::to_string(a);cout << s << endl;//stoi():将字符串转为整数int b = stoi(s);cout << b << endl;//stod():将字符串转为浮点数double c = std::stod(s);printf("%lf\n", c);  //注意cout默认输出两位小数,所以在输出浮点数时最好使用printf()//atoi():将字面字符串转为整数const char* ss = "2345678";b = atoi(ss);cout << b << endl;//atof():将字面字符串转为浮点数c = atof("1234.5678");printf("%f\n", c);}// operator +{cout << "---------------------------" << endl;string firstlevel("com");string secondlevel("cplusplus");string scheme("http://");string hostname;string url;hostname = "www." + secondlevel + '.' + firstlevel;url = scheme + hostname;std::cout << "网址:" + url + '\n';}// 比较运算符:逐个按ASCII码比较{cout << "---------------------------" << endl;string s1 = "abcd";string s2 = "abcde";cout << (s1 == "a") << endl;cout << (s1 > s2) << endl;cout << (s1 >= "abcd") << endl;cout << (s1 < s2) << endl;cout << (s1 <= s2) << endl;}// 按行输入 : getline(cin, str){cout << "---------------------------" << endl;string str;getline(cin, str, '.'); //按行输入,指定以.结束。cout << str << endl;}// 练习1:实现字符串替换函数:{// 法一:倒着找到后先删除后插入string s1("hello world lin");for (int i = s1.size(); i >= 0; i--){if (s1[i] == ' '){s1.erase(i, 1);s1.insert(i, "%20");}}// 法二:开一个新字符串string s2;for (int i = 0; i < s1.size(); i++){if (s1[i] == ' ')s2 += "20%";elses2 += s1[i];}cout << s1 << endl;cout << s2 << endl;}// 练习2:获取文件后缀{// 用find找子串,用substr获取子串。string file_path = "test.cpp.zip.tar";size_t index = file_path.find(".");size_t index1 = file_path.rfind("."); // 从结尾开始找string suffix = file_path.substr(index);string suffix1 = file_path.substr(index1);cout << "使用find获取文件所有后缀:" << suffix << endl;cout << "使用rfind获取文件真后缀:" << suffix1 << endl;}// C++中涉及到char*的操作以'\0'为结尾,涉及string的操作以size的长度算结尾。{cout << "---------------------------" << endl;string s3 = "asdfg ";s3 += '\0';s3 += "hjkl";cout << s3 << endl;cout << s3.c_str() << endl;string s4 = s3;cout << s4 << endl;}return 0;
}

------------------------END-------------------------

才疏学浅,谬误难免,欢迎各位批评指正。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/bicheng/6674.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

前后端分离实践:使用 React 和 Express 搭建完整登录注册流程

文章目录 概要整体架构流程技术名词解释ReactExpressReact RouterAnt Design 技术细节前端设计后端逻辑数据交互 小结 概要 本项目是一个基于React和Express的简单登录注册系统。通过前后端分离的方式&#xff0c;实现了用户的注册、登录和查看用户列表等功能。前端使用React框…

PostgreSQL 14 向量相似度搜索插件 (pgvector) 安装指南

本文是关于在 PostgreSQL 14 中安装并使用向量相似度搜索插件(pgvector)的详细指南。此插件允许用户在数据库中执行高效的向量运算,特别适用于机器学习模型的向量数据存储与检索场景。 环境需求 已安装PostgreSQL 14或更高版本。安装了Visual Studio 2022,用于编译插件。安装…

GitHub显示无法在此仓库中合并不相关的历史记录

你好,我是Qiuner. 为记录自己编程学习过程和帮助别人少走弯路而写博客 这是我的 github gitee 如果本篇文章帮到了你 不妨点个赞吧~ 我会很高兴的 &#x1f604; (^ ~ ^) 想看更多 那就点个关注吧 我会尽力带来有趣的内容 GitHub显示无法在此仓库中合并不相关的历史记录 场景&…

基于 Dockerfile 部署 LNMP 架构

目录 前言 1、任务要求 2、Nginx 镜像创建 2.1 建立工作目录并上传相关安装包 2.2 编写 Nginx Dockerfile 脚本 2.3 准备 nginx.conf 配置文件 2.4 生成镜像 2.5 创建 Nginx 镜像的容器 2.6 验证nginx 3、Mysql 镜像创建 3.1 建立工作目录并上传相关安装包 3.2 编写…

linux内核源码分析--核心网络文件和目录

图3-2显示了在/proc/sys中由网络代码所使用的主要目录&#xff0c;就每个目录而言&#xff0c;都列出了在哪一章描述其文件。 proc/sys/net bridge ipv4 core route neigh conf 图3-2/proc/sys/net 中的核心目录 根据前借所述&#xff0c;我们来看net中的树根是如何定义的&…

【YOLO】目标检测 YOLO框架之train.py参数含义及配置总结手册(全)

1.一直以来想写下基于YOLO开源框架的系列文章&#xff0c;该框架也是日常项目开发中常用的一款工具&#xff0c;最近刚好挤时间梳理、总结下这块儿的知识体系。 2.熟悉、梳理、总结下YOLO目标检测相关知识体系&#xff0c;之前实战配置时总是临时性检索些注释含义&#xff0c;但…

java下乡扶贫志愿者招募管理系统springboot-vue

计算机技术在现代管理中的应用&#xff0c;使计算机成为人们应用现代技术的重要工具。能够有效的解决获取信息便捷化、全面化的问题&#xff0c;提高效率。 技术栈 前端&#xff1a;vue.jsElementUI 开发工具&#xff1a;IDEA 或者eclipse都支持 编程语言: java 框架&#xff1…

[C++基础学习-04]----C++数组详解

前言 在C中&#xff0c;数组是一种用来存储相同类型元素的数据结构。一维数组是最简单的数组形式&#xff0c;它由一系列按顺序存储的元素组成。二维数组则是由一维数组构成的数组&#xff0c;可以看作是一堆一维数组堆叠在一起形成的矩阵。 正文 01-数组简介 一维数组和二维…

《QT实用小工具·五十六》自适应界面变化的控件

1、概述 源码放在文章末尾 该项目实现了网格显示多张带文字的图片在界面中自适应布局 特点 跟随窗口大小变换位置&#xff0c;并带移动动画 响应鼠标事件&#xff0c;图片缩放动画 点击水波纹动画 项目demo演示如下所示&#xff1a; 项目部分代码如下所示&#xff1a; #i…

【华为】路由综合实验(OSPF+BGP基础)

【华为】路由综合实验 实验需求拓扑配置AR1AR2AR3AR4AR5PC1PC2 查看通信OSPF邻居OSPF路由表 BGPBGP邻居BGP 路由表 配置文档 实验需求 ① 自行规划IP地址 ② 在区域1里面 启用OSPF ③ 在区域1和区域2 启用BGP&#xff0c;使AR4和AR3成为eBGP&#xff0c;AR4和AR5成为iBGP对等体…

半监督节点分类:标签传播和消息传递

基础概念回顾 传统图机器学习的特征工程——节点层面&#xff0c;连接层面&#xff0c;全图层面 节点层面&#xff1a;信用卡欺诈 连接层面&#xff1a;推荐可能认识的人 全图层面&#xff1a;预测分子结构 半监督节点分类 半监督节点分类&#xff1a;用已知标签节点预测未…

OpenWRT部署Zerotier虚拟局域网实现内网穿透

前言 细心的小伙伴肯定已经发现了&#xff1a;电脑上部署了Zerotier&#xff0c;如果路由器也部署了OpenWRT&#xff0c;那是否能远程访问呢&#xff1f; 答案是肯定的。 OpenWRT部署Zerotier有啥好处&#xff1f; 那好处必须多&#xff0c;其中的一个便是在外远程控制家里…

图像压缩问题

图像压缩问题的bilibil讲解 1.问题引入 首先&#xff0c;图像是由像素组合成的&#xff0c;每个像素都有灰度值&#xff0c;灰度值是体现像素的颜色的。灰度值从0~255&#xff0c;灰度值占用的位数就是像素占用的位数。我们要存储一个图像就要存储它的所有像素。现在的问题是我…

车载电子电器架构 —— 关于bus off汇总

车载电子电器架构 —— 关于bus off汇总 我是穿拖鞋的汉子,魔都中坚持长期主义的汽车电子工程师。 老规矩,分享一段喜欢的文字,避免自己成为高知识低文化的工程师: 屏蔽力是信息过载时代一个人的特殊竞争力,任何消耗你的人和事,多看一眼都是你的不对。非必要不费力证明…

【uniapp】H5+、APP模拟浏览器环境内部打开网页

前言 今天将智能体嵌入到我的项目中&#xff0c;当作app应用时&#xff0c;发现我使用的webview组件&#xff0c;无论H5怎么登录都是未登录&#xff0c;而APP却可以&#xff0c;于是进行了测试&#xff0c;发现以下几种情况&#xff1a; 方法<a>标签webviewAPP✅✅网页…

spring高级篇(八)

本篇对Spring MVC 的执行流程做一个简单总结 MVC执行流程总结 当浏览器发送一个请求&#xff0c;例如http://localhost:8080/hello&#xff0c;请求到达服务器后&#xff0c;一般会进行如下操作&#xff1a; 1、首先会经过DispatcherServlet&#xff0c;默认映射路径为 /&…

GRU模块:nn.GRU层的输出state与output

在 GRU&#xff08;Gated Recurrent Unit&#xff09;中&#xff0c;output 和 state 都是由 GRU 层的循环计算产生的&#xff0c;它们之间有直接的关系。state 实际上是 output 中最后一个时间步的隐藏状态。 GRU 的基本公式 GRU 的核心计算包括更新门&#xff08;update gat…

用于密集预测任务的通道知识蒸馏——关键字:蒸馏

摘要 https://arxiv.org/pdf/2011.13256 知识蒸馏(KD)已被证明是训练紧凑密集预测模型的简单有效工具。通过从大型教师网络转移而来的额外监督来训练轻量级学生网络。大多数先前的针对密集预测任务的KD变体都在空间域中对学生网络和教师网络的激活图进行对齐,通常是通过在每…

【Linux】进程间通信 - 管道

文章目录 1. 进程间通信介绍1.1 进程间通信目的1.2 进程间通信发展1.3 进程间通信分类 2. 管道2.1 什么是管道2.2 匿名管道2.3 用 fork 来共享管道原理2.4 站在文件描述符角度 - 深入理解管道2.5 站在内核角度 - 管道本质2.6 管道读写规则2.7 管道特点 3. 命名管道3.1 匿名管道…

linux代码实操——信号的使用

信号的基本概念 信号是系统响应某个条件而产生的事件&#xff0c;进程接收到信号会执行相应的操作。 与信号有关的系统调用在“signal.h”头文件中有声明 常见信号的值&#xff0c;及对应的功能说明&#xff1a; 修改信号的响应方式 – signal() 我们来做个小实验: 在键盘上…