C++ string用法详解

目录

一.为什么要学习string类

1.1 C语言中的字符串

二. string类的常用操作

2.1 string类的初始化

2.2 string类常用的容量操作

2.2.1 size()

 2.2.2 length() 函数

2.2.3   capacity() 函数

2.2.4    empty()函数

 2.2.5 resize()函数和reserve()函数

 2.2.5 clear() 函数

2.3 string类对象的访问及遍历操作函数

2.3.1 []  (operator[])

 2.3.2 begin() 和 end()

  2.3.3 rbegin() 和 rend()

 2.3.4 范围for

 2.4. string类对象的修改操作

2.4.1 push_back() 函数

 2.4.2  append() 函数

  2.4.3 +=(operator+=)

 2.4.4 c_str

 2.4.5 find() + npos

  2.4.6 rfind()

 2.4.7 substr()

 2.5  常用string类非成员函数

2.5.1 operator+

2.5.2  >>和<<

2.5.3 getline

 2.5.4 relational operators()


一.为什么要学习string类

1.1 C语言中的字符串

   在C语言中,字符串是以'\0'结尾的一些字符的集合,为了操作方便,C标准库中提供了一些str系列的库函数,但是这些库函数与字符串是分离开的,不太符合OOP的思想,而且底层空间需要用户自己管理,稍不留神可能还会越界访问。

  为了弥补这些C语言中的部分设计缺陷,C++研发出了string类,更好的服务于程序员。

重点:

在OJ中,有关字符串的题目基本以string类的形式出现,而且在常规工作中,为了简单、方便、快捷,基本都使用string类,很少有人去使用C库中的字符串操作函数。为了找到好Offer,熟练掌握string类是我们C艹程序员的必要工作。

二. string类的常用操作

  string类的文档链接:https://cplusplus.com/reference/string/string/

  同时,使用string类大多数情况还需要头文件#include

2.1 string类的初始化

  string对象的初始化和普通类型变量的初始化基本相同,只是string作为类,还有类的一些特性:使用构造函数初始化。

  String类的常用初始化

函数名称(红色为重点) 功能说明
string   s() 构造空的string类对象,即空字符串
string   s(const char* s) 用C-string来构造string类对象
string   s(size_t n, char c) string类对象中包含n个字符c
string   s(const string&s) 拷贝构造函数

如:

//常用构造函数
#include
//用string类的话需要包含头文件#include
using namespace std;
int main()
{
	string s1;
	string s2("abcdefg");
	string s3(99, 'a');
	string s4(s2);

	cout << s2 << endl;
	cout << s3 << endl;
	cout << s4 << endl;
	return 0;
}

代码结果为:

C++ string用法详解_第1张图片

2.2 string类常用的容量操作

函数名称(红色为重点) 功能说明
size() 返回字符串有效字符长度,(有效空间)
length() 返回字符串有效字符长度,(有效空间)
capacity() 返回空间总大小
empty() 检测字符串释放为空串,是返回true,否则返回false
clear() 清空有效字符
reserve(size_t n=0) 为字符串预留空间
resize(size_t n,char c) 将有效字符的个数该成n个,多出的空间用字符c填充

如:

2.2.1 size()

 

//容量操作
#include
using namespace std;

//  size()函数
int main()
{
	string s1(99, 'a');
	cout << s1.size() << endl;
	return 0;
}

代码结果为:

C++ string用法详解_第2张图片

 

 2.2.2 length() 函数

//容量操作
#include
using namespace std;

//length()函数
int main()
{
	string s1(99, 'a');
	cout << s1.length() << endl;
	return 0;
}

代码结果为:

C++ string用法详解_第3张图片

 注意:
 size()与length()方法底层实现原理完全相同,引入size()的原因是为了与其他容器的接口保持一致,一般情况下基本都是用size()。(这个属于C++的早期设计缺陷)

2.2.3   capacity() 函数

//容量操作
#include
using namespace std;

//capacity()函数
int main()
{
	string s1(10,'a');
	cout << s1.capacity() << endl;
	
	return 0;
}

代码结果为:

C++ string用法详解_第4张图片

 根据vs 开辟空间的规则,创建string类时初始分配十五个字节的总空间,但实际上这里的有效空间为10。

我们可以用size求出s1的有效空间    如:

#include
using namespace std;

//capacity()函数
int main()
{

	string s1(10,'a');
	cout << s1.capacity() << endl;
	cout << s1.size() << endl;`
	return 0;
}

C++ string用法详解_第5张图片

 

2.2.4    empty()函数

//容量操作
#include
using namespace std;

//  empty()函数
int main()
{
	string s1;
	string s2("12345");
	cout << s1.empty() << endl;
	cout << s2.empty() << endl;
	return 0;
}

代码结果为:

C++ string用法详解_第6张图片

 2.2.5 resize()函数和reserve()函数

一.resize() 重新规划string的大小,但是注意,这里实际上规划的是有效空间的大小。

通过前边的知识,我们可以用size()求出有效空间的大小,用resize进行重新规划。

如:

//容量操作
#include
using namespace std;

//resize()函数和reserve()函数
int main()
{
	string s1("Hello World");

	cout << s1.size() << endl;
	cout << s1.capacity() << endl;

	s1.resize(5);//通过resize把有效空间改为5

	cout << s1.size() << endl;
	cout << s1.capacity() << endl;

	cout << s1 << endl;
	return 0;
}

输出结果为:

C++ string用法详解_第7张图片

这时候就分两种情况

1.缩小有效空间:

  这种情况下,容器中长度在n之外的部分会被截取掉,只保留n长度内的元素,但是容器的容量却没有改变,更不会出现扩容的状况,上段代码体现了这一点。

2.扩大有效空间:

  这种情况下,容器为了能够放的下更多的元素,会发生扩容,扩容之后,其容量会比原来大,这时候就会出现没有用过的有效空间,此时我们通过函数的第二个元素 c 进行剩余空间的初始化。

  也就是说,当扩容时,扩容的空间内存放的元素全都是第二个元素 C。如果没有指定第二个元素c,那就用string的默认初始化了,这种情况下,容器一定是分配了内存并全部发生了初始化的。

如:

//容量操作
#include
using namespace std;

int main()
{
	string s1("Hello World");

	cout << s1 << endl;
	cout << s1.size() << endl;
	cout << s1.capacity() << endl;
	s1.resize(20, 'x');

	cout << s1 << endl;
	cout << s1.size() << endl;
	cout << s1.capacity() << endl;
	
	return 0;
}

代码结果为:

C++ string用法详解_第8张图片

 注意:有效空间的变化可能会影响最大空间的变化,最大空间的变化也可能影响有效空间的变化。

二.reserve() 函数改变最大空间。
 

容量操作
#include
using namespace std;

int main()
{
	string s1("Hello World");

	cout << s1.capacity() << endl;
	s1.reserve(20);

	cout << s1.capacity() << endl;
	
	return 0;
}

 代码结果为:

C++ string用法详解_第9张图片

 注意:这里代码结果不同预想也是因为VS 的容量规则

 2.2.5 clear() 函数

容量操作
 #include
using namespace std;

int main()
{
	string s1("Hello World");

	cout << s1.size() << endl;
	s1.clear();

	cout << s1.size() << endl;
	cout << s1.capacity() << endl;

	return 0;
}

代码结果为:

C++ string用法详解_第10张图片

注意:clear()只是将string中有效字符清空,不改变底层空间大小。

2.3 string类对象的访问及遍历操作函数

函数名称  (重点为红色) 功能说明
[]  (operator[]) 返回pos位置的字符,const string类对象调用
begin() 获取第一个字符位置的迭代器
end() 获取最后一个字符下一个位置的迭代器
rbegin() 获取最后一个元素的反向迭代器
rend() 获取第一个位置之前一个位置的反向迭代器
范围for C++11支持更简洁的范围for的新遍历方式

2.3.1 []  (operator[])

实际上就是数组的[],可以随机访问元素,底层是操作符重载(不讲)。

//string类对象的访问及遍历操作函数 
#include
using namespace std;

// []
int main()
{
	string s1("abcde");
	cout << s1[0] << endl;
	cout << s1[s1.size()-1] << endl;
	cout << s1[2] << endl;
	return 0;
}

代码结果为:

C++ string用法详解_第11张图片

 2.3.2 begin() 和 end()

//string类对象的访问及遍历操作函数 
#include
using namespace std;

//begin()和end()
int main()
{
	string s1("12345");
	string::iterator it = s1.begin();
	while (it != s1.end())
	{
		cout << *it << endl;
		it++;
	}
	return 0;
}

代码结果为:

C++ string用法详解_第12张图片

 两图解迭代器原理(狗头保命):

C++ string用法详解_第13张图片

 C++ string用法详解_第14张图片

 

 

 C++中,迭代器就是一个类似于指针的对象,它能够用来遍历C++标准模板库容器中的部分或全部元素,每个迭代器对象代表容器中的确定的地址。

  但在string中,我们最常用的还是数组的下标访问,故不在多描述。

  2.3.3 rbegin() 和 rend()

//string类对象的访问及遍历操作函数 
#include
using namespace std;

//rbegin()和rend()
int main()
{
	string s1("12345");
	string::reverse_iterator it = s1.rbegin();
	while (it != s1.rend())
	{
		cout << *it << endl;
		it++;
	}
	return 0;
}

结果为:

C++ string用法详解_第15张图片

 2.3.4 范围for

//string类对象的访问及遍历操作函数 
#include
using namespace std;


//for(auto )
int main()
{
	string s1("12345");
	for (auto it : s1)
	{
		cout << it << endl;
	}
	return 0;
}

代码结果为:

C++ string用法详解_第16张图片

 是不是看起来很高端:

一图解范围for:
C++ string用法详解_第17张图片

 2.4. string类对象的修改操作

函数名称 功能说明
push_back(c) 在字符串后尾插字符c
append(s) 在字符串后追加一个字符串
+=(operator+= ) 在字符串后追加字符串str
c_str 返回C格式字符串
find + npos 从字符串pos位置开始往后找字符c,返回该字符在字符串中的位置
rfind 从字符串pos位置开始往前找字符c,返回该字符在字符串中的位置
substr 在str中从pos位置开始,截取n个字符,然后将其返回

2.4.1 push_back() 函数

类似于链表的尾插

//string类对象的访问及遍历操作函数 
#include
using namespace std;

int main()
{
	string s1("Hello ");

	cout << s1 << endl;
	s1.push_back('W');
	s1.push_back('o');
	s1.push_back('r');
	s1.push_back('l');
	s1.push_back('d');

	cout << s1 << endl;
	return 0;
}

结果为:

C++ string用法详解_第18张图片

 2.4.2  append() 函数

也类似于链表的尾插,但是插入的是一个字符串。

//string类对象的访问及遍历操作函数 
#include
using namespace std;

int main()
{
	string s1("Hello ");
	cout << s1 << endl;
	s1.append("World");
	cout << s1 << endl;
	return 0;
}

结果为:

C++ string用法详解_第19张图片

  2.4.3 +=(operator+=)

本质上是一个符号重载,依旧类似于链表的尾插。

//string类对象的访问及遍历操作函数 
#include
using namespace std;

int main()
{
	string s1("Hello ");
	cout << s1 << endl;
	s1 += "World";
	cout << s1 << endl;
	return 0;
}

结果为:

C++ string用法详解_第20张图片

注意:
 在string尾部追加字符时,s.push_back(c) / s.append(1, c) / s += 'c'三种的实现方式差不多,一般情况下string类的+=操作用的比较多,+=操作不仅可以连接单个字符,还可以连接字符串。 

 2.4.4 c_str

  在C语言中,字符串是以'\0'结尾的一些字符的集合。但在C++中,string类不以'\0'结尾,而是根据有效空间的大小结束。

  这个函数的本质作用是:将 const string* 类型 转化为 const char* 类型

 2.4.5 find() + npos

find有很多函数重载,我们只学一种就好了。

     size_t find  (const string &s,int pos=0);

s是需要查找的字符串,pos是从哪个位置查找 , 如果未查找到则返回npos(size_t 的最大值)。

如:

//string类对象的访问及遍历操作函数 
#include
using namespace std;

int main()
{
	string s1("fghasdabc");
	cout << s1.find('a') << endl;

	string s2("abc");
	cout << s1.find(s2) << endl;
	cout << s1.find('e') << endl;
	return 0;
}

代码结果为:

C++ string用法详解_第21张图片

  2.4.6 rfind()

同样,rfind()和find()只有一个往前找,一个像后找的区别:

size_t find  (const string &s,int pos=npos);

 

//string类对象的访问及遍历操作函数 
#include
using namespace std;

int main()
{
	string s1("fghasdabc");
	cout << s1.rfind('a') << endl;

	string s2("abc");
	cout << s1.rfind(s2) << endl;
	cout << s1.rfind('e') << endl;
	return 0;
}

 此时 第一个打印结果就会发生变化:

C++ string用法详解_第22张图片

 2.4.7 substr()

函数定义为: string substr(size_t pos=0,size_t len=npos) const;

作用为:在string的pos位置截取n个字符,然后返回

//string类对象的访问及遍历操作函数 
#include
using namespace std;

int main()
{
	string s1("Hello World");

	cout << s1 << endl;
	string s2(s1.substr(0, 5));

	cout << s1 << endl;

	cout << s2 << endl;
	return 0;
}

结果为:

C++ string用法详解_第23张图片

 2.5  常用string类非成员函数

函数名字 (红色为重点) 作用说明
operator+ 尽量少用,因为传值返回,导致深拷贝效率低
operator>> 输入运算符重载
operator<< 输出运算符重载
getline 获取一行字符串
relational operators 字符串大小比较

2.5.1 operator+

这个大家根据  + 和 +=的特性 ,再结合类的知识点,自己推一下为什么效率低(绝对不是因为我懒!!!)。

2.5.2  >>和<<

  重载输入输出。

2.5.3 getline

函数定义为:

istream& getline (istream & is,string& str);

注意:
cin输入会自动吃点前置换行和空格,即cin输入得到的不可能是空串。而getline不会吃掉换行符号和空格,可能会使得输入出现意料之外的错误。

比如说:

#include
#include//需要头文件
using namespace std;

int main()
{
	string s1;//输入个Hello World 看看
	cin >> s1;
	cout <

代码结果为:

C++ string用法详解_第24张图片

 可见,cin遇见空格就结束了,可能会使得输入出现意料之外的错误。

正确的做法是使用getline();

//string类对象的访问及遍历操作函数 
#include
#include//需要头文件
using namespace std;

int main()
{
	//string s1;//输入个Hello World 看看
	//cin >> s1;
	//cout <

C++ string用法详解_第25张图片

 2.5.4 relational operators()

 

 就是符号重载了关系运算符;

使得>=,<=等运算符可以用于字符串比较

 

你可能感兴趣的:(c++,开发语言,c语言)