目录
sring接口解析
1.string简介
2.默认成员函数
2.1构造函数
2.2析构函数
2.3赋值重载
3.迭代器
3.1初识迭代器
3.2迭代器的使用
3.3特殊迭代器
3.4范围for
4.大小接口
4.1字符长度相关接口
4.2空间大小相关接口
5.其他常用接口
5.1operator[ ]
5.2增
5.3查
5.4导出
sring接口解析
1.string简介
在C语言中字符串底层实际是以'\0'结尾的字符数组,而这样操作方式并不是很方便,因此C++中将字符串封装成了独立的sring类,下面就来详细了解下string类的使用。
以下内容均参考https://legacy.cplusplus.com/
2.默认成员函数
2.1构造函数
在C++11标准中,编译器提供的构造函数如下:
(1) 默认构造:创建空字符串,并将所有成员变量初始化。下面进行代码演示,并顺便调试观察string的成员变量:
#include<iostream>
#include<string>using namespace std;//初始化
void Stringtest01()
{string s1;cout << s1 << endl;
}
调试结果如下:
可以看到string类中除了提供底层的字符数组,并且提供了大小(size),以及空间大小(capacity)成员,后面的两个成员变量主要与其他功能有关。下面来看看其他的构造函数
(2)拷贝构造:利用其他已初始化对象来初始化对象。
(3)从pos(下标)开始往后len长度的字符串来初始化对象,但这里可以看到len默认给了缺省值npos,从网站中可以看到npos的值是-1
但其实npos代表的是size_t类型的最大值,至于给-1的原因是size_t类型是unsigned类型,其最大值的二进制码全为1,而-1的补码就是全为1,因此就是最大值。
(4)利用C中的字符数组(包括常量字符数组)来初始化对象。
(5)取字符数组中前n个字符来初始化对象。
(6)初始化成n个c字符。
下面进行代码演示:
#include<iostream>
#include<string>using namespace std;//初始化
void Stringtest01()
{//(1)string s1;cout << s1 << endl;//(4)string s2("Hello World");cout << s2 << endl;//(5)string s3("Hello World", 2);cout << s3 << endl;//(2)string s4(s2);cout << s4 << endl;//(3)string s5_1(s2, 1);cout << s5_1 << endl; string s5_2(s2, 1, 6);cout << s5_2 << endl;string s6(5, 'a');cout << s6 << endl;
}int main()
{Stringtest01();return 0;
}
运行结果如下:
2.2析构函数
主要用于释放对象中所申请的资源。
2.3赋值重载
赋值重载主要是为了完成给对象赋值操作:
(1)已初始化对象进行赋值。
(2)C字符串进行赋值。
(3)字符进行赋值
下面进行代码示例:
//赋值重载
void Stringtest02()
{string s1("abcdef");cout << s1 << endl;string s2;s2 = s1;cout << s2 << endl;string s3;s3 = "gh";cout << s3 << endl;string s4;s4 = 'i';cout << s4 << endl;
}int main()
{//Stringtest01();Stringtest02();return 0;
}
运行结果如下:
3.迭代器
3.1初识迭代器
在C语言中对于字符数组的遍历,我们可以直接利用下标或者指针进行遍历,而STL中的容器成员变量可能会很复杂,或者不同容器的遍历逻辑不同,这时C++中引入了迭代器,来进行遍历。
3.2迭代器的使用
迭代器是每个STL容器中的内置类,对于string的迭代器使用如下:
//迭代器
void Stringtest03()
{string s1("1234567");//迭代器string::iterator it1 = s1.begin();while (it1 != s1.end()){cout << (*it1) << ' ';it1++;}cout << endl;
}int main()
{//Stringtest01();//Stringtest02();Stringtest03();return 0;
}
运行结果如下:
下面通过此代码来了解迭代器,首先来看看begin和end接口。
先看其返回可以知道begin是返回对象开始位置的迭代器指针,end则是最后元素的下一个位置的迭代器指针,可以看出迭代器是一种类指针用法。以string为例,begin可类比于返回字符数组的首元素指针,end则是返回'\0'位置的指针。以此从首元素地址遍历到最后元素地址。
begin和end接口为了区分const类型字符串,还重载了const类型接口,这里的详细使用在const迭代器位置讲。
其次,因为是类指针操作,所以对于非const对象,是能进行修改操作的:
//迭代器
void Stringtest03()
{string s1("1234567");//迭代器string::iterator it1 = s1.begin();cout << s1 << endl;while (it1 != s1.end()){--(*it1);it1++;}cout << s1 << endl;
}int main()
{//Stringtest01();//Stringtest02();Stringtest03();return 0;
}
运行结果如下
但要注意这里的解引用(*)迭代器指针运算符是重载的,仅对字符进行修改,其他成员变量不变。
3.3特殊迭代器
除了常用的普通迭代器,还有之前提到的const对象迭代器,以及逆序迭代器。
const迭代器主要为了进行const对象的遍历,string中也给出了对应的cbegin和cend接口(C++11标准):
而C++11之前则是使用的则是begin和end,const对象在迭代时便会自动调用const版本接口,而后的cbegin和cend是为了进行区分。
const迭代器类似于const char*的使用,不能对解引用内容进行修改,但可以修改指针变量的值。定义迭代器指针时使用的是const_iterator。
对于逆序迭代器(reverse_iterator)使用的则是rbegin与rend接口:
rbegin返回是最后一个元素的迭代器指针(不是'\0'),而rend返回的则是第一个元素之前元素的迭代器指针。
代码示例如下:
//迭代器
void Stringtest03()
{string s1("1234567");//迭代器string::iterator it1 = s1.begin();cout << s1 << endl;while (it1 != s1.end()){--(*it1);it1++;}cout << s1 << endl;//const迭代器const string s2("abcdef");string::const_iterator it2 = s2.begin();while (it2 != s2.end()){cout << *it2 << ' ';++it2;}cout << endl;//reverse迭代器string s3("ABCDEF");string::reverse_iterator rit3 = s3.rbegin();while (rit3 != s3.rend()){cout << *rit3 << ' ';++rit3;}cout << endl;
}int main()
{//Stringtest01();//Stringtest02();Stringtest03();return 0;
}
运行结果如下:
除此之外reverse迭代器也有const版本,可以用C++11提出的crbegin和crend接口,也可用rbegin和rend的const重载版本。
3.4范围for
迭代器的使用语法相比python中的for循环相对繁琐,于是在C++11中引入了范围for来简化迭代器语法。
使用范围for前需要了解下auto关键字,auto实际是一种自动识别类型然后赋值的类型:
auto a = 'a';
这里的范围for语法如下:
for(auto e : s1)
{cout << e << ' ';
}
cout << endl;
这里的范围for实际只是简化迭代器语法,但底层还是迭代器。
4.大小接口
string的大小接口主要分为字符串长度相关接口和内部空间大小相关接口
4.1字符长度相关接口
string中长度相关接口主要有:字符串长度(size、length),最大字符串长度(max_size),再分配字符串长度(resize),清理字符(clear),判断是否为空串(empty),下面逐一了解
字符串长度(size、length)
对于size和length这两个接口返回的值是相同的,返回的都是真实的字符串长度(不包括'\0')。
清理字符串(clear)
清理字符串接口功能是将对象中的字符清空,使其变为空串,但内存空间不会进行改变。
字符串判空(empty)
字符串判空就是判断该对象是否为空字符,若为空字符串则返回true,非空则返回flase。
下面进行以上接口的代码演示:
//大小接口
void Stringtest04()
{string s1;cout << s1.size() << endl;cout << s1.length() << endl;s1 = "abcd";cout << s1.capacity() << endl;s1.clear();cout << s1.capacity() << endl;if (s1.empty()){cout << "string s1 is empty." << endl;}else{cout << "string s1 is not empty." << endl;}
}int main()
{//Stringtest01();//Stringtest02();//Stringtest03();Stringtest04();return 0;
}
这里的capacity接口是返回字符串字节大小(不包括'\0'),运行结果如下:
以上接口是常用的接口类型,剩下的接口不太常用,只进行说明,不进行代码演示。
最大字符长度(max_size)就是返回该对象成储存最大字符长度值,这里的最大值分配具体根据编译器来决定。
重置长度(resize)是将对象的长度重置成想要的长度大小,但不会小于真实字符串长度,具体能不能重置取决于编译器,因此不常用。
4.2空间大小相关接口
空间大小的接口包括:返回现有空间大小(capacity),预留空间(reserve),C++11中引入的缩容(shrink_to_fit),下面逐一介绍。
对于之前提到的capacity接口,其只返回不包括结尾'\0'空间字节的空间大小,但实际的字符串空间是capacity() + 1。
reserve接口常用于扩容操作,比如对象需要储存很多字符,则可提前开辟相应大小空间,避免之后的多次扩容,但reserve不建议进行缩容操作,不仅效率低,编译器还不一定会进行。
对于缩容(shrink_to_fit)接口,其功能是缩容到相对于size合适空间,但不一定会缩到size,具体大小根据编译器来定
5.其他常用接口
5.1operator[ ]
string中提供了像数组一样,通过[ ]和下标形式直接调用或修改字符串元素
但这里的下标也是不能越界的,越界访问会进行assert断言:
//其他接口
void Stringtest05()
{string s1("abcdef");cout << s1[s1.size() + 1] << endl;
}int main()
{//Stringtest01();//Stringtest02();//Stringtest03();//Stringtest04();Stringtest05();return 0;
}
运行结果如下:
5.2增
string进行增加操作常用的是operate以及push_back()
但其中operate+=比push_back更常用,因为+=与尾插功能相似,但+=支持添加字符串,更为便捷。
//其他接口
void Stringtest05()
{string s1("abcdef");cout << s1[s1.size()] << endl;string s2;string s3;s2 += "123456";s3.push_back('1');s3.push_back('2');cout << s2 << endl;cout << s3 << endl;
}int main()
{//Stringtest01();//Stringtest02();//Stringtest03();//Stringtest04();Stringtest05();return 0;
}
运行结果如下:
5.3查
string中查的常用接口提供了find和rfind,find能从字符串中指定的pos位置开始向后查找字符c或字符串s,若找到则返回该位置的下标,若未找到则返回npos。
rfind与find功能相似,只不过rfind是从最后一个字符位置开始查找。
代码演示:
//其他接口
void Stringtest05()
{string s1("abcdef");cout << s1[s1.size()] << endl;string s2;string s3;s2 += "123456";s3.push_back('1');s3.push_back('2');cout << s2 << endl;cout << s3 << endl;string s4 = "aaaaaa";cout << s4.find('a') << endl;cout << s4.rfind('a') << endl;cout << s4.find('b') << endl;
}int main()
{//Stringtest01();//Stringtest02();//Stringtest03();//Stringtest04();Stringtest05();return 0;
}
运行结果如下
5.4导出
导出接口中主要是为了提供string中特定串,常用的有提供C接口(c_str)和提供特点串(substr)。
c_str的提供主要是为了兼容C,因为C中的函数接口都是char*。
而substr可以将字符串中所需要的子串提取出来。
其中长度问题:在左闭右开区间[a, b)中b - a就是a到b的长度,比如字符串"abc"的len就是s.size() - 0。
下面以提取网址中的协议、域名、目录为例,进行代码演示:
//分离网址
vector<string> split_url(const string& url)
{vector<string> v;size_t i1 = url.find(':');if (i1 != string::npos){v.push_back(url.substr(0, i1));}size_t i2 = i1 + 3;size_t i3 = url.find('/', i2);if (i3 != string::npos){v.push_back(url.substr(i2, i3 - i2));v.push_back(url.substr(i3 + 1));}return v;
}void test()
{string s1 = "https://gitee.com/xiao-chen-is-studying-c";vector<string> spurl = split_url(s1);cout << spurl[0] << endl;cout << spurl[1] << endl;cout << spurl[2] << endl;
}int main()
{//Stringtest01();//Stringtest02();//Stringtest03();//Stringtest04();//Stringtest05();test();return 0;
}