C++—string类接口与用法大总结(其中涉及STL基础)
目录
1.string类的本质
2.string类的构造
1.普通构造
2.功能型构造
1.拷贝构造功能型
2.带参构造功能型
3.其余构造
3.operator[]
4.迭代器(iterator)
1.概念
2.改变string对象本身
3.正向迭代器(iterator)
4.反向迭代器(reverse_iterator)
5.const迭代器
1.const正向迭代器(const_iterator)
2.const反向迭代器(const_reverse_iterator)
5.范围for(遍历与修改)
0.auto
1.概念
2.不改变string对象本身
3.改变string对象本身
6.容量系列
1.size:求有效数据个数(不算'\0')
2.capacity:求顺序表容量
3.reserve:用于扩容和缩容
1.扩容:
2.缩容:
7.增删系列
1.push_back:尾插一个字符
2.append:尾插一个字符串
3.operator+=:拼接字符或字符串
4.insert:在指定下标插入字符串或字符
1.插入字符串:
2.插入字符:
5.erase:从指定下标开始删除k个字符
8.replace:替换
9.find:查找(找到指定内容并返回其第一次出现的下标)
10.swap:交换函数
11.c_str:返回string类的指针成员变量(本质是为了兼容C语言)
12.substr:从某个下标开始的k个字符构造成一个新的string对象并返回
13.find_first_of:从s1中找是否存在我传过去的字符串中的任意一个字符,如果比对成功则返回下标
14.operator+
15.getline:默认遇到\n才会停止在缓冲区中取数据(cin默认遇到空格和\n就会停止在缓冲区中取数据)
1.string类的本质
string类是由字符组成的顺序表。
2.string类的构造
1.普通构造
#include <iostream>
#include <string>
using namespace std;
int main()
{//默认构造string s1;//带参构造string s2("111111");//拷贝构造string s3(s2);cout << s1 << endl;cout << s2 << endl;cout << s3 << endl;
}
结果:
2.功能型构造
1.拷贝构造功能型
string s1("hello world");//拷贝构造功能型//从下标为6的字符开始拷贝5个字符
string s2(s1, 6, 5);
//如果第三个参数超出了字符串的范围,就是从下标为6开始、打印完就结束
string s3(s1, 6, 50);
//省略第三个参数的话,就是从下标为6开始、打印完就结束
string s4(s1, 6);cout << s1 << endl;
cout << s2 << endl;
cout << s3 << endl;
cout << s4 << endl;
结果:
2.带参构造功能型
//拿字符串前5个字符构造
string s1("hello world",5);
cout << s1 << endl;
结果:
3.其余构造
//拿10个X组成字符串构造
string s1(10, 'X');
cout << s1 << endl;
结果:
3.operator[]
string类中重载了[]运算符,使其能够像数组一样使用。
class string
{
public:char& operator[](int x){return arr[x];}private:char* arr;int size;int capacity;
};
用引用返回是为了能够改变指定下标的值。
string s1("hello world");
s1[0] = 'X';
cout << s1 << endl;
结果:
4.迭代器(iterator)
1.概念
s1.begin()指向第一个元素,s1.end()指向最后一个元素的下一个元素。(最后一个元素指的是最后一个有效元素)
string s1("hello");
string::iterator it = s1.begin();
while (it != s1.end())
{cout << (*it)<<" ";it++;
}
cout << endl;
注意:这里的it可以当指针理解,但本质不一定是指针。
结果:
2.改变string对象本身
string s1("hello");
string::iterator it = s1.begin();
while (it != s1.end())
{//这里会改变s1的每个变量*it += 2;it++;
}
cout << s1 << endl;
结果:
3.正向迭代器(iterator)
s1.begin()指向第一个元素,s1.end()指向最后一个元素的下一个元素。(最后一个元素指的是最后一个有效元素)
string s1("hello");
string::iterator it = s1.begin();
while (it != s1.end())
{cout << (*it)<<" ";it++;
}
cout << endl;
结果:
4.反向迭代器(reverse_iterator)
rbegin指向最后一个元素,rend指向第一个元素的前一个元素。
string s1("hello");
string::reverse_iterator rit = s1.rbegin();
while (rit != s1.rend())
{cout << *rit << " ";rit++;
}
结果:
5.const迭代器
1.const正向迭代器(const_iterator)
const string s3("hello world");
string::const_iterator cit = s3.begin();
while (cit != s3.end())
{//不能*cit += 2;cout << *cit << " ";++cit;
}
cout << endl;
2.const反向迭代器(const_reverse_iterator)
const string s3("hello world");
string::const_reverse_iterator rcit = s3.rbegin();
while (rcit != s3.rend())
{// 不能*rcit += 2;cout << *rcit << " ";++rcit;
}
cout << endl;
5.范围for(遍历与修改)
范围for适用于容器和数组
0.auto
auto是用来自动推导类型的。
string s1("hello");
//string::iterator it = s1.begin();//这里的迭代器也可以这么写:
auto it = s1.begin();
//这样写编译器会自动推导出auto此时的位置应该是一个迭代器类型
auto存在的目的是为了简化代码,但弊端就是降低了代码的可读性。
1.概念
string s2("hello");
//范围for底层是一个迭代器
//这里的x相当于拷贝的*it
for (auto x : s2)
{cout << x << " ";
}
结果:
2.不改变string对象本身
string s2("hello");
//范围for底层是一个迭代器
//这里的x相当于拷贝的*it
for (auto x : s2)
{//这里不会改变s2字符串本身,因为x变量只是拷贝x += 2;cout << x << " ";
}cout << endl << s2 << endl;
结果:
3.改变string对象本身
string s2("hello");
//范围for底层是一个迭代器
//这里的x相当于*it的别名
for (auto& x : s2)
{//这里会改变s2字符串本身,因为x变量是引用的s2中的每一个变量x += 2;cout << x << " ";
}cout << endl << s2 << endl;
结果:
6.容量系列
1.size:求有效数据个数(不算'\0')
string s1("hello");
cout << s1.size() << endl;
结果:
2.capacity:求顺序表容量
string s1("hello");
cout << s1.capacity() << endl;
结果:
3.reserve:用于扩容和缩容
1.扩容:
s1.reserve(100);
假如上述语句是在扩容,那么容量会变成比100要大或者等于100的数。
2.缩容:
s1.reserve(2);
假如上述语句是在缩容,那么容量会不会变小不好说,取决于编译器,但是最起码能够保证的是,它绝对不会因为缩容而影响你原来的数据。
7.增删系列
1.push_back:尾插一个字符
string s1("hello");
s1.push_back('o');
cout << s1 << endl;
结果:
2.append:尾插一个字符串
这里的众多接口与前面讲到的构造类似,所以不再过多赘述。
string s1("hello");
s1.append("xxx");
cout << s1 << endl;
结果:
3.operator+=:拼接字符或字符串
string s1("hello");
s1 += ' ';
s1 += "world";
cout << s1 << endl;
结果:
4.insert:在指定下标插入字符串或字符
1.插入字符串:
string s1("hello");
//在下标为1的位置插入xxx
s1.insert(1, "xxx");
cout << s1 << endl;
结果:
2.插入字符:
string s1("hello");
char ch = 'x';
//在下标为0的位置插入2个ch字符
s1.insert(0, 2, ch);
cout << s1 << endl;
结果:
这里的第二个参数不能省略从而变成插入1个字符,可见C++中的string类的设计是有一些冗余的。
5.erase:从指定下标开始删除k个字符
string s1("hello world");
//从指定下标0开始删除1个数据
s1.erase(0, 1);
cout << s1 << endl;
结果:
string s1("hello world");
//若省略第二个参数,则从指定下标6开始删除直到结束
s1.erase(6);
cout << s1 << endl;
结果:
8.replace:替换
string s1("hello world");
//将下标为5起始的4个元素替换
s1.replace(5, 4, "xxx");
cout << s1 << endl;
结果:
9.find:查找(找到指定内容并返回其第一次出现的下标)
string s1("hello world");//返回找到的下标,如果没找到,则返回npos
int pos = s1.find("hello");
cout << pos << endl;
结果:
string s1("hello world hello hello ");//返回找到的下标(从3下标开始找),如果没找到,则返回npos
int pos = s1.find("hello",3);
cout << pos << endl;
结果:
10.swap:交换函数
swap函数用来交换两个对象的所有成员变量。
string s1("hello xxx");
string s2("hello yyy");
s1.swap(s2);
cout << s1 << endl;
cout << s2 << endl;
结果:
11.c_str:返回string类的指针成员变量(本质是为了兼容C语言)
class string
{
public:private:char* arr;int size;int capacity;
};
string s1("hello xxx");
string s2("hello yyy");
const char* str1 = s1.c_str();
这里的s1.c_str()返回的就是s1.arr
12.substr:从某个下标开始的k个字符构造成一个新的string对象并返回
//例如我想找到一个文件后缀名
string s1("test.cpp");
int pos = s1.rfind('.');
string s2 = s1.substr(pos);
cout << s2 << endl;
结果:
13.find_first_of:从s1中找是否存在我传过去的字符串中的任意一个字符,如果比对成功则返回下标
这个接口作者本人觉得命名不太好,应该改成find_any_of会更容易理解一些
string s1("hello world");
cout<<s1.find_first_of("abcde")<<endl;
结果:
string s1("hello world");
//从下标为3的位置开始找
cout<<s1.find_first_of("abcde",3)<<endl;
结果:
还有一个接口是find_last_of,而这个接口就是将find_first_of换成倒着找而已。说实话这个名字取得也有点矬,应该取名为rfind_any_of会更好一些(作者吐槽)。
14.operator+
string s1("abc");
string s2 = "de" + s1;
cout << s2 << endl;
结果:
15.getline:默认遇到\n才会停止在缓冲区中取数据(cin默认遇到空格和\n就会停止在缓冲区中取数据)
string s1;
//默认遇到\n才会停止取数据
getline(cin, s1);
cout << s1 << endl;
结果:
string s1;
//默认遇到*才会停止取数据
getline(cin, s1,'*');
cout << "——————————————"<<endl;
cout << s1 << endl;
结果: