目录
1.为什么学习string类?
C语言中,字符串是以'\0'结尾的一些字符的集合,为了操作方便,C标准库中提供了一些str系列的库函数,但是这些库函数与字符串是分离开的,不太符合面向对象的思想,而且底层空间需要用户自己管理,稍不留神可能还会越界访问。
2.string类中的常用接口
注意在使用string类前我们需要包含他的头文件<string>与c语言相比他没有后缀.h
string类中大部分接口我们都会了解:
2.1构造函数
string类的构造函数有多种方式,我们主要掌握三种
1.无参构造
string s1; //无参构造方式
我们通过监视窗口可以看到他构造了一个空的字符串
2.有参构造(c语言字符串方式构造)
string s2("hello world!"); //以c字符串的方式构造
我们同样发现他完成了构造并且size为12。
3.拷贝构造
string s3(s2); //拷贝构造
我们用s2来拷贝构造s1 ,s1同样被创建成功并且size为12。
2.2 string类容量接口函数
1.size
返回字符串的长度,不包括'\0'。
2.lenth
返回字符串的长度,不包含'\0'。
与size功能一样
3.capacity
返回数组容量
string s("hello world!");
cout <<"size:" << s.size() << endl;
cout << "lenth:" << s.length() << endl;
cout << "capacity:" << s.capacity() << endl;
由于这三个接口比较简单我们统一演示:
size和lenth的值都是12不包括'\0'。
capacity返回底层数组的容量。
4.empty
判断字符串是否为空
string s("hello world!");
string s1;
cout << s.empty()<<endl;
cout << s1.empty() << endl;
我们创建两个字符串对象s和s1,字符串为空empty返回1,否则返回0。
5.clear
清空字符串,不改变底层的容量
string s("hello world!");
cout <<"capacity:"<< s.capacity() << endl;
cout <<"size:"<< s.size() << endl;
cout << s.empty()<<endl;
s.clear();
cout << "capacity:" << s.capacity() << endl;
cout << "size:" << s.size() << endl;
cout << s.empty() << endl;
我们先创建一个字符串,然后使用clear清空来看看他的变化
我们发现他的size变为0,成了空字符串,但空间容量并没有改变。
6.reserve
改变字符串底层空间的容量
string s("hello world!");
cout <<"capacity:"<< s.capacity() << endl;
cout <<"size:"<< s.size() << endl;
s.reserve(1000);
cout << "capacity:" << s.capacity() << endl;
cout << "size:" << s.size() << endl;
s.reserve(10);
cout << "capacity:" << s.capacity() << endl;
cout << "size:" << s.size() << endl;
改变容量分为两种情况:增大和缩小,我们分别来看看编译器对他的处理。
我们可以看出,reserve对于增大空间会增大他的容量,不改变size大小,但为什么是1007不是我们设定的1000呢?因为增大空间是按照1.5倍大小每次扩增的,所以与我们设定的值不同。
reserve对于减小空间的请求不会做处理,因为我们想要缩小空间容量时,他的容量和size并没有改变。
对于reserve减小空间的请求不做处理很容易理解,因为编译器不确定我们后面是否还需要用这份空间,如果释放了,我们还要增加数据,那么就要再次申请,申请空间代价太大,所以不会减小空间
7.resize
改变字符串的size大小
改变字符串的size大小又要考虑他与原来的size大小,和原capacity大小关系。
string s("hello world!");
cout <<"capacity:"<< s.capacity() << endl;
cout <<"size:"<< s.size() << endl;
cout << endl;
s.resize(15);
cout << "capacity:" << s.capacity() << endl;
cout << "size:" << s.size() << endl;
cout << endl;
s.resize(20);
cout << "capacity:" << s.capacity() << endl;
cout << "size:" << s.size() << endl;
cout << endl;
s.resize(5);
cout << "capacity:" << s.capacity() << endl;
cout << "size:" << s.size() << endl;
运行后我们看到
我们发现 如果我们resize大小大于size,小于等于capacity大小那么不会扩容,会将size扩增到我们设定的size,后面的数据以‘\0’填充。
如果我们resize大小大于size,大于capacity大小那么就会进行对底层容量的扩容,会将size扩增到我们设定的size,后面的数据以‘\0’填充。
如果我么resize大小小于size,那么会将size减少到我们设定的size大小,后面的字符就会被截断,capacity不变。
2.3 string类对象元素访问接口
1.operator[ ]
以下标的方式随机访问string类对象的元素。
string s("hello world!");
for (size_t i = 0; i < s.size(); ++i)
{
cout << s[i];
}
cout << endl;
这个我们很容易理解就相当于数组的访问方式。
2.at访问
以下标的方式随机访问string类对象的元素。
string s("hello world!");
for (size_t i = 0; i < s.size(); ++i)
{
cout << s.at(i);
}
cout << endl;
at访问同样能够帮助我们访问元素,那么他与operator[ ]有什么区别呢?
他们处理越界的方式不同。
operator[ ]处理越界的方式时断言报错。
at访问处理越界的方式时抛异常。
3.front
访问string类对象的第一个元素
4.back
访问string类对象的最后一个元素
2.4string类对象修改接口
1.operator+=
operator+=用来拼接字符和字符串,它重载了三个类型,它可以拼接字符,可以拼接c语言的字符串,也可以拼接新的string类。
2.replace
string& replace (size_t pos, size_t len, const string& str);
作用:替换字符串,从某一位置pos开始,删除的数据大小len,以及要替换的str。
3.insert
在指定pos位置插入元素
由于string很少使用insert,我们简单认识几个就好
4.erase
删除指定位置元素
5.reverse
反转整个字符串
2.5string类特殊接口
1.c_str
将string类对象转换为c语言中的字符串
c_str转换出来的与string类对象不同只是一个字符指针。
2.find
从前往后查找指定元素返回元素所在位置的下表pos
我们发现s对象中又两个字符o,但是他返回的时第一个o的位置,因为find时查找第一个出现的字符。
3.rfind
从后往前查找指定元素返回元素所在位置的下表pos
同样rfind查找的也是第一个出现的元素位置
4.substr
从某一个string对象中截取字串
3.总结
我们初步认识了string类的各个接口,在平时做题我们熟悉掌握他的各个接口就会事半功倍。
我们之后在来自己实现string类