1、什么是string类
(1)字符串是表示字符序列的类,string是表示字符串的字符串类 (2)标准的字符串提供了对此类对象的支持,其接口类似于标准字符容器的接口与常规容器的接口基本相同,但添加了专门用于操作单字节字符字符串的设计特性,也就是专门用来操作string的常规操作 (3)string类是使用char作为它的字符类型 (4)string类是basic_string模版类的一个实例,它使用char来实例化basic_string模板类,并用char_traits和allocator作为basic_string的默认参数
代码语言:javascript复制basic_string<char> s1;
string s2;
//这两个是一样的,string就是basic_string的char类型特化
typedef basic_string<char, char_traits, allocator> string;//底层
(5)不能操作多字节或者变长字符的序列 (6)在使用时要包头文件以及展开命名空间
2、string类的常用接口讲解
(1)string类的常见构造
函数名称 | 功能说明 |
---|---|
string() | 构造空的字符串 |
string(const char* s) | 用C格式的字符串构造字符串 |
string(const string& s) | 拷贝构造函数 |
string(size_t n,char c) | 字符串中包含n个字符c |
void test()
{
string s1;
string s2("hello world");
string s3(s2);
string s4(5, 'a');
}
(2)string类的容量操作
函数名称 | 功能说明 |
---|---|
size | 返回字符串有效字符长度 |
empty | 检测字符串是否为空,是返回true,否返回false |
clear | 清空有效字符 |
reserve | 为字符串预留空间 |
resize | 将有效字符个数改为n个,多出的空间用字符c填充 |
capacity | 总空间大小 |
length | 返回字符串有效字符长度 |
void test2()
{
string s1("hello world");
cout << s1 << endl;
//测试size和length
cout << s1.size() << endl;
cout << s1.length() << endl;
//size和length底层实现原理完全相同,在刚刚创造出string的时候,对于字符串来说,叫length很合适,
//所以起名为length,但不久后STL产生了,为了与其他的模版比如list,vector等统一,
//所以加了size,保持接口一致性,一般都用size
//测empty
cout << s1.empty() << endl;
//测capacity
cout << s1.capacity() << endl;
//测resize
s1.resize(5, 'a');
cout << s1 << endl;
s1.resize(15, 'a');
cout << s1 << endl;
//resize(size_t n)与resize(size_t n,char c)都是将字符串中有效字符个数改到n个,
//不同的是当字符个数增多时,resize(size_t n)用0来填充多出的元素空间,
//resize(size_t n,char c)用c字符填充多出的元素空间
//resize改变元素个数时,如果个数增多,可能会改变底层容量的大小,如果减少则不变
//测reserve
s1.reserve(15);
cout << s1.capacity() << endl;
//为string预留空间,如果reserve的参数小于string的底层空间总大小时,reserve不会改变容量大小
//测clear
s1.clear();
cout << s1.capacity() << endl;
s1 = "little monster";// =在后边有讲解
cout << s1 << endl;
//clear只是将string中有效字符清空,不改变底层大小,可以再键入新内容
}
(3)string类对象的访问及遍历
函数名称 | 功能说明 |
---|---|
operator[ ] | 返回pos位置的字符,const string类调用 |
begin 和 end | begin获取一个字符的迭代器,end获取最后一个字符的后一个位置的迭代器 |
rbegin 和 rend | rbegin获取一个字符的迭代器,rend获取最后一个字符的后一个位置的迭代器 |
范围for | 更简洁的遍历 |
void test3()
{
string s1("hello world");
cout << s1[6] << endl;
//使用下标操作符[]可以直接找到对应位置的字符
//string::iterator it = s1.begin();
auto it = s1.begin();//这里体现出了auto的优越性,上面一长串的类型可以直接用auto推导代替
for (it; it != s1.end(); it )
{
cout << *it << " ";
}
cout << endl;
//begin记录第一个有效字符的位置,end记录最后一个有效字符的后一个位置
//从头到尾的打印, 是一个重载运算符,在其他类中,包括链表类也可以直接找到下一个成员
for (auto it : s1)
{
cout << it << " ";
}
cout << endl;
//使用范围for进行遍历,十分方便
auto rit = s1.rbegin();
for (rit; rit != s1.rend(); rit )
{
cout << *rit << " ";
}
//rbegin和rend是一对与begin和end相反的函数,rbegin记录的是最后一个有效字符的位置,rend记录的是第一个有效字符的前一个位置,通过 实现逆向输出
}
(4)string类对象的修改
函数名称 | 功能说明 |
---|---|
operator = | 在字符串后追加字符串 |
c_str | 返回C格式字符串 |
find | 从字符串pos位置开始往后找字符c,返回该字符在字符串中的位置 |
push_back | 在字符串后尾插字符 |
append | 在字符串后追加一个字符串 |
rfind | 从字符串pos位置开始往前找字符c,返回该字符在字符串中的位置 |
substr | 在str中从pos位置开始,截取n个字符,然后将其返回 |
void test4()
{
string s1("hello world");
// =测试
s1 = "!!!!";
cout << s1 << endl;
//c_str测试
cout <<s1.c_str() << endl;
//c_str就是将c 的格式转化为c语言的格式,这样字符串就可以用C语言的方式来操作
//并且c_str返回的是指针,因为<<是重载运算符,所以才显示指向的内容
//find测试
cout << s1.find('w',2) << endl;
//pushback测试
s1.push_back('6');
cout << s1 << endl;
//append测试
s1.append("789");
cout << s1 << endl;
//rfind测试
cout << s1.rfind('l' , 6) << endl;
//substr测试
cout << s1.substr(0, 11) << endl;
//substr只会截取并返回,不改变s1的内容
}
在string尾部追加字符时,可以使用push_back , append , = ,push_back只能追加字符,append追加字符串,所以我们一般常用的是 =,既可以追加字符又可以追加字符串,并且使用起来书写简单,代码可读性高
对string进行操作时,如果可预见可以放多少字符,可以用reserve把空间预留好
这里的 find 和 rfind 与 begin rbegin 那一套一样,r都表示相反,注意这里find是从pos开始往后找到的第一个指定字符,rfind是从pos开始往前找到的第一个指定字符,然后返回该字符所在位置的下标
(5)string类非成员函数
函数名称 | 功能说明 |
---|---|
operator>> | 输入运算符重载 |
operator<< | 输出运算符重载 |
getline | 获取一行字符串 |
relational operators | 大小比较 |
operator | 少用,传值返回,深拷贝效率低 |
这部分内容比较简单,我设置了超链接,直接点进去看一下文档就可以了
(6)其他
string类还有很多其他的操作,不一一列举了,需要时直接打开cplusplus查找文档即可 string类
(7)vs和g 下string结构说明
前提:32位平台
vs下的string结构
string总共占28个字节,内部结构稍微复杂一点,有一个联合体,用来定义string中字符串的存储空间:当字符串长度小于16时,使用内部固定的字符数组存放,当字符串长度大于等于16时,从堆上开辟空间,这样保证了字符串在较小时不需要通过堆创建,提高了效率,占16字节
还有一个size_t字段保存字符串长度,占4字节,一个size_t字段保存从堆上开辟空间总的容量,占4字节
最后还有一个指针,4字节,共28字节
g 下string结构
在g 下,string通过写时拷贝实现,只占4个字节,内部只包含一个指针,指向一块堆空间,堆空间内部包含了空间总大小、字符串有效长度、引用计数
写时拷贝:在数据第一次写入到某个存储位置时,首先将原有内容拷贝出来,写到另一位置处,然后再将数据写入到存储设备中,该技术只拷贝在拷贝初始化开始之后修改过的数据 简单来说就是在用之前不开空间,在真正要修改和写入时才开辟空间,可以减少空间的浪费,它是在浅拷贝的基础上增加了引用计数的方式实现的
引用计数:用来记录资源使用者的个数,在构造时,将资源的计数给成1,每增加一个对象使用该资源,就给计数增加1,当某个对象被销毁时,先给该计数减1,然后再检查是否需要释放资源,如果计数为1,说明该对象是该资源的最后一个使用者,将该资源释放,否则因为其他对象还在使用该资源,该资源就不能释放
今日分享就到这里~