【C++】string类(1)

🤖个人主页: 起名字真南

🤖个人专栏:【数据结构初阶】 【C语言】 【C++】

目录

  • 引言
  • [1 string类的基础知识](#1 string类的基础知识)
    • [1.1 什么是string类](#1.1 什么是string类)
    • [1.2 string和STL](#1.2 string和STL)
  • [2 范围for](#2 范围for)
    • [2.1 范围for的语法](#2.1 范围for的语法)
  • [3 string类的主要功能和操作](#3 string类的主要功能和操作)
    • [3.1 string类的构造](#3.1 string类的构造)
    • [3.2 string类对象空间容量操作](#3.2 string类对象空间容量操作)
    • [3.3 string类对象的访问和遍历操作](#3.3 string类对象的访问和遍历操作)
    • [3.4 string类对象的修改操作](#3.4 string类对象的修改操作)
    • [3.5 string类对象的非成员函数](#3.5 string类对象的非成员函数)

引言

在C++中,string类是标准库中的一个重要工具,用于处理字符串。与传统的C风格字符串(char数组)相比,C++的string类提供了更高的灵活性和安全性,并且能够自动处理内存管理。因此,掌握string类的使用对于编写高效、安全的C++代码至关重要。本文将从string类的基础知识入手,逐步深入探讨它的常用操作、底层实现及高级技巧,帮助你更好地理解并应用这一强大的工具。

1 string类的基础知识

1.1 什么是string类

C++的string类其实是标准库std的一部分,并且定义在了< string >头文件中,封装了字符数组并且提供了很多便捷的方法

1.2 string和STL

在C++中std::string与STL有着密切的关系(Standard Template Library,标准模板库)有着密切的联系。std::string类实际上是基于STL设计原则构建的一的特殊模板类,用于处理字符串这种常见的数据类型。

1 std::string是STL容器的特例 :

容器是组成STL的六大组件之一,它包含了 std::vector std::list 等等一些容器,而std::string本质上是专门处理字符串的一个容器,和vector< char >有很多相似的地方

  • 自动分配内存:std::string会自动管理储存的字符串内存,在对字符串进行增删查改等内容时会自动分配内存,不需要手动管理
  • 迭代器 :std::string可以使用STL标准模板库中的迭代器进行遍历整个容器,可以使用begin() end() 用来遍历字符。
    例如下面的代码 :
cpp 复制代码
#include<iostream>
#include<string>
using namespace std;
int main()
{
	string str = "hello world";
	for (auto it : str)
	{
		cout << it;
	}
	return 0;
}

这里的for循环时范围for因为后续学习STL的过程中都少不了他的存在所以接下来为大家介绍一下

2 范围for

其实范围for的本质上还是使用了STL中的六大组件之一的迭代器,通过调用begin() end()两个函数来返回string容器中的开头和结尾的迭代器。

2.1 范围for的语法

cpp 复制代码
for(auto it : 容器)
{
	cout<< it ;
}

这里的it是一个迭代器而不是指针,但是你可以理解为他是一个智能指针,因为它提供了像(*解引用,++递增)的一些用法,但是并不一定是指向实际内存的地址。而且不同的容器迭代器的类型也不同,例如vector的迭代器就是普通类型,但是list迭代器的类型可能是一个复杂的对象。

指针:则是指向内存的地址,是指向内存中某个位置的变量,并且只能用于数组中还有连续内存中的对象。

如果看不懂的话范围for的写法也可以是这样:

cpp 复制代码
auto begin = str.begin();
auto end = str.end();
for(auto it = begin; it != end; it++)
{
	char currentChar = *it;
	cout<< currentChar;
}

这里是定义了三个迭代器 分别是begin(用于记录str容器的开头位置)end(用于记录str的结尾位置) 还有it(作为循环变量),在for的循环体中我们定义了一个currentChar的变量用于记录当前字符,然后通过对it进行解引用来获取当前字符,最后输出当前字符然后it++,知道it == end的时候循环结束完整的输出整个字符串。

3 string类的主要功能和操作

在这里给大家提供一个可以作为参考的网址:

链接: C++string参考资料

3.1 string类的构造

函数名称 功能说明
string() (重点) 构造空字符串作为string类的对象
string(const char * s) (重点) 字符串作为string类的对象
string(size_t n, char c) n个字符c来构造string类的对象
string(const string& str) (重点) 用一个string类型来初始化另一个string类型的对象
string (const string& str, size_t pos, size_t len = npos) 使用字符串str的pos位置向后len个长度来构建string类的对象)

代码演示:

cpp 复制代码
int main()
int main()
{
	//string() 
	string s1;
	
	//string(const char* s)
	string s2("hello world");

	//string(const string& str)
	string s3(s2);


	//string(siez_t, char c)
	string s4(10, 'a');

	//string(const string& str, size_t pos, size_t len);
	string s5(s3, 6, 5);  //区间是左闭右开

	cout << "s1 :" << s1 << "\ns2: " << s2 << "\ns3: " << s3 << endl;
	cout << "s4: " << s4 << endl;
	cout << "s5: " << s5 << endl;

	return 0;
}

输出结果:

由于string的功能太多所以只对主要内容进行讲解。我们在写构造函数的时候需要注意在构造s1 的时候后面不能加()如果加了括号编译器会认为是一个函数声明并且不需要传参,不加括号编译器则会自动调用string的构造函数当我们在使用示例s5构造函数的时候要注意打印的区间是左开右闭,代码示例中是从第六个位置开始打印包括第六个位置后的五个字符

3.2 string类对象空间容量操作

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

代码演示:

cpp 复制代码
int main()
{
	string s1("hello world");

	cout << "s1.size() :" << s1.size() << endl;
	cout << "s1.length() :" << s1.length() << endl;
	cout << "s1.capacity() :" << s1.capacity() << endl;
	if (!s1.empty())
	{
		cout << "s1.empty() :" << "true" << endl;
	}
	s1.reserve(40);
	cout << "s1.reserve(40) :" << s1.capacity() << endl;
	s1.resize(20, 'p');
	cout <<"s1.resize(20, 'p'):" << s1 << endl;
	s1.clear();
	cout<< "s1.clear(): " << s1 << endl;
	

	return 0;
}

输出结果:

在我们reserve(40)之后为什么编译器开辟的空间是47?是因为编译器的内存管理策略,目的是提高性能并减少未来重新分配,一般开辟的空间只会比我们输入的更大不会更小

3.3 string类对象的访问和遍历操作

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

代码演示:

cpp 复制代码
int main()
{
	string s1("hello world");
	for (int i = 0; i < s1.size(); i++)
	{
		cout << s1[i];
	}

	cout << endl;
	auto begin = s1.begin();
	auto end = s1.end();

	for (auto it = begin; it != end; it++)
	{
		cout << *it;
	}
	

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

	cout << endl;
	auto rbegin = s1.rbegin();
	auto rend = s1.rend();

	for (auto it = rbegin; it != rend; it++)
	{
		cout << *it;
	}

	return 0;
}

输出结果:

需要注意一种情况就是在调用rbegin 和 rend的时候最后循环条件改变的方式依旧是++,而不是--。

3.4 string类对象的修改操作

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

代码演示:

cpp 复制代码
int main()
{
	string s1;
	s1.push_back('a');
	s1.push_back('a');
	s1.push_back('a');
	s1.push_back('a');

	cout << s1 << endl;

	s1.append("bxvxcvb");
	cout << s1 << endl;

	s1 += "xzviuynq";
	cout << s1 << endl;

	size_t c = s1.find('c', 0);
	cout << "c第一次出现的坐标大小 :" << c << endl;

	size_t rc = s1.rfind('c',-1);
	cout << "c最后一次出现的坐标大小 :" << rc << endl;

	string s2;
	s2 = s1.substr(0, 9);  //左闭右开所以返回的是下标从0-8的字符
	cout << s2 << endl;

	if (strcmp(s1.c_str(), s2.c_str()) > 0)
	{
		cout << "s1 > s2" << endl;
	}
	else if (strcmp(s1.c_str(), s2.c_str()) < 0)
	{
		cout << "s1 < s2" << endl;
	}
	else
	{
		cout << "s1 == s2" << endl;
	}
	return 0;
}

输出结果:
注意这里的find 和refind 的返回值都是字符c的坐标,我们调用c_str的原因是我们没有重载< 和 >操作符所以不能对string类直接进行比较,所以我们需要使用c_str来将他们转换成字符型来进行比较。

3.5 string类对象的非成员函数

函数名称 功能说明
operator+ 将两个字符串拼接并返回一个新字符串
relational operators (==, !=, <, >, <=, >=) 用于比较两个字符串的大小或相等性
swap (string& str) 交换两个字符串的内容
operator>> (istream& in, string& str) 从输入流读取字符串
operator<< (ostream& out, const string& str) 将字符串输出到输出流
getline (istream& in, string& str) 从输入流中读取一行字符串,直到遇到换行符

代码演示:

cpp 复制代码
int main()
{
	string s1("hello ");
	string s2("world");

	string s3 = s1 + s2;
	cout << s3 << endl;

	string foo = "alpha";
	string bar = "beta";

	if (foo == bar) cout << "foo and bar are equal\n";
	if (foo != bar) cout << "foo and bar are not equal\n";
	if (foo < bar)  cout << "foo is less than bar\n";
	if (foo > bar)  cout << "foo is greater than bar\n";
	if (foo <= bar) cout << "foo is less than or equal to bar\n";
	if (foo >= bar) cout << "foo is greater than or equal to bar\n";

	string s4;
	cout << "s4 = ";
	cin >> s4;
	cout << s4 << endl;

	cin.ignore();
	string s5;
	cout << "输入一串文字 :";
	getline(cin, s5);
	cout << s5 <<endl;
	return 0;
}

输出结果:

注意当我们在使用cin和getline的时候需要注意一种情况就是cin只会读取到空格而在你输出的完之后按下的空格cin不会读取而是会存到缓冲区里,当我们使用getline的时候会直接读取缓冲区的\n从而导致程序出错直接结束不会再读取你输入的内容。,

解决的办法有两种:

  1. 使用cin.ignore()用来清除缓冲区的一个字符一般是换行符'\n'
  2. 先执行getline()在用cin。
相关推荐
Ajiang282473530423 分钟前
对于C++中stack和queue的认识以及priority_queue的模拟实现
开发语言·c++
幽兰的天空28 分钟前
Python 中的模式匹配:深入了解 match 语句
开发语言·python
Theodore_10223 小时前
4 设计模式原则之接口隔离原则
java·开发语言·设计模式·java-ee·接口隔离原则·javaee
‘’林花谢了春红‘’5 小时前
C++ list (链表)容器
c++·链表·list
----云烟----5 小时前
QT中QString类的各种使用
开发语言·qt
lsx2024065 小时前
SQL SELECT 语句:基础与进阶应用
开发语言
开心工作室_kaic6 小时前
ssm161基于web的资源共享平台的共享与开发+jsp(论文+源码)_kaic
java·开发语言·前端
向宇it6 小时前
【unity小技巧】unity 什么是反射?反射的作用?反射的使用场景?反射的缺点?常用的反射操作?反射常见示例
开发语言·游戏·unity·c#·游戏引擎
武子康6 小时前
Java-06 深入浅出 MyBatis - 一对一模型 SqlMapConfig 与 Mapper 详细讲解测试
java·开发语言·数据仓库·sql·mybatis·springboot·springcloud
转世成为计算机大神7 小时前
易考八股文之Java中的设计模式?
java·开发语言·设计模式