C++ string类中函数的使用方法
**难受的一天从读英文文档开始**
1.默认成员函数
1.1构造函数
构造函数的重载函数如下:
int main()
{
// 1.string();
// 无参的构造函数
string s1;
cout << s1 << endl;
// 2.string(const char* s);
// 用一个字符串初始化 s2
string s2("abcdefgh");
cout << s2 << endl;
// 3.string(const string & str);
// 用一个类构造 s3
string s3(s2);
cout << s3 << endl;
// 4.string(const string & str, size_t pos, size_t len = npos);
// 从 str 的 pos 下标的位置开始, 向后取 len 个字符 初始化 s4
string s4(s2, 4,3);
cout << s4 << endl;
// npos 默认值为 -1 -1转化为无符号类型是一个特别大的整数 2的31次方
// 因为len的缺省值是npos
// 第三个参数不传值,会把 str 从 pos开始向后 到 \0 前的所有字符拷贝到 s5
string s5(s2, 0);
cout << s5 << endl;
// 5.string(const char* s, size_t n);
// 用字符串 s 的前 n 个字符初始化 s6
string s6("abcdexyz",7);
cout << s6 << endl;
// 这里要与 75 行的代码区分开,75行的第一个形参是string类型的类,
// 这个函数的第一个参数是一个字符串
// 6.string(size_t n, char c);
// 用 n 个 c 字符初始化 s7
string s7(7,'x');
cout << s7 << endl;
return 0;
}
1.2析构函数与赋值函数
析构函数由系统自动调用,也不需要传参数
赋值函数的三种重载方式:
看参数就知道它可以赋值string类,字符串,单个字符
int main()
{
string s1;
string s2("abcdefgh");
s1 = s2;
cout << s1 << endl;
s1 = "xxxxx";
cout << s1 << endl;
s1 = 'c';
cout << s1 << endl;
return 0;
}
2.迭代器iterator
2.1begin
它的返回值是 iterator 迭代器,如果是const对象,那它的返回类型就是const_iterator
如果const对象调用begin()函数,那它的返回值一定要写成const_iterator,权限可以缩小但不可以放大
正确写法:
string s1("abcdefgh");
const string s2(s1);
string::iterator it1 = s1.begin();
string::const_iterator it2 = s2.begin();
2.2 end
end与begin的返回类型相同,它是指向有效数据的下一个位置
它们结合起来的使用方法:
string s1("abcdefgh");
string::iterator it1 = s1.begin();
while (it1 != s1.end())
{
(*it1)++;
it1++;
}
cout << s1 << endl;
string s1("abcdefgh");
//用s1的begin+3位置开始,到begin+4位置的前一个字符,构造s2
string s2(s1.begin() + 3, s1.begin()+4);
cout << s2 << endl;
2.3 rbegin与rend
rbegin就是结尾的第一个数据,rend就是开头的前一个字符。
而且rbegin的++,就是向前移动。rend的–是向后移动。
string s1("abcdefgh");
string::reverse_iterator it1 = s1.rbegin();
cout << *it1 << endl;
string::reverse_iterator it2 = s1.rend();
cout << *(it2-1) << endl;
使用场景:我们想要逆序输出string的所有数据
string s1("abcdefgh");
string::reverse_iterator it1 = s1.rbegin();
while (it1 != s1.rend())
{
cout << *it1 << ' ';
it1++;
}
cout << endl;
当一个const string 类型的对象 调用 rbegin与rend它的返回值分别为reverse_iterator,const_reverse_iterator
2.4cbegin,cend,crbegin,crend
cbegin,cend相当于返回类型为const_iterator 的begin和end
crbegin,crend相当于返回类型为const_reverse_iterator 的rbegin和rend
3.capacity容量
这些函数比较简单,基本上看一下就知道它怎么使用了
string s1("abcdefgh");
cout << s1.size() << endl;
cout << s1.length() << endl;
cout << s1.max_size() << endl;
cout << s1.capacity() << endl;
s1.clear();
cout << s1 << endl;
cout << s1.empty() << endl;
resize与reserve
1.基本使用方法
resize
1.传一个参数意思是可以把它的长度扩大或缩小
2.传两个参数,第一个参数是要修改size的大小,第二个参数是如果size扩大了,把扩大的内容都初始化为第二个参数
string s1("abcdefgh");
cout << s1.size() << endl;
s1.resize(50,'c');
cout << s1 << endl;
s1.resize(50);
cout << s1.size() << endl;
s1.resize(5, 'c');
cout << s1 << endl;
reserve改变对象的容量,但它相当于是给编译器一个建议,也可能不会修改容量
它可以扩容也可以缩容,但这需要我们自己来观察容量,不同编译器下它的扩容和缩容规则不一样。
为什么是这样呢,这与编译器有关,我使用的的vs2019
这个编译器的扩容规则是,第一次扩容是×2倍的容量,后面的扩容是×1.5倍的容量,
缩容也是有消耗的,需要先释放掉原来的空间,在从新申请空间,来保存有效数据
那为什么第一次缩容失败了,第二次却成功了?
实际上编译器在初始化s1时多开辟了空间,其中多开的空间中有一个16个字节的字符数组,
因为申请空间是有消耗的所以如果初始化时的空间小于16就把数据存在数组中,如果大于16才会去开辟空间
这里的buf数组就是string类在我们创建对象时开辟的
reverse的使用场景:知道之后的程序需要多少空间,一次性直接开辟好,之后不需要扩容,因为扩容可能也会有消耗。
string s1;
s1.reserve(200);
cout << s1.capacity() << endl;
它们两的关联
结论:resize 的扩大可能会影响 容量capacity
但 reserve 不管是扩大还是缩小容量都不会改变resize
string s1;
s1.reserve(200);
s1 = "1111111111111111111111111";
cout << s1.size() << endl;
cout << s1.capacity() << endl;
s1.resize(500);
cout << s1.size() << endl;
cout << s1.capacity() << endl;
s1.reserve(10);
cout << s1.size() << endl;
cout << s1.capacity() << endl;
4.Element access数据的存取
operator【】是以下标来访问数据
at就是访问对象的第pos个位置的数据
back访问最后一个,front是访问第一个数据
string s1("abcdefg");
cout << s1[5] << endl;
cout << s1.at(5) << endl;
cout << s1.back() << endl;
cout << s1.front() << endl;
注意:如果是const类型对象返回值是不能修改的。每个功能都重载了一个const类型
5.修改
1.operator+=
直接可以理解为在string类的后面插入数据
// += 的对象可以是 字符串,string类,字符
string s1("abcdefg");
string s2("xxx");
s1 += s2;
s1 += "yyy";
s1 += 'z';
2.append
在string类后插入数据,虽然参数比较多,但是函数的形式与之前的构造函数那里意思大致相同。
string s1("abcdefg");
string s2("xxx");
string s3("yyy");
s1.append(s2);
cout << s1 << endl;
s1.append(s3,1,2);
cout << s1 << endl;
s1.append("zzz");
cout << s1 << endl;
const char* str = "qqqqqqqqqqqq";
s1.append(str, 5);
cout << s1 << endl;
s1.append(9, 'r');
cout << s1 << endl;
3.push_back
在string类后插入一个字符
string s1("abcdefg");
s1.push_back('s');
cout << s1 << endl;
4.assign
功能还是与之前类似,推荐大家亲自动手实现一遍这些功能,这里的参数一眼就可以看的懂
用一个新的字符串覆盖掉这个字符串。功能类似之前的strcpy。
string s1("abcdefg");
cout << s1 << endl;
string s2("xxx");
s1.assign(s2);
cout << s1 << endl;
s1.assign("yyyy");
cout << s1 << endl;
s1.assign("123456789",5);
cout << s1 << endl;
s1.assign(5, 'c');
cout << s1 << endl;
5.insert
在string类中插入数据
string s1("abcdefg");
string s2(" xxx ");
cout << s1 << endl << endl;
//在s1的第一个位置插入s2
s1.insert(1, s2);
cout << s1 << endl;
//在s1的第pos个位置插入,s2的第pos后的len给字符
//string& insert(size_t pos, const string& str, size_t subpos, size_t sublen);
s1.insert(1, s2, 3, 1);
cout << s1 << endl << endl;
//在第pos个位置插入字符串
s1.insert(0, "sss");
cout << s1 << endl << endl;
//在pos位置插入n个字符c
s1.insert(0, 2, '1');
cout << s1 << endl << endl;
//迭代器位置插入n个字符c
s1.insert(s1.begin(), 2, '2');
cout << s1 << endl << endl;
//迭代器位置插入字符c
s1.insert(s1.begin(), 'z');
cout << s1 << endl << endl;
6.erase
删除字符串中的一部分
可以看到erase函数是有缺省值的如果什么都不传的话就会把字符串清空
//清空字符串
string s1("abcdefg");
s1.erase();
cout << s1.size() << endl;
cout << s1 << endl;
//从第三个位置开始删除两个字符
string s2("abcdefg");
s2.erase(3,2);
cout << s2.size() << endl;
cout << s2 << endl;
//删除第三个字符之后的字符
string s3("abcdefg");
s3.erase(3);
cout << s3.size() << endl;
cout << s3 << endl;
7.replace
用新内容替换字符串中从字符pos开始并跨越len字符的部分(或字符串中介于[i1,i2)之间的部分)
先讲第一个函数,后面的大致与这个都相同
string s1("abcdefg");
cout << s1 << endl;
string s2("xxxxx");
string s3("y");
//s1的pos个位置向后len个长度改为s2
//如果replace的第二个参数,小于s2的长度则把s2全部拷贝过去
s1.replace(3, 2, s2);
cout << s1 << endl;
//如果replace的第二个参数长度,大于s2
//那就从pos位置向后数的len给长度替换为s3,不会拷贝s2的 '\0'
s1.replace(3, 3, s3);
cout << s1 << endl;
迭代器版本:
string& replace (iterator i1, iterator i2, const string& str);
意思为将某个区间替换
string s1("abcdefg");
cout << s1 << endl;
string s2("xxx");
string::iterator it1 = s1.begin();
it1 += 3;
string::iterator it2 = s1.end();
// 用s2替换掉s1中【it1,it2】的位置
s1.replace(it1, it2, s2);
cout << s1 << endl;
8.swap
与另一个string类交换
string s1("abcdefg");
string s2("xxxxxxx");
s1.swap(s2);
cout << s1 << endl;
cout << s2 << endl;
9.pop_back
尾删,每次删除一个字符
strint s1("abcdefg");
cout << s1 << endl;
s1.pop_vack();
cout << s1 << endl;
s1.pop_vack();
cout << s1 << endl;
6.String operations
1.c_str,data,copy
string s1("abcdcdcd");
//获取等价的s1字符串
const char* str = s1.c_str();
cout << str << endl;
//输出s1中的数据
cout << s1.data() << endl;
//size_t copy (char* s, size_t len, size_t pos = 0) const;
//向s中拷贝 len 个字符,从 string类的第pos个位置开始
char s[10] = "aaaaaa";
s1.copy(s, 3, 2);
cout << s1 << endl;
cout << s << endl;
函数易懂看输出结果就可以知道它的作用了
2.find系列
find与rfind
string s1("abcdcd");
string s2("cd");
//size_t find(const string& str, size_t pos = 0) const;
//不传参数
cout << s1.find(s2) << endl;
//传递参数
cout << s1.find(s2, 3) << endl;
//size_t rfind(const string& str, size_t pos = npos) const;
//返回最后一次出现的位置,这个函数是从最后一个位置开始查找
cout << s1.rfind(s2) << endl;
//传递参数
cout << s1.rfind(s2,0) << endl;
find_first_of 与 find_last_of
find_first_of
string s1("i like you");
string s2("aeiou");
//在string类中找给定string类中任意一个字符出现的第一个字符
// 即 s2 中的任意一个字符在 s1 中第一次出现的位置
cout << s1.find_first_of(s2) << endl;
//也可以指定从 s1 的第pos给位置开始找
cout << s1.find_first_of(s2, 1) << endl;
find_last_of
在字符串中搜索与参数中指定的任何字符匹配的最后一个字符。
find_first_not_of 与 find_last_not_of
string s1("i like you");
string s2("aeiou");
//在字符串中搜索第一个与参数中指定的任何字符不匹配的字符。
cout << s1.find_first_not_of(s2) << endl;
//在字符串中搜索最后一个与参数中指定的任何字符不匹配的字符。
cout << s1.find_last_not_of(s2) << endl;
3.strsub
string s1("i like you");
string s2;
//string substr(size_t pos = 0, size_t len = npos) const;
//返回一个新构造的字符串对象,其值初始化为此对象的子字符串的副本。
s2 = s1.substr(2,7);
cout << s1 << endl;
cout << s2 << endl;
4.compare
它的用法与C语言中的字符串比较函数完全一样
int compare (const string& str) const;
比较方法:从第一个字符按ascll码向后比较
大于返回 大于0的数
小于返回小于0的数
等于返回 0