【C++语言】想学STL,先细细拿捏string类,万字详解string类 (内附精美思维导图)


在这里插入图片描述


✨思维导图附上

看不清楚戳这里【String思维导图】
在这里插入图片描述
图片因为上传上限是5MB,所以不能直接传。图片无法更新但网页持续更新。

这一节我们将详细学习string字符串这个类,string类是早于STL标准库的,后面把string归属到STL,支持标准库中很多操作。触类旁通,通过学习string,也便于我们更好的学习STL。活不多说开始~


string 字符串

我们学习关于STL的学习通过【cplusplus旧网站】来学习。

1.string类简介

在这里插入图片描述
我就充当翻译官吧,不对的地方欢迎指正:

  • String 类是一个字符序列的对象。

  • 标准字符串类提供了类似于标准字节容器的接口,但增加了专门用于操作单字节字符字符串的特性。

  • 字符串类是基本字符串类模板(basic_string class template)的一个实例化,它使用char(即字节)作为其字符类型,并使用其默认的char_traits和分配器类型。typedef basic_string<char> string (如果大家对基本的string模板感兴趣,可以通过网站查看)

我自己对String的看法是:把c的char数组封装起来的感觉,然后提供很多方法,char形的顺序表哈哈(以空字符 \0 结尾的字符数组)。 当然这个看法肯定是浅显的。

2.string 的属性

string的属性,在库中可能是比较复杂的,它的字符存储位置不相同,比如小于某个数字的字节,就储存在buffer这个字符数组,大于有存在其他地方,这个比较杂。我这里就简单的把它理解为三个属性(这只是我的简单理解,并非库中真实)。

//基本属性:
char* _str;             //存储字符串的动态数组吧
size_t _size;			//记录字符长度(不包括\0)
size_t _capacity;		//记录数组的容量(最大空间)

3.成员常量

在这里插入图片描述
npos这个的值代表无符号整形的最大值:4294967295 。一般在成员函数之间使用,直接使用即可。

4.string 的默认成员函数

构造函数:

在这里插入图片描述
代码示例:

方式1:default

1 |	//default 默认无参构造:
2 |	string s1;	
3 |	//错误: string s1(); 
4 |	//原因:编译器无法识别这是在声明函数还是对象实例化,会报错!

方式2:copy

1 |	//拷贝构造:把s1拷贝给s2(深拷贝)
2 |	string s2(s1);	

方式3:substring

1 |	//拷贝s1,从下标为0的字符开始,拷贝10个长度的字符串
2 |	string s3(s1, 0, 10);

方式4:c-string

1 |	//拷贝str1字符数组,直到遇到\0:
2 | char str[10] = { 'h','e','l','l','o' };
3 | string s4(str1);	

方式5:sequence

1 |	//拷贝str1字符数组,前5个字符
2 |	string s5(str1, 5);	

方式6:fill

1 |	//拷贝5个单字符'*':
2 |	string s6(5, '*');

方式7:range

1 |	//迭代器拷贝 其实相当于指针拷贝 //begin()指向字符数组的第一个元素,end()指向字符数组最后一个元素的下一个位置\0
2 |	string s7(s6.begin(), s6.end());

方式8:pointer range

1 |	//字符数组 地址拷贝 str1 = "Hello World";
2 |	string s8(str1, str1 + sizeof(str1));

析构函数

在这里插入图片描述
析构函数释放char* _str;指针申请的堆上空间。

赋值运算符重载

在这里插入图片描述
代码示例:

方式1:string

//把s1赋值给s2
string s1;
string s2;				   
s2 = s1;                   // 赋值 string类的权限缩小到const string&

方式2:c-string

//赋值一个字符串“hello”
string s1;
s1 = "hello"			  // 赋值 char* 权限缩小到 const char*

方式3:character

//赋值一个字符*
string s1;
s1 = '*';				     // 赋值 char 权限缩小到 const char

构造赋值小疑问?

提问:
string s = "zhang san" ; 这个是什么?
答案:
构造函数+拷贝构造: 这里"zhang san" 是个c-string字符数组,要把它转换到string。就是"zhang san"会调用string的构造sting("zhang san"),然后会再拷贝构造。为什么不是赋值?因为这里是在构造一个对象并初始化,不是赋值。

string s = "zhang san" ; 我自己感觉这样写或者string s("zhang san");这两种写法对我来说最舒服。

5.容量操作

size、length

这两个成员函数是冗余的,两个的效果是一样的,我猜测设计size是为了让string更好的融入STL标准库。
在这里插入图片描述
代码示例:

函数: size()length();
作用:返回string对象的成员数量(_size大小);
返回值:size_t

string s("zhang san");
cout << s.size() << endl;     //9
cout << s.length() << endl;   //9

max_size

在这里插入图片描述
代码示例:

函数: max_size();
作用:string对象在当前编译器,操作系统系能开辟的最大空间;
返回值:size_t

string s;
cout << s.max_size() << endl;     //2147483647

不同编译器,操作系统结果可能不同,所以这个函数作用不大。

capacity

在这里插入图片描述
代码示例:

函数: capacity();
作用:当前对象的容量,返回_capacity的大小;
返回值:size_t
string s("zhang san");
cout << s << endl;				//zhang san
cout << s.size() << endl;		//9
cout << s.capacity() << endl;	//31

resize

在这里插入图片描述
在VS,Windows系统下, 开辟空间大于n的空间,具体要看平台,把size扩到或缩到n;
若n大于当前capacity,扩容,追加n-size个指定的字符(没指定也会把size扩到n,用\0沾满)
若n小于capacity,改变size到n,并size位置赋值一个\0;缩小过程,第二个参数没用。

代码示例:

string s("zhang san");
//扩大
s.resize(20,'*');
cout << s << endl;				//zhang san***********
cout << s.size() << endl;		//20
cout << s.capacity() << endl;	//31
//缩小
s.resize(5);
cout << s << endl;				//zhang
cout << s.size() << endl;		//5
cout << s.capacity() << endl;	//31

reserve

在这里插入图片描述
扩容: 传递一个无符号整形n ,改变对象的capacity到n不等(平台不同,扩容不同),开辟一个大小为n的空间,实际开辟n+1不等个。若当前容量大于n,可能会缩小,看平台。
总结一下 : 若你的容量小于n,它会扩容到至少n+1;若n小于当前容量,可能处理,可能不处理。

代码示例:

string s("zhang san");
//缩小
s.reserve(5);
cout << s << endl;				//zhang san
cout << s.size() << endl;		//9
cout << s.capacity() << endl;	//15
//扩大
s.reserve(100);
cout << s << endl;				//zhang san
cout << s.size() << endl;		//9
cout << s.capacity() << endl;	//111

clear

在这里插入图片描述
清除对象中的数据
代码示例:

string s("zhang san");
s.clear();
cout << s << endl;     //无数据

empty

在这里插入图片描述
代码示例:

函数: empty();
作用:判断当前对象是否为空,为空返回True,反之;
返回值:bool

string s("zhang san");
cout << s.empty() << endl;				//0

shrink_to_fit (C++11)

在这里插入图片描述
代码示例:

函数: shink_to_fit();
作用:把容量缩小到和size一样大小;
返回值:void

string s("zhang san");
s.reserve(1000);
cout << s.size() << endl;		//9
cout << s.capacity() << endl;	//1007
s.shrink_to_fit();
cout << s.size() << endl;		//9
cout << s.capacity() << endl;	//15

5.元素访问

orerator[]

在这里插入图片描述
真爽好吧!下标访问好。[]运算符重载,两个构成函数重载。

代码示例:

函数: orerator[](); 
作用:给它一个初始下标位置,它会返回对应值的引用;
返回值:char&

string s("zhang san");
cout << s[3] << endl ; //n

at

在这里插入图片描述
代码示例:

函数: at(); 
作用:给它一个初始下标位置,它会返回对应值的引用;
返回值:char&

string s("zhang san");
cout << s.at(3) << endl ; //n

back (C++11)

在这里插入图片描述
代码示例:

函数: back(); 
作用:返回最后一个元素的引用,注意确保对象不为空(会报错);
返回值:char&

string s("zhang san");
cout << s.back() << endl ; //n

front (C++11)

在这里插入图片描述

代码示例:

函数: front(); 
作用:返回第一个元素的引用,注意确保对象不为空(会报错);
返回值:char&

string s("zhang san");
cout << s.front() << endl ; //z

7.修改

append

在这里插入图片描述
追加操作,在对象最后追加内容
代码示例:

string s1("zhang san");
string s2("li si");
const char* str = "wang wu" ;

方式1:string

//在s1后插入s2
s1.append(s2);    //zhang sanli si

方式2:substring

//在s1后插入s2,从s2下标为2的位置开始的3个字符
s1.append(s2,2,3);    //zhang san si

方式3:c-string

//在s1后插入"li si"
s1.append("li si");    //zhang sanli si

方式4:buffer

//在s1后插入str数组中前三个字符
s1.append(str,3);    //zhang sanwan

方式5:fill

//在s1后插入5个#
s1.append(5,'#');    //zhang san#####

方式6:range

//在s1后插入s2,从开始到结尾的字符.[)
s1.append(s2.begin(),s2.end());    //zhang sanli si

方式7:pointer range

//在s1后插入数组范围开始到第三个位置.[)
s1.append(str,str+3);    //zhang sanwan

push_back

在这里插入图片描述
代码示例:

函数: push_back(); 
作用:在最后一个位置后插入一个字符;
返回值:void 

string s("zhang san");
s.push_back('c')
cout << s << endl ; //zhang sanc

operator +=

在这里插入图片描述
前面说了那么多,最爽的登场!
代码示例:

string s1("zhang san");
string s2("li si");
s1 += s2; 				 //zhang sanli si
s1 += "wang wu";         //zhang sanwang wu
s1 += '#'; 			     //zhang san#

assign

在这里插入图片描述
覆盖,assign不是追加,而是覆盖。这里我们已经熟悉了这些参数套路,我就不再次一一举例了。

代码示例:

string s1("zhang san");
string s2("li si");
s1.assign(s2);   //li si

insert

在这里插入图片描述
具体就是在给定pos位置前,插入一个string、substring、c-string、buffer、fill、character、range
代码示例:

string s("zhang san");
//在下标为3的元素,前面插入"#####"(c-string类型)
s.insert(3,"#####");      //zha#####ng san

erase

在这里插入图片描述
代码示例:
方法1:sequence

//删除s下标为6开始的2个的字符 这里给了缺省值哈
string s("zhang san");
s.erase(6,2)		//zhang n

方法2:character

//删除第一个元素。删除iterator处的元素,可以用指针.
string s("zhang san");
s.erase(s.begin())		//hang san

方法3:range

//删除所有元素。范围
string s("zhang san");
s.erase(s.begin(),s.end())		//

replace

在这里插入图片描述

swap

在这里插入图片描述
交换两个对象,注意是地址也是要交换的,不是只交换值
代码示例:

//交换s1和s2
string s1("zhang san");
string s2("li si");
s1.swap(s2);
cout<<s1<<endl;		//li si
cout<<s2<<endl;     //zhang san

pop_back (C++11)

在这里插入图片描述
删除最后一个位置的元素
代码示例:

//尾删
string s1("zhang san");
s1.pop_back();       //zhang sa 

8.字符串操作

c_str

在这里插入图片描述
代码示例:

//c_str 返回字符串首地址
string s1("zhang san");
cout<<s1.c_str<<endl;			//zhang san
cout<<*s1.c_str()<<endl;    	//z

data

在这里插入图片描述
这个也是多余的,和c_str一样的作用。

get_allocator

在这里插入图片描述

copy

在这里插入图片描述
str.copy(char* a, int len , int begin_pos ) 拷贝str对象中从begin_pos开始,长度为len的字符串,到a数组,copy不会自动改\0,所以需要自己修改。返回值为len。若a数组中原本有数据,会从头开始覆盖。
代码示例:

//拷贝s1中从0位置开始的5个字符到a数组,并返回拷贝长度
string s1("zhang san");
char a[100]={'n','h'};
int len = s1.copy(a,5,0);
a[len]='\0';
cout<<a<<endl;

find

在这里插入图片描述
在对象中查找是否有与它(str指针内容)相同的,第一个参数可以string,c-string,buffer,character.默认从首位置开始.找到返回找到字符串的的第一个字符的位置,没找到就返回npos。
代码示例:

//s1从首位置开始,找"zhang"字符串
string s1("zhang san");
s1.find("zhang",0);

rfind

在这里插入图片描述
与find相反,反着找,默认位置是最后,返回值相同.

find_first_of

在这里插入图片描述
给定第一个参数string,c-string,buffer,character,相当于把前面的字符串全部拆分成字符,str如果出现了第一个参数的任意字符,则返回首次出现的位置。默认从第一个数据开始找。往后找。

//s1从下标为0上位置开始,正向找's','q','w'三个字符,返回最后一次位置的下标
string s1("zhang san");
s1.find_first_of("sqw",0);    //6

find_last_of

在这里插入图片描述
注意:寻找方向是从pos位置,向前找
代码示例:

//s1从下标为0上位置开始,反向找's','q','w'三个字符,返回最后一次位置的下标
string s1("zhang san");
s1.find_last_of("sqw",0);    //npos;
s1.find_last_of("sqw",6);    //6

find_first_not_of

在这里插入图片描述
从第一个位置开始,向后查找,出现不存在在string中组成的字符时,就返回元素位置;若不存在则npos
代码示例:

//在s1中查找不是‘z’,'h','n','g','s'的元素
string s1("zhang san");
s1.find_first_not_of("zhngs",0);    //2  

rfind_last_not_of

在这里插入图片描述
从第一个位置开始,向后查找,出现不存在在string中组成的字符时,就返回元素位置;若不存在则npos
代码示例:

//在s1中查找不是‘z’,'h','n','g','s'的元素
string s1("zhang san");
s1.find_last_not_of("zhngs");    //7 

substr

在这里插入图片描述
获得子字符串,string substr(begin_pos=0,len=npos) 获取从pos位置长度为len的字符串,并返回。
代码示例:

//从s1的首位置后的5个字符作为字符串返回
string s1("zhang san");
string s2 = s1.substr(0,5);  //zhang

compare

在这里插入图片描述

9. Iterator

关于迭代器,是需要单独一篇博客来稍微进行分析的,这里只能暂且介绍相关函数。在string类中,我们把typedef char* iterator;,所以这里我们简单的把iterator理解为char*指针。

begin

在这里插入图片描述
begin()返回字符串的首字符的地址。

end

在这里插入图片描述
end()返回字符串的最后一个元素的下一个位置的地址。也就是\0那个位置。

rbegin

在这里插入图片描述
rbegin指向的位置和end()是对称的,也就是最后一个元素的下一个地址。\0的位置。但我们实践发现,解引用后打印的是最后一个元素。那是因为解引用操作的运算符重载,访问的是前一个元素。这是反向迭代器的一个小重点。
代码示例:

string s1("zhang san");
cout << *s1.rbegin();

rend

在这里插入图片描述
rend()它指向的位置也和begin对称,指向字符串首地址。

crbegin (C++11)

在这里插入图片描述

crend (C++11)

在这里插入图片描述

10.string的遍历方法

代码示例:

方法1:常规遍历

for (int i = 0; i < s1.size(); i++)
{
	cout << s1[i] << ' ';
}
cout << endl;

方法2:迭代器遍历

string::iterator it = s1.begin();
	while(it!=s1.end())
	{
		cout << *it << ' ';
		it++;
	}
	cout << endl;

方法3:语法糖(迭代器遍历)

for (auto e : s1)
	{
		cout << e << ' ';
	}
	cout << endl;

语法糖底层也是迭代器遍历,迭代器它是容器之间通用的,也就是说在库里面,迭代器用法都是一样的,但是其底层实现还是存在很多差异的。


总结

这篇博客介绍了string类的所有成员函数,希望对大家有所帮助。博文中部分为进行介绍的函数,后续会补齐。


C++语言系列学习目录

提示:这里可以添加系列文章的所有文章的目录,目录需要自己手动添加,添加超链接

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

胖胖龙大兄很忙

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值