c++ string类详解

1,string定义:

Strings are objects that represent sequences of characters(string是表示字符序列的对象)string是一个类。string属于标准库,头文件<string>.

(注:string的有些方法比较冗杂,我这里会陈列所有方法,但只阐述常用的!!!)

2,npos:

string有一个静态成员变量:npos

3,string的构造函数:

string s1;

string s2("hello world");

string s3(s2, 6, 5);//从下标为6开始,取五个字符

string s4(s2, 6);//从下标为6开始,缺省值为size_t npos=-1;最大的整型,越界,到字符串完为止

string s5 (10, 'a');

cout << s5 << endl;//aaaaaaaaaa

string s6(s5.begin(), s5.end());

cout << s6 << endl;//aaaaaaaaaa

4,operator=

string s8 = s7;

s8 = "xxx";

s8 = 'x';

5,非成员函数

(1)operator<<

此函数非成员函数,原因:这个运算符是用来直接打印字符串的,(cout<<s1)运算符左右两边分别是ostream类型和string类型,所以这两个参量将作为这个运算符重载的第一第二参数,如果这个作为成员函数,那么第一个参数默认是*this(也就是string),那么与我们想要达到的参数顺组颠倒,所以它不能作为成员函数。

用法:cout << s1 << endl;

(2)operator>>

此函数非成员函数。

用法:string s1("wwwwww");

cin >> s1;

cout << s1 << endl;

(1)留提取后,原先的的内容会被覆盖。

(2)提取的时候以空格和换行符截止,如果想要得到一整行的内容,应该使用getline();

(3)getline (string)

此函数非成员函数。

(1)这个方法,字符串原先的的内容会被覆盖。

(2)第一个是遇到字符(delim)这个参数,才停止。第二个是遇到'\0'截止

用法:

(1)string s1;

getline(cin, s1,'#');

(2)string s1;

getline(cin, s1);

(4)swap (string)

非成员函数:

成员函数:

两者原理大致相同,

用法:string s1("xxx");

string s2("yyy");

swap(s1, s2);

(5)operator+ (string)

非成员函数:

用法:

string s1("hello");

string s2("world");

cout << s1 + s2 << endl;

cout << s1 + '#' << endl;

(6)relational operators (string)

非成员函数:

这里有各种各样的字符串的比较方法,这里是根据首元素字母的ascll码值进行比较的

用法:

string s1("hello");

string s2("world");

cout << (s1 < s2) << endl;//1

cout << (s1 == s2) << endl;//0

6,Element access

**(1)**operator[]

(1)[ ]可以直接通过下标访问字符数组中的值。

(2)这里提供了两种,一种是既可以读又可以改变内容的,第二种是只可以读取,不可以更改的

const string s1("hello world");

for (size_t i = 0;i < s1.size();i++) {

//读

cout << s1[i] << " ";

}(这里调用的第二个用函数)

以上情况就是因为,这是一个用const就是的引用,不可以修改,但是这里修改了,所以报错。

string s1("hello world");

for (size_t i = 0;i < s1.size();i++) {

cout << s1[i]++ << " ";

}(这里调用的第一个用函数)所以这里的值可以修改

(2)at()

at和[]相似,但失败后会抛异常

(3)back()

返回字符串最后一个字符的引用

(4)front()

返回字符串第一个字符的引用

7,迭代器相关的函数

(1)begin()

返回一个指向字符串第一个字符的迭代器。

(2)end()

返回一个指向字符串末尾后的字符的迭代器。

(3)rbegin()

返回指向字符串最后一个字符的反向迭代器

(4)rend()

返回一个反向迭代器,该迭代器指向字符串第一个字符前面的理论元素。

(5)cbegin()

返回一个指向字符串第一个字符的const_iterator迭代器,该迭代器是指向const内容的迭代器,这个迭代器本身可以改变指向的对象(除非它本身也是const修饰的),但是指向的的内容,即用const修饰的字符串,不能随意修改。

(6)cend()

返回一个指向字符串末尾后的字符的const_iterator迭代器。

(7)crbegin()

返回一个const_reverse_iterator,指向字符串的最后一个字符

(8)crend()

返回一个const_reverse_iterator,该迭代器指向字符串第一个字符前面的理论元素

(9)用法:

(1)string::iterator it = s1.begin();

while (it != s1.end()) {

cout << *it << " ";

++it;

}

cout << endl;//用来读

(2) it = s1.begin();

while (it != s1.end()) {

//写

*it = 'a';

++it;

}

cout <<s1<< endl;//用来写

(3)auto rit= s1.rbegin();

while (rit!=s1.rend())

{

cout << *rit << " ";

rit++;

}

cout << endl;//倒着遍历

(4)void func(const string& s) {

//引用传参

string::const_iterator it = s.begin();

while (it != s.end()) {

//读

cout << *it << " ";

++it;

}

cout << endl;

迭代器的优势:定义在类域,运用方式相似,屏蔽了底层细节

第三种遍历方式:

上述已经提供了两种遍历的方法了,第一种是【】遍历,第二种是迭代器。一下讲第三种范围for,它的底层也是迭代器。

for (auto ch : s1) {

//读

cout << ch << " ";

}

cout << endl;

for (auto& ch : s1) {

//写

cout << ch << " ";

}

cout << endl;

8,Capacity:

(1)size()和length()

string s1 = "hello world";

cout << s1.size() << endl;//从容器来看,具有通用性

cout << s1.length() << endl;

(2)clear()

s1.clear();//清除数据,但是没有释放空间

(3)max_size()

返回字符串可以达到的最大长度。这是字符串可以达到的最大潜在长度,但不能保证对象能够达到该长度,它无法分配内存在达到该长度之前。

(4)resize()

将字符串大小调整为n个字符的长度。如果n小于当前字符串长度,则将当前值缩短到前n个字符,删除第n个字符以外的字符。如果大于当前字符串长度,将字符串大小调整为n个字符的长度,并用'\0',或者字符char c补齐补齐。

用法:

string s1 = "hello world";

s1.resize(20,'$');

cout <<s1 << endl;

(5)capacity()

返回分配内存的大小。

string s;

size_t old = s.capacity();

cout << "初始" << s.capacity() << endl;//可以存的有效字符

for (size_t i = 0; i <100; i++)

{

s.push_back('x');

if (s.capacity() != old) {

cout << "扩容" << s.capacity() << endl;

old = s.capacity();

}

}

vs中:

(6)reserve()

该方法和resize相似,但是也有区别。reserve只是预留空间,不创建元素对象。resize既分配了空间,也创建了对象,可以通过下标访问。reserve会修改capacity大小,但不修改size大小;resize既修改capacity大小,也修改size大小。

价值:确定大概要多少空间,提前开好,减少扩容,提高效率

9,Modifiers:

(1)operator+=

用法:

string s;

string s1("world");

s += '#';

s += "hello";

s += s1;

cout << s << endl;

(2)push_back()

尾插法

用法:string s;

s.push_back('#');

(3)append()

在当前字符串的基础上进行拼接,

string s;

s.append("hello");

s.append("world",0,3);

string s2("ld");

s.append(s2);

string s3("xxxxxx");

s.append(s3,1);

s.append(4,'#');

cout << s << endl;

(4)assign()

为字符串赋一个新值,替换其当前内容

用法:

string ss;

string ss1("hello world");

ss.assign(ss1);

cout << ss << endl;//hello world

string ss2("xxxxx");

ss2.assign(ss1);

cout << ss2 << endl;//hello world,覆盖

string ss3("xxxxx");

ss3.assign(ss1,5,10);

cout << ss3 << endl;// world

(5)insert()

string s("hello world");

s.insert(0, 1, 'x');

s.insert(s.begin(), 'x');

s.insert(0, "aaa", 1, 2);在下标为0的位置插入,字符串"aaa"中的一部分,这一部分从下标1开始,长度为两个字符。

cout << s << endl;

(6)erase()

s.erase(7, 2);//从小标7,开始删,删2个字符

s.erase(7);//从小标7,开始删,删完

(8)replace()

s.replace(5, 1, "%%%%%%");//将下标为5的一个字符改为这个字符串

注:insert / erase / replace 尽量不要用,都涉及移动数据,效率不高

10,String operations

(1)c_str()

返回指向数组的指针

(2)find()

用法:

string s1("test.c.ter.zip");

size_t i = s1.find('.',5);//4

size_t i = s1.find('.');//6

string s2("est");

string& s3 = s2;

int i=s1.find(s3);//1

cout << i << endl;

(3)substr()

string s1("test.c.ter.zip");

size_t i = s1.find('.');

string s2 = s1.substr(i);

cout << s2 << endl;//.c.ter.zip

(4)rfind()

从后往前找

string s1("test.c.ter.zip");

size_t j = s1.rfind('.');

s2 = s1.substr(j);//.zip

练习一:

分离协议,域名,资源名:

string s3("https://cplusplus.com/reference/string/string/swap-free/");

//协议

//域名

//资源名

size_t i1 = s3.find(':');

string sub1, sub2, sub3;

if (i1 != string::npos) {

sub1 = s3.substr(0, i1);

}

else {

cout << "没有找到i1的位置" << endl;

}

size_t i2 = s3.find('/',i1+3);

if (i1 != string::npos) {

sub2 = s3.substr(i1+3,i2-(i1+3));

}

else {

cout << "没有找到i2的位置" << endl;

}

sub3 = s3.substr(i2 + 1);

cout << sub1 << endl;

cout << sub2 << endl;

cout << sub3 << endl;

练习二:

大数相加:

string addstrings(string num1, string num2) {

int end1 = num1.size() - 1,

end2 = num2.size() - 1;

int next = 0;

string str;

while (end1 >= 0 || end2 >= 0)

{

int x1 = end1 >= 0 ? num1[end1] - '0' : 0;

int x2 = end2 >= 0 ? num2[end2] - '0' : 0;

int ret = x1 + x2 + next;

next = ret / 10;

ret = ret % 10;

str += ('0' + ret);

--end1;

--end2;

}if (next == 1) {

str +=' 1';

}

reverse(str.begin(), str.end());

return str;

}

相关推荐
王ASC24 分钟前
SpringMVC的URL组成,以及URI中对/斜杠的处理,解决IllegalStateException: Ambiguous mapping
java·mvc·springboot·web
是小崔啊26 分钟前
开源轮子 - Apache Common
java·开源·apache
大胆飞猪28 分钟前
C++9--前置++和后置++重载,const,日期类的实现(对前几篇知识点的应用)
c++
因我你好久不见31 分钟前
springboot java ffmpeg 视频压缩、提取视频帧图片、获取视频分辨率
java·spring boot·ffmpeg
1 9 J31 分钟前
数据结构 C/C++(实验五:图)
c语言·数据结构·c++·学习·算法
程序员shen16161132 分钟前
抖音短视频saas矩阵源码系统开发所需掌握的技术
java·前端·数据库·python·算法
夕泠爱吃糖33 分钟前
C++中如何实现序列化和反序列化?
服务器·数据库·c++
小老鼠不吃猫35 分钟前
力学笃行(二)Qt 示例程序运行
开发语言·qt
长潇若雪36 分钟前
《类和对象:基础原理全解析(上篇)》
开发语言·c++·经验分享·类和对象
Ling_suu1 小时前
SpringBoot3——Web开发
java·服务器·前端