文章目录:
1️⃣关于string类(标准库)
1、string是表示字符串的字符串类。
2、string类的接口与常规容器的接口基本相同,再添加了一些专门用来操作string的常规操作。
3、string类是使用char,string在底层是:basic_string模板类的别名,typedef basic_string<char,char_traits,alloctaor> string。
4、string类是basic_string模板类的一个实例,它使用char来实例化basic_string模板类,并用char_traits和allocator作为basic_string的默认参数。
5、string类独立于所使用的编码来处理字节:若用来处理多字节或者变长字符(UTF-8等)的序列,string类的所有成员以及它的迭代器,将仍热按照字节来操作,而不是按照实际编码的字 符来操作。
2️⃣string类常用接口
string类常见构造
(constructor)函数名称 | 功能 |
---|---|
string() | 构造空的string类对象,即构造空字符串 |
string(const char * s) | c_string构造string类对象 |
string(const string& str) | 拷贝构造函数 |
string(size_t n,char c) | 用n个字符c来构造string类对象 |
int main()
{
string s1; //构造空的string类对象s1
string s2("world"); //用c形式的字符串构造string类对象s2
string s3 = "world";
string s4(s3); //用s3拷贝构造s4
string s5(5, 'x'); //用5个字符x来构造s5
return 0;
}
string类对象的容量操作
resize
⚽️将有效字符的个数该成n个,多出的空间用字符c填充
int main()
{
string s1("resize");
s1.resize(15);
string s2("resize");
s2.resize(15, 'x');
return 0;
}
reserve
🚀用reserve来提高插入数据的效率,避免频繁的增容带来的开销
void TestReserve()
{
string s;
s.reserve(115);
size_t sz = s.capacity();
cout << "make s grow" << endl;
for (int i = 0;i < 115;++i)
{
s.push_back('x');
if (sz != s.capacity())
{
sz = s.capacity();
cout << "capacity changed : " << sz << endl;
}
}
}
运行测试:
void Teststring2()
{
string s;
// 测试reserve是否会改变string中有效元素个数
s.reserve(100);
cout << s.size() << endl;
cout << s.capacity() << endl;
// 测试reserve参数小于string的底层空间大小时,是否会将空间缩小
s.reserve(50);
cout << s.size() << endl;
cout << s.capacity() << endl;
}
size/length/capacity
⚽️size - 返回字符串中有效字符的长度
⚽️length - 返回字符串中有效字符的长度
⚽️capacity - 返回当前为该字符串分配的存储空间的大小
int main()
{
string s("teststring");
cout << s.size() << endl; //有效字符长度
cout << s.length() << endl; //有效字符长度
cout << s.capacity() << endl; //所开空间大小
return 0;
}
empty
⚽️ 检测字符串是否为空串,是则返回true,否则返回false
clear(重点)
⚽️ 清空字符串的内容,它变成一个空字符串(长度为0个字符)。
总结一下:
- size()与length()方法底层实现原理完全相同,实现size()的目的是与其它容器的接口保持一致,平时用size()会比较多。
- clear()只是将字符串中的有效字符清空,并不改变底层空间的大小。
- resize在改变元素的个数时,若将元素的个数增多,可能会改变底层容量的大小,若元素个数减少,底层空间大小不改变(一般不会缩空间)。
- reserve为string预留空间,不改变有效元素个数,若reserve的参数小于string的底层空间大小时,reserve不会改变容量大小。
3️⃣string类对象的修改
operator +=
⚽️通过在当前值的末尾添加额外的字符来扩展字符串:
int main()
{
string s1 = "!!!!";
string s("pushback");
s += " ";
s += "追加";
s += s1;
cout << s << endl;
return 0;
}
运行测试:
appened
⚽️通过在当前值的末尾添加额外的字符来扩展字符串。
int main()
{
string s1("hello");
cout << s1 << endl;
s1.append("world");
cout << s1 << endl;
string s2("!!!!!!");
s1.append(s2.begin(), s2.end());
cout << s1 << endl;
return 0;
}
运行测试:
push_back
⚽️将字符c追加到字符串的末尾,使其长度增加1。
void TestPushBack()
{
string s("hell");
s.push_back('o');
cout << s << endl;
}
c_str
⚽️ 返回一个指向数组的指针,该数组包含一个以空结束的字符序列(即C-string),表示string对象的当前值。
void TestC_str()
{
string s("frangrance jeak");
cout << s << endl; //调用 operator<<(cout,s1)
cout << s.c_str() << endl; //调用 operator<<(cout,const char*)
}
find
⚽️从字符串pos位置开始往后找字符c,返回该字符在字符串中的位置。
⁉️:如和写一个程序取出网址中的协议名和域名。
//取出url中的域名
string GetDomain(const string& url)
{
size_t pos = url.find("://");
if (pos != string::npos)
{
size_t start = pos + 3;
size_t end = url.find('/', start);
if (end != string::npos)
return url.substr(start, end - start);
else
return string();
}
else
return string();
}
//取出url中的协议
string GetProtocol(const string& url)
{
size_t pos = url.find('://');
if (pos != string::npos)
return url.substr(0, pos - 0);
else
return string();
}
int main()
{
string url1 = "https://cplusplus.com/reference/string/string/?kw=string";
string url2 = "https://blog.csdn.net/";
cout << GetDomain(url1) << endl;
cout << GetDomain(url2) << endl;
cout << GetProtocol(url1) << endl;
cout << GetProtocol(url2) << endl;
return 0;
}
rfind
⚽️ 从字符串pos位置开始往前找字符c,返回该字符在字符串中的位置。
⁉️:取出文件名的后缀
//要求取出文件名的后缀
int main()
{
string filename = "test.txt.zip";
size_t pos = filename.rfind('.');
if (pos != string::npos)
{
string suff = filename.substr(pos);
cout << suff << endl;
}
return 0;
}
总结一下:
1、在string尾部追加字符时,push_back / append / += 三种的实现方式基本没有什么区别,一般情况下使用string类的+=比较多,+=既可以连接单个字符,也可以连接字符串。
2、操作string时,若能够预测到大约需要多少空间可以通过reserve提前开好空间,避免频繁扩容而带来的损耗。
4️⃣非string类成员函数
5️⃣string类对象的遍历
函数名称 | 功能 |
---|---|
operator[] | 返回特定位置的字符,const string类对象调用 |
begin+end | begin获取一个字符串的迭代器 + end获取字符串最后一个位置的下一个位置的迭代器 |
rbegin+rend | begin获取一个字符串的迭代器 + end获取字符串最后一个位置的下一个位置的迭代器 |
🔵遍历方式1:for + operator[]
int main()
{
string s("ejfkaj afkjkajf");
for (size_t i = 0;i < s.size();++i)
{
cout << s[i] << " ";
}
cout << endl;
return 0;
}
🔵遍历方式2:迭代器
🚀[begin(),end()) end()返回的不是最后一个数据位置的迭代器,返回是最后一个位置的下一个位置。
需要注意的是,c++中迭代器一般都是给的[)左闭右开区间。
// 正向迭代器
int main()
{
string s("fhajh ahfjh");
string::iterator it = s.begin();
while (it != s.end())
{
cout << *it << " ";
++it;
}
cout << endl;
return 0;
}
//反向迭代器
int main()
{
string s("123fhajh");
string::reverse_iterator rit = s.rbegin();
while (rit != s.rend())
{
cout << *rit << " ";
++rit;
}
cout << endl;
return 0;
}
❗️string,vector等支持[]遍历,但是list,map等容器不支持[]
🔵遍历方式3:范围for
🚀 c++11提供范围for,写起来更方便。一次取容器中的数据赋值给e,自动判断结束。
int main()
{
string s("ejfkaj afjak");
for (auto& e : s)
{
cout << e << " ";
}
cout << endl;
for (auto e : s)
{
cout << e << " ";
}
cout << endl;
return 0;
}