在C语言中,字符串是以’\0’结尾的一些字符的集合,为了操作方便,C标准库中提供了一些str系列的库函数,但是这些库函数与字符串是分离开的,而且底层空间需要用户自己管理,稍不留神可能会越界访问。
-
标准库中的string类
1) string是表示字符串的字符串类。
2)该类的接口与常规容器的接口基本相同,再添加了一些专门用来操作string的常规操作。
3) string在底层实际是:basic_string模板类的别名,typedef basic_string<char, char_traits, allocator> string;。
4) 不能操作多字节或变长字符的序列。 -
string类的常用接口
这里列出string对象的常见构造和容量操作:
#include<iostream>
#include<string>
using namespace std;
void TestString1()
{
//string类的常见构造
string s1;//构造空的string类对象s1
string s2("hello world");//用C-string字符串来构造string类对象s2
cout << s2 << endl;
string s3(10, 'a');//用10个字符'a'构造string类对象s3
string s4(s2);//拷贝构造s4
string s5(s2, 5);//用s2中前5个字符构造string对象s5
//string类对象的容量操作
cout << s2.size() << endl;//返回字符串的有效字符长度
cout << s3.capacity() << endl;//返回s3空间的总大小
s2.clear();//清空有效字符串
cout << s2.size() << endl;//清空后size为0
cout << s2.capacity() << endl;//但清空后capacity的大小不变
s2.resize(10, 'a');//将s2中的有效字符个数增加到10个,多出位置用'a'进行填充
cout << s2 << endl; //"aaaaaaaaaa"
s2.resize(15);//将s2中的有效字符个数增加到15个,多处的位置用缺省值'\0'填充
cout << s2 << endl;//"aaaaaaaaaa\0\0\0\0\0"
s2.resize(3);//将s2中的有效字符个数缩小到3个
cout << s2.size() << endl;
cout << s2.capacity() << endl;
cout << s2 << endl;//"aaa"
}
int main()
{
TestString1();
return 0;
}
运行结果:
void TestString2()
{
//string对象的修改操作
//reserve insert erase replace push_back append
string s("I am a student");
s.reserve(100);
cout << s.size()<< endl;//输出为0
cout << s.capacity() << endl;//输出为111,说明reserve不会改变string中的有效个数元素
s.reserve(50);
cout << s.size() << endl;//输出为0
cout << s.capacity() << endl;//输出为111,说明reserve参数小于string的底层空间大小时,不会将空间缩小
s.insert(0, "hello");//在0位置插入hello
cout << s << endl;
s.erase(0, 5);//在0位置向后删除5个字符
cout << s << endl;
s.replace(0, 3, "bitxxx");//在0位置向后替换前3个字符,剩余部分接着向后覆盖
cout << s << endl;
s.push_back('A');//在字符串末尾插入字符'A'
cout << s << endl;
s.append("hehe");//在字符串末尾追加"hehe"
cout << s << endl;
}
int main()
{
TestString2();
return 0;
}
运行结果:
void TestString3()
{
//string对象的访问操作
string s1("hello world");
const string s2("Hello world");
cout << s1 << " " << s2 << endl;
cout << s1[0] << " " << s2[0] << endl;
s1[0] = 'H';
cout << s1 << endl;
for(size_t i = 0;i < s1.size();++i)
{
cout << s1[i] << " ";
}
cout << endl;
//但是不能用s2[0] = 'h',因为const类型对象不能修改
}
int main()
{
TestString3();
return 0;
}
运行结果:
注意:
1)size()与length()方法底层实现原理完全相同,引入size()的原因是为了与其他容器的接口保持一 致,一般情况下基本都是用size()。
2) clear()只是将string中有效字符清空,不改变底层空间大小。
3)resize(size_t n) 与 resize(size_t n, char c)都是将字符串中有效字符个数改变到n个,不同的是当字符个数增多时:resize(n)用0来填充多出的元素空间,resize(size_t n, char c)用字符c来填充多出的 元素空间。注意:resize在改变元素个数时,如果是将元素个数增多,可能会改变底层容量的大小,如果是将元素个数减少,底层空间总大小不变。
4) reserve(size_t res_arg=0):为string预留空间,不改变有效元素个数,当reserve的参数小于 string的底层空间总大小时,reserver不会改变容量大小。
- string的几种遍历方式
1.for循环方式的遍历(适用于地址连续的空间)
string s("hello world");
for(int i = 0;i < s.size(); ++i)
{
cout << s[i] << " ";
}
cout << endl;
2.迭代器方式的遍历(通用)
string s("hello world");
string::iterator it = s.begin();
while(it != s.end)
{
cout << *it << " ";
++it;
}
//反向迭代器
string::reverse_iterator rit = s.rbegin();
while(rit != s.rend)
{
cout << *rit << " ";
++rit;
}
cout << endl;
3.范围for(可以遍历所有的容器,底层是依赖迭代器实现的)
string s("hello world");
for(auto ch : s)
{
cout << ch << " ";
}
cout << endl;
- 获取文件后缀以及网址的取域名
void TestString4()
{
//获取file1的后缀
string file1("string.cpp");
size_t pos = file1.rfind('.');
string suffix(file1.substr(pos, file1.size() - pos));
cout << suffix << endl;
// npos是string里面的一个静态成员变量
// static const size_t npos = -1;
// 取出url中的域名
string url("http://www.cplusplus.com/reference/string/string/find/");
cout << url << endl; size_t start = url.find("://");
if (start == string::npos)
{
cout << "invalid url" << endl;
return;
}
start += 3;
size_t finish = url.find('/', start);
string address = url.substr(start, finish - start);
cout << address << endl;
// 删除url的协议前缀
pos = url.find("://");
url.erase(0, pos+3);
cout<<url<<endl;
}
int main()
{
TestString4();
return 0;
}
运行结果: