温馨提示:如有问题可在此C++网址查询
1.为什么学习string?
string相对C语言字符串有哪些优势?
C语言中,字符串是以'\0'结尾的一些字符的集合,为了操作方便,C标准库中提供了一些str系列的库函数, 但是这些库函数与字符串是分离开的,不太符合OOP的思想,而且底层空间需要用户自己管理,稍不留神可能还会越界访问。OOP:面向对象编程。
2.标准库里的string类
2.1. string类
1. STL的string类是C++标准库中用于处理单字节字符串的一种数据类型。
2. 该类的接口与常规容器的接口基本相同,再添加了一些专门用来操作string的常规操作。
3. string在底层实际是:basic_string模板类的别名,typedef basic_string string;
4. 不能操作多字节(如Unicode字符)或者变长字符的序列。(STL string类内部使用了char类型来表示每个字符,而char类型只能表示8位的字符。对于多字节字符,例如中文字符,一个字符可能占用多个字节,因此无法直接使用STL string类来正确处理这些字符。)
在使用string类时,必须包含#include<string>头文件以及using namespace std;
2.2.string类常见接口介绍
1.string类对象的常见构造
构造函数名称 | 功能说明 |
string()(重点) | 构造空的string类对象 |
string(const char* s)(重点) | 用C-string来构造string类对象 |
string(size_t n,char c) | string类对象中包含n个字符c |
string(const string& str)(重点) | 拷贝构造 |
string(const string& str , size_t pos , size_t len=npos) | 选取拷贝构造 |
npos:maximum value for size_t(它表示字符串中无效的或未找到的位置。具体来说,它是一个特殊的std::string::size_type
类型的常量,其值被定义为-1。它通常用于表示字符串操作中的失败或错误状态,或者用于指示未找到某个特定子串或字符。)
void test_string1()
{
string s1;//*构造
string s2("hello");//*构造
string s3("hello", 2);
string s4(s2);//*拷贝构造
string s5(s2,1, 2);
string s6(s2, 1);
string s7(10,'a');
s1 = s7;//*赋值
cout << s1 << endl;
cout << s2 << endl;
cout << s3 << endl;
cout << s4 << endl;
cout << s5 << endl;
cout << s6<< endl;
cout << s7 << endl;
}
2.string类对象的容量操作
函数名称 | 功能说明 |
size(重点) | 返回字符串有效字符长度 |
length | 返回字符串有效字符长度 |
capacity | 返回空间总大小 |
empty(重点) | 检测字符串释放为空串,是返回true,否则返回false |
clear(重点) | 清空有效字符 |
reserve(重点) | 为字符串预留空间 |
resize(重点) | 将有效字符的字数改为n个,多出的空间用字符C填充 |
#include<iostream>
#include<string>
using namespace std;
// size/clear/resize
void Teststring1()
{
// 注意:string类对象支持直接用cin和cout进行输入和输出
string s("hello, bit!!!");
cout << s.size() << endl;
cout << s.length() << endl;
cout << s.capacity() << endl;
cout << s << endl;
// 将s中的字符串清空,注意清空时只是将size清0,不改变底层空间的大小
s.clear();
cout << s.size() << endl;
cout << s.capacity() << endl;
// 将s中有效字符个数增加到10个,多出位置用'a'进行填充
// “aaaaaaaaaa”
s.resize(10, 'a');
cout << s.size() << endl;
cout << s.capacity() << endl;
// 将s中有效字符个数增加到15个,多出位置用缺省值'\0'进行填充
// "aaaaaaaaaa\0\0\0\0\0"
// 注意此时s中有效字符个数已经增加到15个
s.resize(15);
cout << s.size() << endl;
cout << s.capacity() << endl;
cout << s << endl;
//将S中有效字符个数缩小到5个
s.resize(5);
cout << s.size() << endl;
cout << s.capacity() << endl;
cout<< s << endl;
}
void Teststring2()
{
string s;
s.reserve(100);
cout << s.size() << endl;
cout << s.capacity() << endl;
// 测试reserve参数小于string的底层空间大小时,是否会将空间缩小 //结果没有将空间缩小
s.reserve(50);
cout << s.size() << endl;
cout << s.capacity() << endl;
}
// 利用reserve提高插入数据的效率,避免增容带来的开销
//================================================================================
void TestPushBack()
{
string s;
size_t sz = s.capacity();
cout << "making s grow:"<<sz<<endl;
for (int i = 0; i < 100; ++i)
{
s.push_back('c');
if (sz != s.capacity())
{
sz = s.capacity();
cout << "capacity changed: " << sz << endl;
}
}
}
void TestPushBackReserve()
{
string s;
s.reserve(100);
size_t sz = s.capacity();
cout << "making s grow:"<<sz<<endl;
for (int i = 0; i < 200; ++i)
{
s.push_back('c');
if (sz != s.capacity())
{
sz = s.capacity();
cout << "capacity changed: " << sz << endl;
}
}
}
1. size()函数返回的是字符串对象当前包含的字符数目,也就是字符的实际长度。(size()与length()方法底层实现原理完全相同,引入size()的原因是为了与其他容器的接口保持一 致,一般情况下基本都是用size()。与其他容器保持一致)
2.capacity()函数返回的是字符对象当前分配的内存容量,也就是字符串可以容纳的最大字符数。
扩充:字符串在自动扩充时第一次一般是(n+m)(原有内存+增加后空间,例:15+16=31),之后一般是1.5倍增加。例如:TestPushBack()。也有可能是直接1.5倍到最后。例如TestPushBackReserve()。一般会多开一个给\0。
3. clear()只是将string中有效字符清空,不改变底层空间大小。
4.resize()函数用于改变字符串对象的大小。它接受一个参数,指定所需的新大小。如果新大小小于当前大小,字符串将被截断,缩短为指定大小;如果新大小大于当前大小,字符串将被扩展,并在末尾填充默认值0。
resize(size_t n) 与 resize(size_t n, char c)都是将字符串中有效字符个数改变到n个,不同的是当字符个数增多时:resize(n)用默认值0来填充多出的元素空间,resize(size_t n, char c)用字符c来填充多出的 元素空间。
注意:resize在改变元素个数时,如果是将元素个数增多,可能会改变底层容量的大 小,如果是将元素个数减少,底层空间总大小不变。
5.reserve()函数用于预留字符串对象的内存空间,而不涉及字符串的大小。它接受一个参数,指定预留空间的大小。如果预留空间大于当前容量,字符串的容量将增加以容纳指定的大小;如果预留空间小于或等于当前容量,不会执行任何操作。reserve()
函数主要用于避免频繁的内存重新分配操作,以提高性能。reserve(size_t res_arg=0):为string预留空间,不改变有效元素个数,当reserve的参数小于 string的底层空间总大小时,reserver不会改变容量大小。
===============================手动分割===================================
3.string类对象的访问及遍历操作
函数名称 | 功能说明 |
operator[](重点) | 返回pos位置的字符,const string 类对象调用 |
begin | begin返回容器的迭代器,指向容器的第一个元素 |
end | end函数返回容器的迭代器,指向容器中的最后一个元素的下一个位置。返回的迭代器实际上是一个越界位置 |
rebegin | rebegin返回逆向迭代器,指向容器的最后一个元素 |
rend | rend函数返回容器的逆向迭代器,指向容器中的第一个元素的前一个位置。 |
for范围 | C++11支持更简洁的for的新遍历方式 |
1.访问:直接使用[]进行访问
void Teststring6()
{
string s1("hello");
const string s2("Hello");
cout << s1 << s2 << endl;
cout << s1[0] << s2[0] << endl;
s1[0] = 'H';
cout << s1 << endl;
}
注意:s2是const,只能读不能写
2.遍历的三种方式:
void Teststring7()
{
string s("hello");
//3种方式(既可以遍历也可以改写)
//1.for+[]
for (size_t i = 0; i < s.size(); i++)
cout << s[i] << endl;
//2.迭代器
//正向
string::iterator it = s.begin();
while (it != s.end())
{
cout << *it << endl;
++it;
}
//逆向
string::reverse_iterator rit = s.rbegin();
while (rit != s.rend())
{
cout << *rit << endl;
++rit;
}
//3.范围for
for (auto ch : s)
{
cout << ch << endl;
}
}
4.string类对象的修改操作
函数名称 | 功能说明 |
push_back | 在字符串后面插字符c |
append | 在字符传后追加一个字符串 |
operator+=(重点) | 在字符串后追加字符串str |
c_str(重点) | 返回C格式字符串 |
find+npos(重点) | 从字符串pos位置开始往后找字符c,返回该字符在字符串中的位置 |
rfind | 从字符串pos位置开始往前找字符c,返回该字符在字符串中的位置 |
substr | 在atr中从pos位置开始,截取n个字符,然后将其返回 |
erase | 删除起止位置之间的内容 |
void Teststring8()
{
string str;
str.push_back(' ');//插入一个空格
str.append("hello");//插入一个字符“hello”
str += 'b';
str += "it";
cout << str << endl;
cout << str.c_str()<<endl;//以C语言的方式打印字符串
//获取file的后缀
string file("string.cpp");
size_t pos = file.rfind('.');
string suffix(file.substr(pos, file.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;
}
常见的插入:+=。+=相对比较简单,且+=适用性更广一些。
#include <iostream>
#include <string>
int main() {
std::string str = "Hello, World!";
const char* cstr = str.c_str();
std::cout << cstr << std::endl; // 输出:Hello, World!
return 0;
}
c_str()
的作用是将 std::string
对象中的字符串内容以 C 风格的字符串(以空字符 '\0' 结尾的字符数组)的形式返回。返回的字符指针指向的是 std::string
对象内部的字符数组的首地址。作用:1.与C语言函数进行交互。2.获取字符串的指针。
5.string类非成员函数
函数 | 功能说明 |
operator+ | 尽量少用,因为传值返回,导致深拷贝效率低 |
operator>>(重点) | 输入运算符重载 |
operator<<(重点) | 输出运算符重载 |
getline(重点) | 获取一行字符串 |
relational operators(重点) | 大小比较 |
到这里就接近尾声了,感谢您能阅读完整篇文章的(说实话挺长的),希望您能从中学到string的知识,并对您的学习产生帮助。好,那这次的文章就到此结束了,如有问题和不懂的欢迎评论和私信我。
好,我就是头发尚存的猿小二,猿小二就是我,即便是平凡,日子也成了诗。