目录
string类简介
string类的常用接口说明
string类对象的常见构造
string类对象的访问及遍历操作
operator[ ]
begin + end
rbegin + rend
string类简介
- string是表示字符串的字符串类
- 该类的接口与常规容器的接口基本相同,再添加了一些专门用来操作string的常规操作。
- string在底层实际是:basic_string模板类的别名,typedef basic_string string;
- 不能操作多字节或者变长字符的序列。
- 在使用string类时,必须包含#include<string>以及using namespace std;
string类的常用接口说明
string类对象的常见构造
C++98定义了多个构造函数,但是我们最常用的只有一下三种:
(constructor)函数名称 功能说明 string() (重点) 构造空的string类对象,即空字符串 string(const char* s) (重点) 用C-string来构造string类对象 string(size_t n, char c) string类对象中包含n个字符c string(const string&s) (重点) 拷贝构造函数
具体实现方法如下图所示:
#include<iostream>
#include<string>using namespace std;void test_string1()
{// 常用string s1; // 构造空的string类对象s1string s2("hello world"); // 用C格式字符串构造string类对象s2string s3(s2); // 拷贝构造s3cin >> s1;cout << s1 << endl;cout << s2 << endl;cout << s3 << endl;
}
其次,string类依然遵守隐式类型转换原则,在引用对象时,需要加上const修饰:
void push_back(const string& s)
{//.......
}void test_string2()
{string s1 = "hello world";// 隐式类型转换//这里s2引用的是临时变量,临时变量具有常性,需要用const修饰const string& s2 = "hello world";构造//string s3("hello world");//push_back(s1);//以后尾插不用先构造再尾插,直接尾插就可以push_back("hello world");
}
s1这样写也是可以的,C++98为我们写了赋值运算符重载,可以直接使用。
string类对象的访问及遍历操作
函数名称 功能说明 operator[ ](重 点) 返回pos位置的字符,const string类对象调用 begin + end begin获取一个字符的迭代器 + end获取最后一个字符下一个位置的迭代器 rbegin + rend begin获取一个字符的迭代器 + end获取最后一个字符下一个位置的迭代器 范围for C++11支持更简洁的范围for的新遍历方式
operator[ ]
string类中operator[ ] 成员函数类似下面代码,引用返回减少一次拷贝构造,也能通过别名修改返回的对象,assert保证了如果传进去的 i 超过了size直接断言报错。
class string
{
public:// 引用返回// 1、减少拷贝// 2、修改返回对象char& operator[](size_t i){assert(i < _size);return _str[i];}
private:char* _str;size_t _size;size_t _capacity;
};
注意:string的类成员对象,如果要统计string变量的大小,要计算类成员变量的内存大小,按照内存对齐原则(32位系统对齐系数是4)即一个string变量大小是12(如图所示的类成员变量总计)而不是算字符串中字符个数,字符的个数与string变量本身内存大小无关。
void test_string3()
{string s1("hello world");s1[0] = 'x'; //'h'修改为'x'cout << s1.size() << endl;//cout << s1.length() << endl;//输出11 不包含\0//lenth和size等价,但是为了后续其他数据计算方便,统一写sizefor (size_t i = 0; i < s1.size(); i++){s1[i]++; //字符串中每个元素+1(ASCII)}// 越界检查 s1[20]; //assert(i < _size);for (size_t i = 0; i < s1.size(); i++){//cout << s1.operator[](i) << " "; 显示调用cout << s1[i] << " "; //遍历字符串打印每个字符}cout << endl;const string s2("hello world");// 不能修改//s2[0] = 'x';
}
如果string被const修饰,还可以将第一个元素修改为'x'吗?如果不能,为什么呢?看下图:
s1,s2优先匹配相似度高的函数,即遵循模板参数的匹配原则。
begin + end
begin获取一个字符的迭代器 + end获取最后一个字符下一个位置的迭代器,begin和end可以实现字符串的遍历。
void test_string4()
{string s1("hello world");// 遍历方式1:下标+[]for (size_t i = 0; i < s1.size(); i++){cout << s1[i] << " ";}cout << endl;//遍历方式2: 迭代器//auto it1 = s1.begin(); //这样写前提是你知道他是什么类型string::iterator it1 = s1.begin();while (it1 != s1.end()){*it1 += 3; cout << *it1 << " ";++it1; //控制it1移动}cout << endl;//遍历方式3: 范围for// 底层角度,他就是迭代器for (auto& e : s1){e++; //想要修改加上引用cout << e << " ";}cout << endl;
}
这样就有三种方式可以遍历数组, 我们可以将迭代器想象成指针,如下图所示:
从begin()开始,到end()就停止遍历,可以修改字符串里的值。
void test_string5()
{const string s1("hello world");//string::const_iterator it1 = s1.begin();auto it1 = s1.begin();while (it1 != s1.end()){// 不能修改//*it1 += 3;cout << *it1 << " ";++it1;}
}
那么加上const修饰应该怎么实现权限的平移呢?另外const_iterator为什么中间要加短下划线?如下图所示:
注意:在编写程序时,const_iterator中间要写下划线
rbegin + rend
rbegin记录字符串尾元素,rend记录字符串头元素,两者为反向迭代器,共同使用可以实现数组的逆序访问。
void test_string6()
{const string s1("hello world");//string::const_reverse_iterator cit1 = s1.rbegin();auto cit1 = s1.rbegin();while (cit1 != s1.rend()){// 不能修改//*cit1 += 3;cout << *cit1 << " ";++cit1;}cout << endl;string s2("hello world");string::reverse_iterator it2 = s2.rbegin();//auto it2 = s2.rbegin();while (it2 != s2.rend()){*it2 += 3;cout << *it2 << " ";++it2;}cout << endl;
}
在图中所示:此处依旧遵循模板参数的匹配原则
此处rbegin从右向左遍历至rend,++往左移动, 编译器实现逻辑如下图所示: