标准库中的string类
在使用string类时,必须包含#include头文件以及using namespace std;
string类的常用接口说明
C++中string为我们提供了丰富的接口来供我们使用 – string接口文档
这里我们只介绍一些常见的接口
string类对象的常见构造
#include <iostream>
using namespace std;
int main()
{
;
cout << string() << endl;
string s1("hello");
cout << s1 << endl;
string s2(5, 'x');
cout << s2 << endl;
string s3(s1);
cout << s3 << endl;
return 0;
}
string类对象的容量操作
1.size 和 length
在string类中我们通过size()和length()来返回字符串的有效字符的长度
int main()
{
string s1("hello");
cout << s1.size() << " " << s1.length();
return 0;
}
2.max_size( )
max_size() 返回的是字符串的最大长度,不同位数系统字符串最大长度还不同,但一般字符串都开不了这么大的空间
32位系统:
int main()
{
string s1("ssss");
cout << s1.max_size() << endl;
return 0;
}
capacity
capacity()返回的是字符串的空间大小,其和字符串的有效长度并不相同,及为字符串可容纳的最大长度,到了最大长度就会扩容
int main()
{
string s1("ssss");
cout << s1.size() << " " << s1.capacity();
return 0;
}
reserve
reserve()当字符串容量不足时,reserve( )会对字符串进行扩容,及size == capacity时
vs和linux(g++)下字符串扩容和缩容机制
int main()
{
string s;
size_t sz = s.capacity();
cout << "capacity:" << sz << endl;
cout << "making s grow:" << endl;
for (int i = 0; i < 100; i++)
{
s.push_back('c');
if (sz != s.capacity())
{
sz = s.capacity();
cout << "capacity changed:" << sz << endl;
}
}//在linux上g++和vs上的capacity都是不计算/0
//如何扩容c++标准并没有规定
return 0;
}
- VS扩容:
这里的capacity要比实际上的capacity要小1,因为在VS上capacity并没有将 ‘\0’ 计算进来
- 为什么初始字符串容量大小为15呢?
- VS中string的结构
string总共占28个字节,内部结构稍微复杂一点,先是有一个联合体,联合体用来定义
string中字符串的存储空间:
当字符串长度小于16时,使用内部固定的字符数组来存放
当字符串长度大于等于16时,从堆上开辟空间
还有一个size_t字段保存字符串长度,一个size_t字段保存从堆上开辟空间总的容量
最后:还有一个指针做一些其他事情。
故总共占16+4+4+4=28个字节。
int main()
{
string s;
size_t sz = s.capacity();
cout << "making s grow:" << endl;
for (int i = 0; i < 100; i++)
{
s.push_back('c');
if (sz != s.capacity())
{
sz = s.capacity();
cout << "capacity changed:" << sz << endl;
}
}//在linux上g++和vs上的capacity都是不计算/0
//如何扩容c++标准并没有规定
return 0;
}
- Linux扩容
int main()
{
string s("111111111111111");//string中有一个16个字节的buff数组
cout << s.capacity() << endl;
s.reserve(100);
cout << s.capacity() << endl;
s.reserve(20);
cout << s.capacity() << endl;//vs不会缩容,而linuxg++会缩容
return 0;
}
VS缩容:
VS下不会进行缩容
Linux缩容
resize( )
将有效字符的个数改成n个
int main()
{
string s = "11111111";
s.resize(5, '0');//不会进行缩容
cout << s.capacity() << " " << s.size() << endl;
s.resize(10, '0');
cout << s.capacity() << " " << s.size() << endl;
return 0;
}
int main()
{
string s = "11111111";
s.resize(5, '0');//不会进行缩容
cout << s << endl;
s.resize(10, '0');
cout << s << endl;
return 0;
}
- 当 resize中n > size ,则会对其进行插入补充字符C,如果没有参数C,就回默认补充字符 ‘\0’ ,
string迭代器
迭代器(Iterator)是一种设计模式,它提供了一种方法顺序访问一个集合对象中的各个元素,而无需暴露该对象的内部表示。
begin 和 end
begin指向字符串开始位置,end指向字符串最后一个字符的下一个位置
rbegin 和 rend
const 迭代器
int main()
{
const string s2("1111111");
string::const_iterator it = s2.begin();
}
string类对象的访问及遍历操作
对于string类的遍历,我们有几种方式来进行遍历:
- 调用at进行访问
int main()
{
string s1("hello world");
for (size_t i = 0; i < s1.size(); i++)
{
cout << s1.at(i) << " ";
}
return 0;
}
at 与 下标加[ ] 进行访问的区别就是越界时 at可以捕获异常,而 [] 不可以捕获异常,直接就回报错
int main()
{
string s("sssssss");
try
{
//s[11];//越界,没有商量的余地
s.at(11);//有商量的余地,可以捕获异常
}
catch (const exception& e)
{
cout << e.what() << endl;
}
return 0;
}
int main()
{
string s("sssssss");
try
{
s[11];//越界,没有商量的余地
}
catch (const exception& e)
{
cout << e.what() << endl;
}
return 0;
}
- 下标加 [] 进行访问遍历(及通过operator[ ]进行访问)
int main()
{
string s1("hello world");
for (size_t i = 0; i < s1.size(); i++)
{
cout << s1[i] << " ";
}
return 0;
}
- 范围for进行访问
int main()
{
string s1("hello world");
for (auto e : s1)
{
cout << e << " ";
}
return 0;
}
- 迭代器进行访问
int main()
{
string::iterator it = s1.begin();
while (it != s1.end())
{
cout << *it << endl;
it++;
}
return 0;
}
int main()
{
string s1("hello world");
string::reverse_iterator rit = s1.rbegin();
while (rit != s1.rend())
{
*rit = 'x';
cout << *rit << " ";
rit++;
}
const string s2("hello world");
string::const_iterator it = s2.begin();
while (it != s2.end())
{
cout << *it << " ";
it++;
}
}
string类对象的修改操作
push_back 和 append 和 operator+=
int main()
{
string s1 = "hello world";
s1.push_back('x');//在字符串后添加一个字符
cout << s1 << endl;
s1.append("xxxxx");//在字符串后添加一床字符
cout << s1 << endl;
s1 += "myself";//在字符串后添加字符串
cout << s1 << endl;
}
下面是上面函数的其他函数重载
assign
int main()
{
string s("12344512233");
s.assign("111");
cout << s << endl;
}
insert 和 erase
string s("122222");
s.insert(s.begin(), 'y');
cout << s << endl;
s.insert(6,"xxxx");
cout << s << endl;
string s1("mmm");
s.insert(s.begin(), s1.begin(), s1.end());
cout << s << endl; //慎用,效率不高
s.erase(1,3);
cout << s << endl;
s.erase(s.begin());
cout << s << endl;
s.erase(s.begin(), s.end());
cout << s << endl;
replace
int main()
{
string s("1111111");
s.replace(2, 6, "s");
cout << s << endl;
}
swap
int main()
{
string s("1111111");
string s1("sss");
s.swap(s1);
cout << s << " " << s1;
}
pop_back
int main()
{
string s("1111111s");
s.pop_back();
cout << s;
}
string类对象的查找操作
int main()
{
string str = "We think in generalities, but we live in details.";
size_t pos = str.find("live");
cout << pos;
return 0;
}