【C++】---STL之string详解

一、STL简介

  1. 什么是STL?
    STL(standard template libaray-标准模板库):是C++标准模版库
  2. STL的六大组件:
    在这里插入图片描述

二、string类

1、string类定义

C语言中,字符串是以’\0’结尾的一些字符的集合。

但是,C++的标准库中定义了string类:

  1. string是表示字符串的字符串类

  2. 该类的接口与常规容器的接口基本相同,再添加了一些专门用来操作string的常规操作。

  3. string在底层实际是:basic_string模板类的别名,typedef basic_string<char, char_traits, allocator> string;

  4. 不能操作多字节或者变长字符的序列。
    注意:在使用string类时,必须包含#include头文件以及using namespace std;

2、string类的构造函数

在这里插入图片描述
最重要的是这三个:(1)无参构造(2)拷贝构造(3)字符串构造

#define _CRT_SECURE_NO_WARNINGS 1 
#include <stdio.h>
#include <string>
using namespace std;
#include<iostream>

void test_string1()
{
	string s0 = "hello bite";
	string s1;// 1.无参的构造函数
	
	// string s1();  错误,无参构造不用加括号(这样写相当于一个声明了!!!)

	string s2(s0);// 2.拷贝构造
	string s3("hello world!"); // 3.字符串构造

	// 4.部分拷贝:含有npos==-1,如果对于nops超出了范围,是有多少拷贝多少!
	string s4("hello world!", 1, 4);

	string s5("hello world!", 1, 100);

	cout <<"s0:"<< s0 << endl;
	cout << "s1:"<< s1 << endl;
	cout << "s2:" << s2 << endl;
	cout << "s3:" << s3 << endl;
	cout << "s4:" << s4 << endl;
	cout << "s5:" << s5 << endl;
}
int main()
{
	test_string1();
	return 0;
}

在这里插入图片描述

3、string类的元素访问符

  1. 遍历string的方法:下标+[ ]
  • 这里string的[ ]调用是一个函数operator[ ],自己不写编译器也会动调用,他跟数组下标访问完全不同。
  • operator[ ]的底层原理是这样的:返回的是pos位置的字符。
    (是一个可读可写的!!!)
class string
{
public:
	char& operator[](size_t pos)
	{
		return _str[pos];
	}
private:
	char* _str;
	size_t size;
	size_t capacity;
};
void test_string2()
{
	string s1("Hello World!");
	for (size_t i = 0; i < s1.size(); i++)
	{
		cout << s1[i] << " ";
	}cout << endl;
}
int main()
{
	//test_string1();
	test_string2();

	return 0;
}
  • 上面的size()表示:返回某个字符串有多少个字符
    在这里插入图片描述
  1. 访问string也可以用at:(at== [ ]下标)
void test_string2()
{
	string s1("Hello World!");
	for (size_t i = 0; i < s1.size(); i++)
	{
		cout << s1[i] << " ";
	}cout << endl;

	for (size_t i = 0; i < s1.size(); i++)
	{
		cout << s1.at(i) << " ";
	}cout << endl;
}
int main()
{
	//test_string1();
	test_string2();

	return 0;
}

在这里插入图片描述

两者的唯一区别就是他们数组越界报错的原因不一样:
下标[ ]:如果出现数组越界,报的是断言错误。
at:如果数组越界,报的是抛异常失败。

4、string类的迭代器(iterator)

string、vector支持[ ]遍历,但是list、map等容器不支持[ ]遍历,迭代器是一种可以统一使用的遍历方式。迭代器是类似于指针。因为:string、vector是有连续的储存地址!可以类似数组一样进行下标访问。

  1. 然后接下来要讲的迭代器则是针对于所有数据结构通用的遍历方式。
void test_string2()
{
	string s1("Hello World!");
	// 迭代器的行为像指针,但是它不是!
	string::iterator it1 = s1.begin();
	while (it1 != s1.end())
	{
		cout << *it1 << " ";
		it1++;
	}
	cout << endl;
}
int main()
{
	//test_string1();
	test_string2();

	return 0;
}

在这里插入图片描述

  • 注意区分这里的:begin()和end()他们类似指针!
    begin() :指向第一个字符!
    end():指向最后一个字符的下一个位置!

    即:左闭右开!
    在这里插入图片描述
  1. 反向迭代器:
void test_string2()
{
	string s1("Hello World!");
	 迭代器的行为像指针,但是它不是!
	//string::iterator it1 = s1.begin();
	//while (it1 != s1.end())
	//{
	//	cout << *it1 << " ";
	//	it1++;
	//}
	//cout << endl;

	string::reverse_iterator it1 = s1.rbegin();
	while (it1 != s1.rend())
	{
		cout << *it1 << " ";
		it1++;
	}
	cout << endl;

}
int main()
{
	//test_string1();
	test_string2();

	return 0;
}

在这里插入图片描述
在这里插入图片描述
3. 范围for也可以用来遍历字符串(它的底层就是迭代器)
取s1的值赋值给e,e是s的拷贝,因此加引用,如果不加引用,就只能对s读,不能对s写。auto是自动推导,使用方便:

void test_string2()
{
	string s1("Hello World!");
	for (auto& e : s1)// 自动判断结束
	{
		cout << e << " ";
	}
	cout << endl;
}
int main()
{
	//test_string1();
	test_string2();

	return 0;
}
  • 正向遍历就多用范围for!
  • 在这里插入图片描述

5、string的插入和拼接

(1)string的插入

①在字符串末尾插入:

void push_back (char c);  //向字符串末尾追加一个字符

②在指定位置插入:

string& insert(size_t pos, const string& str);//插入字符串拷贝
string& insert (size_t pos, const char* s);//插入c形式的字符串
string& insert (size_t pos, const char* s, size_t n);//将字符串s的前n个字符插到pos位置
#include<iostream>
#include<string>
using namespace std;
int main()
{
	string s0("");
	s0.push_back('h');//s0尾插h
	cout << s0 << endl;
 
	string s1("ell");
	s0.insert(1, s1);//在下标为1的位置插入s1的拷贝
	cout << s0 << endl;
 
	s0.insert(4, "o");//在下标为4的位置插入字符串o
	cout << s0 << endl;
 
    s0.insert(0, "cplusplus",2);//在下标为0的位置插入"cplusplus"的前2个字符
    cout << s0 << endl;
 
    return 0;
}

(2)字符串的拼接

①使用append进行拼接

string& append (const string& str);  //向字符串对象末尾追加字符串
string& append (const char* s);//向字符串末尾追加字符
string& append(size_t n, char c);//向字符串末尾追加n个相同字符
#include<iostream>
#include<string>
using namespace std;
int main()
{
	string s0("");
	s0.append("hello");//将hello追加到s0末尾
	cout << s0 << endl;
	string s1 = " world";
	s0.append(s1);//s0.append(s1.begin().s1.end());//将字符串s1追加到s0末尾
	cout << s0 << endl;
	s0.append(3, '!');//想s0末尾追加3个!
	cout << s0 << endl;
	
	//用+=追加很方便,比append更常用
	s0 += '!';
	s0 += " yes";
	string s2 = " it is.";
	s0 += s2;
	cout << s0 << endl;
}

②使用全局函数operator+拼接:

string operator+ (const string& lhs, const string& rhs);//拼接lhs和rhs
#include<iostream>
#include<string>
using namespace std;
 
int main()
{    
    string s1 = "cplusplus";
	string s2 = ".com";
	string s3 = s1 + s2;
	cout << s3 << endl;
 
	return 0;
}

6、string的删除

  1. erase:

在这里插入图片描述

void test_string3()
{
	string s1("Hello World!");
	
	//s1.erase(2, 2);
	s1.erase(2, 100); // 如果参数2,len的常量>size,那么就全部清理完!
	
	cout << s1 << endl;
}
int main()
{
	test_string3();
	return 0;
}

在这里插入图片描述
在这里插入图片描述

7、string的容量

(1)求字符串的个数

size_t size() const;//size()求字符串中有效字符的个数
size_t length() const;//length()求字符串中有效字符的个数

size( )和length( )没有区别:

#include<iostream>
#include<string>
using namespace std;
 
int main()
{
    string s1;
	cout << s1.size() << endl;
	cout << s1.length() << endl;
    
    return 0;
}

(2)判空

bool empty() const;//判断字符串是否为空
    string s1;
	cout << s1.empty() << endl;

(3)容量

size_t capacity() const;//返回所分配内存的字节数
void test_string4()
{
	string s1("Hello World!");

	cout << s1.capacity() << endl;
	cout << s1.size() << endl;
	
}
int main()
{
	test_string4();
	return 0;
}

在这里插入图片描述
size<capacity的原因:要给‘\0’留有空间!

(4)调整字符串的大小

只调整size大小,不填充内容!

void resize(size_t n); // n为调整后的字符串大小,
//默认插入字符'\0',32位机器一般为4的倍数,64位机器一般为8的倍数,一般按2倍去调整

void test_string4()
{
	string s1("Hello World!");

	s1.resize(21);
	
	cout << s1.size() << endl;
	cout << s1.capacity() << endl;
}
int main()
{
	test_string4();
	return 0;
}

没有走resize()之前size==12
在这里插入图片描述

走了resize之后:size==21且后面新增的空间全部默认为’\0’:
在这里插入图片描述
②调整字符串大小,并将增加的空间内容初始化成给定字符:

s1.resize(21,'x');
void test_string4()
{
	string s1("Hello World!");

	s1.resize(21,'x');
	
	cout << s1.size() << endl;
	cout << s1.capacity() << endl;
}
int main()
{
	test_string4();
	return 0;
}

在这里插入图片描述

(5)调整字符串的容量(reserve)

void reserve (size_t n = 0);//调整容量,缺省容量为0
void test_string5()
{
	string s1("Hello World!"); 

	cout << "szie->"<<s1.size() << endl;
	cout <<"capacity->"<< s1.capacity() << endl;

	s1.reserve(20);
	cout << "szie->" << s1.size() << endl;
	cout << "capacity->" << s1.capacity() << endl;

	s1.reserve(50);
	cout << "szie->" << s1.size() << endl;
	cout << "capacity->" << s1.capacity() << endl;
}
int main()
{
	test_string5();
	return 0;
}

在这里插入图片描述
第二次reserve 之后的容量变成了63,是第一次reserve之后容量的2倍:
2. 查看扩容机制:


void test_string5()
{
	string s1("Hello World!");

	size_t cp = s1.capacity();
	cout << "cp->" << cp << endl;
	cout << "making a cp growing\n";
	for (size_t i = 0; i < 100; i++)
	{
		s1.push_back('x');
		if (cp != s1.capacity())// 当cp(即:原容量)!=未扩容的capacity时
		{
			cp = s1.capacity(); // 此时的capacity就已经扩好容了
			cout << "capacity changed:" << s1.capacity() << endl;
		}
	}
}
int main()
{
	test_string5();
	return 0;
}

在这里插入图片描述
在不同的系统下,扩容的机制不同,比如windows中的vs和Linux的扩容机制就不同!

8、string字符串的操作(find重要)

(1)查找

size_t find(const string & str, size_t pos = 0) const;//返回在给定字符串中查找字符串str第一次出现的位置	
size_t find(const char* s, size_t pos = 0) const;//返回在给定字符串中从下标为pos的位置开始查找字符串s第一次出现的位置
size_t find(const char* s, size_t pos, size_t n) const;//返回在给定字符串中从下标为pos的位置开始查找字符串s的前n个字符第一次出现的位置
size_t find(char c, size_t pos = 0) const;//返回在给定字符串中从下标为pos的位置开始查找字符c第一次出现的位置
void test_string6()
{
	string s1("Hello World!");
	cout << s1.find("lo", 2) << endl;// 返回在字符串s1中从下标为2的地方开始查找,字符lo第1次出现的位置。
	cout << s1.find("ll") << endl;// 返回在字符串s1中,字符ll第1次出现的位置。
	cout << s1.find('o') << endl;// 返回在字符串s1中,字符o第1次出现的位置。
}
int main()
{
	test_string6();
	return 0;
}

(2)查找子串

string substr (size_t pos = 0, size_t len = npos) const;//截取给定字符串中从第pos个位置开始的len个长度的字符
void test_string7()
{
	string s1("Hello World!");
	
	cout << s1.substr(0, 5) << endl;// 截取从下标为0的位置开始,长度len为5的字符!
}
int main()
{
	test_string7();
	return 0;
}

在这里插入图片描述

(3)反向查找

size_t rfind(const string & str, size_t pos = npos) const;//从右向左在给定字符串中查找字符串str第一次出现的位置	
size_t rfind(const char* s, size_t pos = npos) const;//从右向左在给定字符串中下标为pos的位置开始查找字符串s第一次出现的位置
size_t rfind(const char* s, size_t pos, size_t n) const;//从右向左在给定字符串中从下标为pos的位置开始查找字符串s的前n个字符第一次出现的位置
size_t rfind(char c, size_t pos = npos) const;//从右向左在给定字符串中从下标为pos的位置开始查找字符c第一次出现的位置

void test_string8()
{
	string s1("Hello World!");
	cout << s1.rfind("He", 2) << endl;
	cout << s1.rfind("el", 2) << endl;
	cout << s1.rfind("lo", 2) << endl;
	cout << s1.rfind('o') << endl;
}
int main()
{
	test_string8();
	return 0;
}

在这里插入图片描述

9、string字符串的比较

bool operator== (const string& lhs, const string& rhs);
bool operator== (const char* lhs, const string& rhs);
bool operator== (const string& lhs, const char* rhs);
 
bool operator!= (const string& lhs, const string& rhs);
bool operator!= (const char* lhs, const string& rhs);
bool operator!= (const string& lhs, const char* rhs);
 
bool operator<  (const string& lhs, const string& rhs);
bool operator<  (const char* lhs, const string& rhs);
bool operator<  (const string& lhs, const char* rhs);
 
bool operator<= (const string& lhs, const string& rhs);
bool operator<= (const char* lhs, const string& rhs);
bool operator<= (const string& lhs, const char* rhs);
 
bool operator>  (const string& lhs, const string& rhs);
bool operator>  (const char* lhs, const string& rhs);
bool operator>  (const string& lhs, const char* rhs);
 
bool operator>= (const string& lhs, const string& rhs);
bool operator>= (const char* lhs, const string& rhs);
bool operator>= (const string& lhs, const char* rhs);
#include<iostream>
#include<string>
using namespace std; 
 
int main()
{
    string s1 = "cplusplus";
	string s2 = ".com";
	
	cout << (s1 == s2) << endl;
	cout << (s1 == "cplusplus.com") << endl;
	cout << ("cplusplus.com" == s2) << endl;
 
	return 0;
}

好了,今天的分享就到这里了
如果对你有帮助,记得点赞👍+关注哦!
我的主页还有其他文章,欢迎学习指点。关注我,让我们一起学习,一起成长吧!
在这里插入图片描述

  • 12
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

小能软糖_

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

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

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

打赏作者

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

抵扣说明:

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

余额充值