C++初阶-string类3
目录
1.元素访问
1.1string::operator[]
1.2string::at
1.3string::back和string::front
2.修饰符
2.1string::operator+=
2.2string::append
2.3string::push_back
2.4string::assign
2.5string::insert
2.6string::erase
2.7string::replace
2.8string::swap
2.9string::pop_back
3.总结
1.元素访问
C++的string类中有Element access这个分类,翻译过来就是元素访问,元素访问有以下的函数:
1.1string::operator[]
在之前的数组的[]的意思就是访问[]里面的位置的下标位置的元素,在string类中也是一样的,返回的是string对象的pos位置的元素:
#include<iostream>
using namespace std;
#include<string>
//重载运算符[]
int main()
{//第一个函数的用法string s1("hello world");cout << s1[4] << endl;//第二个函数的用法const string s2("happy naodongjie");cout << s2[3] << endl;return 0;
}
运行结果如下:
我们在string类中用这个方法来访问string类中的一个字符。
1.2string::at
这个函数除了有检查是否有越界的问题外,其余的和[]差不多,我们主要是注意它们两个如果有越界的情况时,处理的方式不同就可以了:
#include<iostream>
using namespace std;
#include<string>
//string::at
int main()
{string s1("hello world");cout << s1[100] << endl;//cout << s1.at(100) << endl;return 0;
}
运行结果如下:
若用at的话,如果越界会有什么问题:
#include<iostream>
using namespace std;
#include<string>
//string::at
int main()
{string s1("hello world");//cout << s1[100] << endl;cout << s1.at(100) << endl;return 0;
}
结果如下:
当然,我们是看不懂这个东西的意思的,第一个底层是用assert(pos<size())来判断是否越界的,所以它会直接强制终止程序,相对比较暴力;而第二个底层则是用try{}catch{}这种方式来捕获异常的,相对比较好。要了解它们两个区别需要看一下Deepseek的回答:
所以二者可以交互使用,如果是比较大的程序的时候,我的建议是用at因为它不会直接终止程序,而会去捕获异常。
1.3string::back和string::front
这两个函数可以通过二者的函数名来知道结果,所以在这里暂时只讲解一般用法:
#include<iostream>
using namespace std;
#include<string>
//string::back
//string::front
int main()
{string s1("hello world");cout << s1.front() << endl;cout << s1.back() << endl;const string s2("hello CSDN");cout << s2.front() << endl;cout << s2.back() << endl;return 0;
}
运行结果为:
2.修饰符
string类中的Modifiers分类是修饰符的意思,包含以下函数:
2.1string::operator+=
这个函数的功能如下:
IL是C++11才添加的,所以我们不用管它,这个函数的功能是把一个string对象或字符串或一个字符添加到string对象结尾,所以这就相当于我们的尾插:
#include<iostream>
using namespace std;
#include<string>
//string::operator+=
int main()
{string s("abc");cout << s << endl;//(1)string s1("def");s += s1;cout << s << endl;//(2)s += "ghi";cout << s << endl;//(3)s += 'j';cout << s << endl;return 0;
}
运行结果如下:
这个函数的功能也相似于我们C语言所学的strcat函数,但是strcat函数是从头开始找\0再在\0后面追加,且strcat是不会扩容的,也就是说可能会出现越界的问题。但是这个+=就不一样了,在追加时都会检查一下是否空间足够的问题,之后所学的很多函数也都会检查。
2.2string::append
append也有添加的意思,它有六个重载函数,这里只讲解前5个的意思,最后一个是插入一个从迭代器first到last的区间
(1)string& append(const string& str);
把string对象(str)添加到string对象后面去,并返回被插入对象的引用。
(2)string& append(const string& str,size_t subpos,size_t sublen);
把str的从subpos位置开始的sublen个字符插入到string对象后面去,如果剩余的字符个数小于sublen则把subpos位置后面的字符全部插入到string对象后面去,并返回被插入对象的引用。
(3)string& append(const char* s);
把s字符串插入到string对象后面去,并返回被插入对象的引用。
(4)string& append(const char* s,size_t n);
取s的前n个字符进行插入到string对象后面,并返回被插入对象的引用。
(5)string& append(size_t n,char c);
插入n个c字符到string对象后面,并返回被插入对象的引用。
#include<iostream>
using namespace std;
#include<string>
//string::append
int main()
{string s1("ab");cout << s1 << endl;//(1)string s2("cd");s1.append(s2);cout << s1 << endl;//(2)string s3("def");s1.append(s3, 1, 10);cout << s1 << endl;//(3)s1.append("gh");cout << s1 << endl;//(4)s1.append("ijk", 2);cout << s1 << endl;//(5)s1.append(3, 'k');cout << s1 << endl;//(6)string s4("lmno");s1.append(s4.begin(), s4.end());cout << s1 << endl;return 0;
}
运行结果为:
append函数比+=运算符所做的事更多,但是+=相对于append使用起来更方便,而且可读性更高,所以二者功能车不多,用法也没有太大区别。
2.3string::push_back
这个函数只有一个功能,就是追加一个字符到字符串的末尾,如:
#include<iostream>
using namespace std;
#include<string>
//string::push_back
int main()
{string s("abcd");string s1("abcd");cout << s.append(1, 'e') << endl;//会报错,因为没有返回值,所以不能这样//cout << s1.push_back('e') << endl;//这样才正确s1.push_back('e');cout << s1 << endl;return 0;
}
运行结果如下:
push_back功能和append第五个重载函数的功能差不多,所以这个函数用得地方不多,而且我们发现它还没有返回值,所以不能直接打印,所以这个函数真的用处不大!
2.4string::assign
这个函数有6个重载,这个函数的功能和=重载函数功能一样,都是赋值,只不过它的功能更多一些:
(1)string& assign(const string& str);
把str直接赋值给string对象(this),并返回string对象的拷贝。
(2)string& assign(const string& str,size_t subpos,size_t sublen);
把str从subpos位置开始的sublen个字符赋值给string对象,并返回string对象的拷贝。
(3)string& assign(const char* s);
把s字符串赋值给string对象,并返回string对象的拷贝。
(4)string& assign(const char* s,size_t n);
把s字符串的前n个字符赋值给string对象,并返回string对象的拷贝。
(5)string& assign(size_t n,char c);
把n个c字符赋值给string对象,并返回string对象的拷贝。
(6)
template <class InputIterator>string& assign (InputIterator first, InputIterator last);
把迭代器从first到last位置的字符赋值给string对象,并返回string对象的拷贝。
#include<iostream>
using namespace std;
#include<string>
//string::assign
int main()
{string s("hello");cout << s << endl;//(1)string s1("ber");s.assign(s1);cout << s << endl;//(2)string s2("what can I say");s.assign(s2);cout << s << endl;//(3)s.assign("Just to do");cout << s << endl;//(4)s.assign("Deepseek", 4);cout << s << endl;//(5)s.assign(3, 'a');cout << s << endl;//(6)string s3("Happy NaoDongJie");s.assign(s3.begin(), s3.end());cout << s << endl;return 0;
}
运行结果为:
assign是否会扩容这种问题需要看是否有出现原空间不够的情况,这个扩容的知识我后面会专门来讲解的。如果原空间不够则需要扩容,否则不扩容。若扩容,则是深拷贝,并需要新申请一块空间;若不扩容则会先clear原空间后再覆盖原内容,这个讲底层的时候会进行更详细的讲解的!
2.5string::insert
insert函数的普遍功能是从pos位置开始插入数据。这些重载函数的解释和前两个差不多(参数名字都一样),所以我就不做解释了,而iterator是迭代器的意思,示例就在deepseek里面生成了,因为这个东西用法确实也不多,我在这里直接用Deepseek的搜索结果了:
在C++中,`std::string`的`insert()`函数有多种重载形式,用于在不同位置插入字符、字符串或子串。以下是所有重载形式的示例:
(1) 在指定位置插入一个字符
std::string s = "Hello";
s.insert(2, 1, 'X'); // 在索引2处插入1个'X'
// 结果: "HeXllo"
(2)在指定位置插入一个C风格字符串
std::string s = "Hello";
s.insert(3, " World"); // 在索引3处插入" World"
// 结果: "Hel Worldlo"
(3) 在指定位置插入另一个`std::string`
std::string s = "Hello";
std::string t = "C++";
s.insert(1, t); // 在索引1处插入t
// 结果: "HC++ello"
(4) 在指定位置插入另一个`std::string`的子串
std::string s = "Hello";
std::string t = "12345";
s.insert(4, t, 1, 3); // 在s的索引4处,插入t从索引1开始的3个字符
// 结果: "Hell234o"
(5) 在指定位置插入多个相同字符
std::string s = "Hello";
s.insert(0, 3, '!'); // 在开头插入3个'!'
// 结果: "!!!Hello"
(6) 在迭代器位置插入一个字符
std::string s = "Hello";
s.insert(s.begin() + 1, 'X'); // 在迭代器位置插入'X'
// 结果: "HXello"
(7) 在迭代器位置插入多个相同字符
std::string s = "Hello";
s.insert(s.begin() + 2, 2, 'Y'); // 在索引2处插入2个'Y'
// 结果: "HeYYllo"
(8)在迭代器位置插入一个字符范围(通过迭代器)
std::string s = "Hello";
std::vector<char> vec = {'A', 'B', 'C'};
s.insert(s.begin() + 3, vec.begin(), vec.end()); // 在索引3处插入vec的内容
// 结果: "HelABClo"
(9) 使用初始化列表插入多个字符
std::string s = "Hello";
s.insert(1, {'X', 'Y', 'Z'}); // 在索引1处插入初始化列表
// 结果: "HXYZello"
(10) 在迭代器位置插入初始化列表
std::string s = "Hello";
s.insert(s.begin() + 2, {'X', 'Y'}); // 在索引2处插入初始化列表
// 结果: "HeXYllo"
注意事项
1. 索引越界:如果`pos > size()`,会抛出`std::out_of_range`异常(与`at()`行为一致)。
2. 性能:频繁插入可能导致内存重新分配(扩容),可用`reserve()`预分配空间优化。
3. 返回值:部分重载(如迭代器版本)会返回指向插入内容的迭代器。
如果需要进一步优化或处理边界条件,可以结合`reserve()`和迭代器操作。
此外,insert也要少使用,因为insert需要找这个位置,还要移动后面的数据,所以非常麻烦,效率低。
2.6string::erase
erase有擦除的意思,有三个重载函数:
(1)string& erase(size_t pos=0,size_t len=npos);
从pos位置开始删除len个字符,如果没有给pos,则自动从开始位置开始删除;如果不给len就会删除npos个数据(全部删除)。
(2)iterator erase(iterator p);
可以删除一个迭代器位置,一般用得不多,但是一般用作头删。
(3)iterator erase(iterator first,iterator last);
删除迭代器的一段区间,但一般用前两个就可以实现了。
#include<iostream>
using namespace std;
#include<string>
//string::erase
int main()
{string s1("hello");string s2("hello");string s3("hello");cout << s1 << endl;//(1)s1.erase(1);cout << s1 << endl;//(2)s2.erase(s2.begin());cout << s2 << endl;//(3)s3.erase(s3.begin() + 1, s3.end());cout << s3 << endl;return 0;
}
运行结果为:
2.7string::replace
replace翻译过来有替换的意思。
(1)将str的从pos位置开始的len个字符替换成string对象,或者将str的i1开始的迭代器到i2结束的迭代器替换为string对象;
(2)用str的从subpos位置开始的sublen个字符替换掉string(原字符串)的从pos位置开始的len个字符。
(3)将string对象的从pos位置开始的len个字符替换为s和将原字符串中由迭代器范围[i1, i2)
指定的子串,替换为C风格字符串s
的内容。
(4)将string对象的从pos位置开始的len他字符替换为s的前n个字符和原字符串中由迭代器范围[i1, i2)
指定的子串,替换为C风格字符串s
的前n个字符。
(5)将string对象的从pos位置开始的len他字符替换为n个c字符和原字符串中由迭代器范围[i1, i2)
指定的子串,替换为C风格字符串s
的n个c字符。
这个函数比较复杂,所以我简单讲解一下示例:
#include<iostream>
using namespace std;
#include<string>
//string::replace
int main()
{string s("abcdefg");cout << s << endl;//(1.1)string s1("hijkmln");s.replace(0, 4, s1);cout << s << endl;//(1.2)string s2("hello");s.replace(s.begin(), s.end() - 3, s2);cout << s << endl;//(2)string s3("Just to do");s.replace(1, 5, s3, 0, 4);cout << s << endl;//(3.1)s.replace(0, 3, "abcde");cout << s << endl;//(3.2)s.replace(s.begin() + 1, s.end() - 2, "fghi");cout << s << endl;//(4.1)s.replace(2, 4, "jklmno", 4);cout << s << endl;//(4.2)s.replace(s.begin() + 1, s.end(), "nopq", 2);cout << s << endl;//(5.1)s.replace(0, 2, 2, 'a');cout << s << endl;//(5.2)s.replace(s.begin() + 2, s.end(), 3, 'b');cout << s << endl;return 0;
}
运行结果如下:
这个示例是随便给的,因为是演示一下用法,所以结果是不重要的,主要是熟悉一下迭代器的用法,之后会用迭代器用得多的地方是vector而不是string。
谨慎使用replace,因为大多数情况下效率极低,因为若替换的内容比被替换内容少或者多,都要往前/后移动数据,这种挪动要覆盖内容,影响效率,之后会讲其他的函数如find,如果加上insert等函数也可以实现该功能。
2.8string::swap
顾名思义,这个函数是交换两个string对象,不做过多讲解:
#include<iostream>
using namespace std;
#include<string>
//string::swap
int main()
{string s1("abcdefg");string s2("hijklmnop");s1.swap(s2);cout << s1 << endl;cout << s2 << endl;return 0;
}
运行结果如下:
2.9string::pop_back
这个函数只是删除一个字符的作用,所以用处不大,就不演示用法了。
3.总结
这一讲内容比较多,主要是我把一些不是很重要的函数讲的比较多了一些,而在这篇博客中有一些函数是与其他函数功能类似,有些函数功能也不是很大,所以我们主要是知道+=、[]、erase、swap这些函数的用法,其余的用处不是很大。下讲将讲解以下函数:
这些函数基本上只要知道用法就可以了。喜欢的可以一键三连哦!下讲再见!