C++深入学习string类成员函数(4):字符串的操作

news/2024/9/28 18:11:22 标签: c++, 学习, 开发语言

引言

在c++中,std::string提供了许多字符串操作符函数,让我们能够秦松驾驭文本数据,而与此同时,非成员函数的重载更是为string类增添了别样的魅力,输入输出流的重载让我们像处理基本类型的数据一样方便地读取和输出字符串,连接操作符的重载使得字符串的拼接变得简洁直观。在这篇博客中,我们将一同深入剖析C++中string类的字符串操作符和非成员函数的重载,为大家在编程之旅中增添一份有力的武器。

在开始介绍操作符函数前,我们先来了解一个string类定义的一个静态成员变量npos。

1.npos

npos是std::string中定义的一个静态常量成员,表示“no opsition”(没有位置)。它通常用于返回表示查找操作失败时的返回值  。

static const size_t npos = -1;
#include <iostream>
using namespace std;

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

	size_t pos = s1.find("good");

	if (pos == string::npos);
	{
		cout << "字符串未找到" << endl;
	}

	return 0;
}

 

2.string类的字符串操作函数

2.1. c_str()

c_str用来返回一个指向C风格字符串(以空字符\0结尾)的指针。适用于需要与C语言或库(如printf、文件操作等)进行交互时将std::string转换为C风格字符串

(1)函数原型

const char* c_str() const;

(2)示例代码

#include <iostream>
using namespace std;

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

	const char* cstr = s1.c_str();

	cout << cstr << endl;//Hello
	return 0;
}

 (3)string与C风格字符串的区别

在 C++中, std::string 类型的字符串与 C 风格字符串有以下一些主要区别:
 
一、内存管理
 -  std::string :自动管理内存。当对 std::string 对象进行赋值、拼接等操作时,它会自动处理内存的分配和释放,无需程序员手动管理。
- C 风格字符串:需要手动管理内存。如果是动态分配的字符数组,程序员必须在合适的时候使用 free (C)或 delete[] (C++)释放内存,否则会导致内存泄漏。对于局部的字符数组,其内存会在作用域结束时自动释放,但长度在创建时就固定,难以灵活调整。
 
二、安全性

 -  std::string :通常具有边界检查机制,不容易出现缓冲区溢出等安全问题。例如,在进行字符串拼接时,会自动调整内存大小以容纳新的内容
- C 风格字符串:缺乏内置的安全检查机制。在进行字符串操作时,如复制、连接等,如果不仔细控制长度,很容易导致缓冲区溢出,可能会破坏程序的稳定性甚至被恶意利用。
 
三、功能丰富度
 -  std::string :提供了丰富的成员函数,如 find (查找子串)、 substr (提取子串)、 append (追加字符串)等,使得字符串操作更加方便和直观。
- C 风格字符串:主要依靠 C 标准库中的函数,如 strcpy (复制字符串)、 strcat (连接字符串)、 strstr (查找子串)等,这些函数使用起来相对较为繁琐,且容易出错。
 
四、初始化和赋值
 -  std::string :可以使用多种方式进行初始化和赋值,例如使用字符串常量、另一个 std::string 对象、字符数组的一部分等。初始化和赋值操作通常比较简洁明了。
- C 风格字符串:初始化通常需要使用字符数组初始化语法或者使用 strcpy 等函数进行复制。赋值操作一般使用 strcpy 或 strncpy 等函数,但需要确保目标字符数组有足够的空间容纳源字符串。
 
五、可变性
 -  std::string :可以方便地修改其中的字符内容。例如,可以直接通过下标访问和修改单个字符。
- C 风格字符串:如果是字符数组常量(如 char str[] = "Hello"; ),存储在只读内存区域,不能修改其内容。如果是动态分配的字符数组,可以修改其内容,但需要小心操作以避免越界。

2.2 copy()

copy()用来将字符串的内容复制到字符串数组中,但不自动添加空字符‘\0’。

(1)函数原型 

size_t copy (char* s, size_t len, size_t pos = 0) const;

- s:目标字符数组

- len:要复制的字符数量。

- pos:从字符串的哪个位置开始复制,默认为0.

- const:表示该函数不会修改调用它的字符串对象(即whis指针所指的对象)

(2)示例代码 

#include <iostream>
using namespace std;

int main()
{
	string s1 = "Hello, henu";
	char s2[20];

	s1.copy(s2, 5, 7);

	s2[5] = '\0';

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

2.3 substr()

substr()用来提取从指定位置开始的子字符串

(1)函数原型

string substr (size_t pos = 0, size_t len = npos) const;

- pos:字符串起始位置,默认为0

- len:子字符串的长度,默认为字符串的剩余部分 。

- const:表示该函数不会修改调用它的字符串对象(即whis指针所指的对象)

2)示例代码

#include <iostream>
using namespace std;

int main()
{
	string s1 = "Hello";
	string s2;
	string s3;

	s2 = s1.substr(1, 3);
	s3 = s1.substr();

	cout << s2 << endl;//ell
	cout << s3 << endl;//Hello
	return 0;
}

2.4 find()与rfind()

2.4.1 find()

- find()用来查找字符串中指定字符串第一次出现的位置。如果未找到,则返回std::string::npos,

- rfind()用于在字符串中查找最后一次出现指定字符串的位置。返回值是找到子串的起始位置如果未找到,则返回npos。 

(1)函数原型

string (1)	
size_t find (const string& str, size_t pos = 0) const noexcept;
c-string (2)	
size_t find (const char* s, size_t pos = 0) const;
buffer (3)	
size_t find (const char* s, size_t pos, size_type n) const;
character (4)	
size_t find (char c, size_t pos = 0) const noexcept;
string (1)	
size_t rfind (const string& str, size_t pos = npos) const;
c-string (2)	
size_t rfind (const char* s, size_t pos = npos) const;
buffer (3)	
size_t rfind (const char* s, size_t pos, size_t n) const;
character (4)	
size_t rfind (char c, size_t pos = npos) const;

find从指定位置往后查找,rfind从指定位置往前查找 

(2)深入解析 

1.查找字符串

size_t find (const string& str, size_t pos = 0) const;
size_t rfind (const string& str, size_t pos = npos) const;
//pos = npos默认查找整个字符串

返回值是size_t,表示找到的位置索引。返回std::string::npos,这是一个特殊值,表示失败。

#include <iostream>
using namespace std;

int main()
{
	string s1 = "Hello, World! World!";
	string s2 = "World!";

	size_t pos1 = s1.find(s2);//查找W第一次出现的位置
	size_t pos2 = s1.rfind(s2);//查找W最后一次出现的位置

	if (pos1 == string::npos)
	{
		cout << "没找到" << endl;
	}
	else
	{
		cout << "找到了, 索引是" << pos1 << endl;//输出7
	}
	if (pos2 == string::npos)
	{
		cout << "没找到" << endl;
	}
	else
	{
		cout << "找到了, 索引是" << pos2 << endl;//输出14
	}

	return 0;
}

 2.查找c风格字符串

size_t find (const char* s, size_t pos = 0) const;
size_t rfind (const char* s, size_t pos = 0) const;
//pos = npos默认查找整个字符串
#include <iostream>
using namespace std;

int main()
{
	string s1 = "Hello, World!World!";

	size_t pos1 = s1.find("World");
	size_t pos2 = s1.rfind("World");
	if (pos1 == string::npos)
	{
		cout << "没找到" << endl;
	}
	else
	{
		cout << "找到了,索引是" << pos1 << endl;//7
	}
	if (pos2 == string::npos)
	{
		cout << "没找到" << endl;
	}
	else
	{
		cout << "找到了,索引是" << pos2 << endl;//13
	}
	return 0;
}

 3.查找字符缓冲区

size_t find (const char* s, size_t pos, size_t n) const;
size_t rfind (const char* s, size_t pos, size_t n) const;
//pos = npos默认查找整个字符串

- s:指向要查找的字符缓冲区的指针,类型为const char*。

- pos:从字符串中的那个位置开始向前查找(可以是npos,表示从末尾查找)。

- n: 要查找的字符缓冲区的前n个字符。

#include <iostream>
using namespace std;

int main()
{
	string s1 = "Hello, World!World!";
	const char* but = "World!";//要查汇的字符缓冲区

	size_t pos1 = s1.find(but, 0, 5);//从位置0开始向后查找缓冲区的前五个字符
	size_t pos2 = s1.rfind(but, string::npos, 5);//从末尾开始向前查找缓冲区的前五个字符
	if (pos1 == string::npos)
	{
		cout << "没找到" << endl;
	}
	else
	{
		cout << "找到了,索引是" << pos1 << endl;//7
	}
	if (pos2 == string::npos)
	{
		cout << "没找到" << endl;
	}
	else
	{
		cout << "找到了,索引是" << pos2 << endl;//13
	}
	return 0;
}

 4.查找单个字符 

size_t find (char c, size_t pos = 0) const;
size_t rfind (char c, size_t pos = 0) const;
//pos = npos默认查找整个字符串
#include <iostream>
using namespace std;

int main()
{
	string s1 = "Hello, World!World!";

	size_t pos1 = s1.find('W');
	size_t pos2 = s1.rfind('W');
	if (pos1 == string::npos)
	{
		cout << "没找到" << endl;
	}
	else
	{
		cout << "找到了,索引是" << pos1 << endl;//7
	}
	if (pos2 == string::npos)
	{
		cout << "没找到" << endl;
	}
	else
	{
		cout << "找到了,索引是" << pos2 << endl;//13
	}
	return 0;
}

2.6 其它成员函数

(1)data()

data用来返回指向存储字符串内容的字符数组的指针。与c_str的不同是返回的指针不是以 `\0` 结尾的。

const char* data() const noexcept;
#include <iostream>
using namespace std;

int main() {
	string str = "Hello, World!";

	// 使用 data() 获取字符串的字符数组
	const char* ptr = str.data();

	cout << ptr << endl;// 输出 "Hello, World!"

	return 0;
}

(2)compare

compare用于比较两个字符串或子字符串的内容。

string (1)	
int compare (const string& str) const noexcept;
substrings (2)	
int compare (size_t pos, size_t len, const string& str) const;
int compare (size_t pos, size_t len, const string& str,
             size_t subpos, size_t sublen) const;
c-string (3)	
int compare (const char* s) const;
int compare (size_t pos, size_t len, const char* s) const;
buffer (4)	
int compare (size_t pos, size_t len, const char* s, size_t n) const;

返回一个整数值,负值表示当前字符串小于str,0表示当前字符串等于str,正值表示当前字符串大于str。

#include <iostream>
using namespace std;
int main()
{
    string str1("green apple");
    string str2("red apple");
    string str3("apple");

    if (str1.compare(str2) != 0)//比较两个字符串
        cout << str1 << " is not " << str2 << endl;

    if (str1.compare(6, 5, str3) == 0)//索引6之后的五个字符串与s3相比
        cout << str1 << " is an apple\n";


    if (str2.compare(str2.size() - 5, 5, "apple") == 0)
        cout << "and " << str2 << " is also an apple\n";

    if (str1.compare(6, 5, str2, 4, 5) == 0)
        //索引6之后的五个字符串与s2索引为4后的五个字符串相比
        cout << "therefore, both are apples\n";

    return 0;
}

 

(3)get_aooocator

std::string::get_allocator用于返回 std::allocator<char> 类型的对象。这个对象是用于管理字符串分配和释放内存的分配器。

​allocator_type get_allocator() const noexcept;
#include <iostream>
using namespace std;

int main() {
	string str = "Hello, World!";
	allocator<char> alloc = str.get_allocator();

	// 使用返回的 allocator 分配内存
	char* buffer = alloc.allocate(20);

	// 分配的内存可以用于存储数据
	for (int i = 0; i < 12; ++i) 
	{
		buffer[i] = str[i];
	}

	buffer[12] = '\0'; // 添加字符串终止符

	cout << buffer << endl;

	// 使用 allocator 释放内存
	alloc.deallocate(buffer, 20);

	return 0;
}

在这个示例中,get_allocator 返回的 allocator 对象被用来分配和释放字符数组的内存,这与字符串的内存管理方式相同。

(4)find_first_of与find_last_of

它用于在字符串中查找指定字符中任意一个字符第一次出现的位置

string (1)	
size_t find_first_of (const string& str, size_t pos = 0) const noexcept;
c-string (2)	
size_t find_first_of (const char* s, size_t pos = 0) const;
buffer (3)	
size_t find_first_of (const char* s, size_t pos, size_t n) const;
character (4)	
size_t find_first_of (char c, size_t pos = 0) const noexcept;

 - pos:从字符串中开始查找的起始位置(默认为 0)。该函数返回找到的第一个字符的索引。如果没有找到任何指定的字符,则返回std::string::npos,这是一个常量,表示没有有效位置。 

string (1)	
size_t find_last_of (const string& str, size_t pos = npos) const noexcept;
c-string (2)	
size_t find_last_of (const char* s, size_t pos = npos) const;
buffer (3)	
size_t find_last_of (const char* s, size_t pos, size_t n) const;
character (4)	
size_t find_last_of (char c, size_t pos = npos) const noexcept;

pos:从字符串的指定位置开始向前查找(默认为std::string::npos,表示从字符串的末尾开始查找)。该函数返回找到的第一个字符的索引。如果没有找到任何指定的字符,则返回std::string::npos,这是一个常量,表示没有有效位置。 

#include <iostream>
using namespace std;

int main()
{
	string str1 = "Hello, World";
	string str2 = "World";

	size_t pos1 = str1.find_first_of(str2);
	size_t pos2 = str1.find_first_of("Wd");
	size_t pos3 = str1.find_first_of("World", 0, 5);
	size_t pos4 = str1.find_first_of('o');

	cout << pos1 << endl;//2,str2中的'l'第一次出现在索引为2处
	cout << pos2 << endl;//7,'Wd'中的'W'第一次出现在索引为7处
	cout << pos3 << endl;//2
	cout << pos4 << endl;//4

	return 0;
}
#include <iostream>
using namespace std;

int main()
{
	string str1 = "Hello, World";
	string str2 = "World";

	size_t pos1 = str1.find_last_of(str2);
	size_t pos2 = str1.find_last_of("He");
	size_t pos3 = str1.find_last_of("World", 0, 5);
	size_t pos4 = str1.find_last_of('o');

	cout << pos1 << endl;//11,str2中的'd'第一次出现在索引为11处
	cout << pos2 << endl;//1,'He'中的'e'第一次出现在索引为1处
	cout << pos3 << endl;//18446744073709551615没有找到
	cout << pos4 << endl;//6

	return 0;
}

 (5)find_first_not_of与find_last_not_of

find_first_not_of​​​​​​​用于查找字符串中第一个不属于指定字符集合的字符的位置(从前往后查找)。find_last_not_of用于查找字符串中最后一个不属于指定字符集合的字符的位置(从后往前查找)。

string (1)	
size_t find_first_not_of (const string& str, size_t pos = 0) const noexcept;
c-string (2)	
size_t find_first_not_of (const char* s, size_t pos = 0) const;
buffer (3)	
size_t find_first_not_of (const char* s, size_t pos, size_t n) const;
character (4)	
size_t find_first_not_of (char c, size_t pos = 0) const noexcept;
string (1)	
size_t find_last_not_of (const string& str, size_t pos = npos) const noexcept;
c-string (2)	
size_t find_last_not_of (const char* s, size_t pos = npos) const;
buffer (3)	
size_t find_last_not_of (const char* s, size_t pos, size_t n) const;
character (4)	
size_t find_last_not_of (char c, size_t pos = npos) const noexcept;

用法同find_first_of和find_last_of类似,不在赘述。

总结

总结:在 C++ 中,std::string 类提供了多种功能强大的成员函数,使字符串处理变得灵活、高效。通过这些操作函数,开发者能够对字符串进行查找、替换、获取子串、内存管理等多种操作,极大地提升了开发效率。以下是一些重要的操作函数总结:

- c_str:c_str() 和 data() 函数提供了字符串的 C 风格字符数组等效形式。这在需要与 C 风格字符串或其他库进行交互时非常实用。

- initializer list 替换:replace 函数可以使用初始化列表对字符串中的某个范围进行替换。这种操作在处理特定范围的修改时非常有用。
  

- copy:通过 copy 函数可以将字符串的一部分复制到字符数组中,适用于需要操作原始字符数据的场景。

- get_allocator:该函数返回用于管理 std::string 内存的分配器,便于自定义内存管理。

- 查找功能:
  - find:查找字符串中某内容首次出现的位置。
  - rfind:查找字符串中某内容最后一次出现的位置。
  - find_first_of:查找指定字符集中的任意字符第一次出现的位置。
  - find_last_of:从字符串末尾开始查找指定字符集中的任意字符。
  - find_first_not_of:查找第一个不属于指定字符集的字符。
  - find_last_not_of:从末尾开始查找不属于指定字符集的字符。

- 子串操作:substr 函数可以生成字符串的子串,适用于提取特定部分内容。

- 字符串比较:compare 函数提供了灵活的字符串比较功能,用于按字典顺序比较两个字符串。

这些操作函数使 std::string 成为一个强大的工具,能够处理从简单字符串操作到复杂的字符串匹配、替换等任务。掌握这些函数可以帮助开发者编写出高效、健壮的字符串处理代码。在实际开发中,这些函数的组合应用能够显著提高代码的灵活性和可读性。

 更多string成员函数:string::find - C++ Reference (cplusplus.com)


http://www.niftyadmin.cn/n/5681605.html

相关文章

测试用例的举例

1. 基于测试公式设计测试用例 通过功能&#xff0c;性能&#xff0c;安全性&#xff0c;界面&#xff0c;安全性&#xff0c;易用&#xff0c;兼容对于一个水杯进行测试用例的设计&#xff1b; 对于一个软件的测试用例设计&#xff1a; 功能&#xff1a;软件本质上能够用来干什…

OpenHarmony(鸿蒙南向)——平台驱动开发【PIN】

往期知识点记录&#xff1a; 鸿蒙&#xff08;HarmonyOS&#xff09;应用层开发&#xff08;北向&#xff09;知识点汇总 鸿蒙&#xff08;OpenHarmony&#xff09;南向开发保姆级知识点汇总~ 持续更新中…… 概述 功能简介 PIN即管脚控制器&#xff0c;用于统一管理各SoC的…

HuggingFists数据服务发布--功能闭环

最近&#xff0c;HuggingFists隆重推出了新的功能模块-“数据服务”模块。该模块可以有效的解决HuggingFists算子能力不足时的扩展问题。 现实世界中&#xff0c;不管是在互联网还是组织内部的私有网络中&#xff0c;都存在着大量以Web API的形式对外开放的特有、特色功能。这些…

基于两分支卷积和 Transformer 的轻量级多尺度特征融合超分辨率网络 !

当前的单图像超分辨率&#xff08;SISR&#xff09;算法有两种主要的深度学习模型&#xff0c;一种是基于卷积神经网络&#xff08;CNN&#xff09;的模型&#xff0c;另一种是基于Transformer的模型。前者利用不同卷积核大小的卷积层堆叠来设计模型&#xff0c;使得模型能够更…

快速实现AI搜索!Fivetran 支持 Milvus 作为数据迁移目标

Fivetran 现已支持 Milvus 向量数据库作为数据迁移的目标&#xff0c;能够有效简化 RAG 应用和 AI 搜索中数据源接入的流程。 数据是 AI 应用的支柱&#xff0c;无缝连接数据是充分释放数据潜力的关键。非结构化数据对于企业搜索和检索增强生成&#xff08;RAG&#xff09;聊天…

如何在 Three.js 场景中创建可点击展开的标签

在复杂的可视化场景中&#xff0c;经常需要为 3D 对象添加可交互的标签&#xff0c;以便用户点击时可以查看详细信息。这篇文章将通过一个简单的案例展示&#xff0c;如何在 Three.js 中为对象创建可点击的标签&#xff0c;点击标签可以展开详细信息&#xff0c;再次点击可以关…

vue框架学习 -- 日历控件 FullCalendar 使用总结

最近在项目中要实现日期排班的功能&#xff0c;正好要用到日历视图的控件&#xff0c;经过对比发现&#xff0c;vue 中 使用 FullCalendar 可以实现相关需求&#xff0c;下面对使用过程做一个总结。 一. 引入 FullCalendar 控件 package.json 中添加相关依赖 "dependen…

AI与大数据的结合:如何从海量数据中提取价值

引言 在当今数字化时代&#xff0c;数据如同新石油&#xff0c;成为推动社会与商业进步的重要资源。随着物联网、社交媒体和企业运营中数据生成的激增&#xff0c;我们正处在一个数据爆炸的时代。然而&#xff0c;面对海量且复杂的数据信息&#xff0c;仅依靠传统的分析方法已经…