【C++】C++ STL 探索:String的使用与理解(三)

简介: 【C++】C++ STL 探索:String的使用与理解

【C++】C++ STL 探索:String的使用与理解(二)https://developer.aliyun.com/article/1617332


7.9 关于replace与find配合使用

(面试题 01.03. URL化 - 力扣(LeetCode)

int main()
{
  string str1("I am a cold boy");
  size_t pos = str1.find(' ');
  while (pos != string::npos)//直到空格替换完
  {
    str1.replace(pos, 1, "%20");
    pos = str1.find(' ');
  }
  cout << str1 << endl;
  return 0;

7.10 rfind

返回值:如果找到相对应的字符或字符串后,rfind会返回该字符或者返回该字符串最后一个字符所在的索引位置;如果没有匹配成功,rfind则会返回npos(-1);

7.10.1 size_t rfind(const char* str, size_t pos = npos) const

int main()
{
  string str1("https://cplusplus.com/reference/string/string/rfind/");
  size_t pos = str1.rfind('/');
  cout << pos << endl;
  return 0;
}

功能:rfind从pos开始位置,向前查找字符串中所需字符所在位置。如果没有指定该pos值,采用缺省值,从字符串最后一位开始

7.10.2 size_t rfind(const c, size_t pos = npos) const

int main()
{
  string str1("https://cplusplus.com/reference/string/string/find/");
  size_t pos = str1.rfind("com");
  cout << pos << endl;
  return 0;
}

功能:rfind从pos开始位置,向前查找字符串中所需字符串所在位置,并返回字符串末尾字符索引位置;如果没有指定该pos值,采用缺省值,从字符串最后一位开始

7.11 substr

int main()
{
  string file("string.cpp");
  size_t pos = file.rfind('.');
  string suffix(file.substr(pos, file.size() - pos));
  cout << suffix << endl;
  return 0;
}

功能:在str中pos位置开始,截取n个字符,然后将其返回。

如果没有给需要截取的字符长度,默认从pos位置截取到字符串末尾位置。通常遵循左闭右开的原则。这意味着它返回的子字符串包括起始索引,但不包括结束索引位置。

7.12 c_str

int main()
{
  string str1("hello world");
  char* p = new char[str1.size() + 1];
  std::strcpy(p, str1.c_str());
  return 0;
}

功能:返回C格式字符串(包括’\0‘)

八、string类非成员函数

**接下来介绍以下函数不属于string类中函数,而是属于全局函数。如果需要使用需要使用对应的头文件。**这里只简单介绍两个函数

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

8.1 relational operator

#include <string>
int main()
{
  string str1("abc");
  string str2("acb");
  
  if (str1 == str2) cout << "str1 and str2 are equal" << endl;
  if (str1 != str2) cout << "str1 and str2 are not equal" << endl;
  //.................................
  return 0;
}

功能:就是大小的比较,重载compare来使用的

8.2 getline

#include <string>
int main()
{
  string name("li hua");
  getline(cin,name);
  cout << name << endl;
}

getline功能:

  1. 从流中得到字符串,解决了读取字符串遇到空格或者换行符终止问题,当然也可以使用getchar完成.
  2. C++ 取不到空格和换行 ,默认为换行和空格是一个分隔符,自动忽略
  3. 在C++中,尽管可以使用C语言中的标准库函数如 getchargetc,但是在纯C++编程中,建议使用C++标准库提供的功能来进行输入操作。

九、VS和GCC下string结构说明

下述结构是32位平台下进行验证,32位平台下指针占4个字节

9.1 VS下string结构

string总共占28个字节,内部结构稍微复杂一点,先是有一个联合体,联合体用来:

  • 当字符串长度小于16时,使用内部固定的字符数组来存放
  • 当字符串长度大于等于16时,从堆上开辟空间
union _Bxty
{   // storage for small buffer or pointer to larger one
    value_type _Buf[_BUF_SIZE];
    pointer _Ptr;
    char _Alias[_BUF_SIZE]; // to permit aliasing
} _Bx;

由于大多数情况下字符串的长度都小于16。当创建好string对象,内部已经有了16个字符数组的固定空间,不需要通过堆创建,效率高。(buff数组优化)

其次还有一个size_t字段保存字符串长度,一个size_t字段保存从堆上开辟空间总的容量。最后还有一个指针做一些其他事情

故总共占16+4+4+4=28个字节。

9.2 GCC下string结构

G++下的,string是通过写时拷贝实现的,string对象总共占4个字节,内部只包含了一个指针,该指针将来指向一块堆空间,内部包含了如下字段:

  • 空间大小
  • 字符串有效长度
  • 引用计数
struct _Rep_base
{
    size_type _M_length;
    size_type _M_capacity;
    _Atomic_word _M_refcount;
};
  • 指向堆空间的指针,用来存放字符串

小内存不用去堆上开,栈开空间比堆块,是在编译时就算好了,成本低。

十、选择String类的理由

在C++编程中,选择 std::string 而不是 C 风格的字符串(C-string,即使用字符数组或指针表示的字符串,如 char*)通常是一个更好的选择。以下是几个关键原因:

  1. 安全性
  • std::string:自动管理内存,避免了手动分配和释放内存的风险,减少了内存泄漏和缓冲区溢出的可能性。
  • -C-string:需要手动管理内存,容易出现缓冲区溢出和内存泄漏问题,尤其是在处理长字符串或动态字符串时。
  1. 简洁性和易用性
  • std::string:提供了丰富的成员函数,如拼接、查找、替换、截取等操作,这些操作使用方便且更符合面向对象的编程风格。
  • -C-string:需要使用标准库函数(如 strcpystrcatstrlen 等)进行操作,语法较为繁琐,不易于阅读和维护。
  1. 动态扩展
  • std::string:自动处理字符串的大小,支持动态扩展,无需担心容量不足问题。
  • -C-string:需要预先定义长度,动态扩展时需要手动重新分配内存,这增加了代码的复杂性和出错的可能性。
  1. 兼容性与集成
  • std::string:与C++标准库和STL容器无缝集成,能够更好地与其他C++标准库组件协同工作。
  • C-string:虽然与C标准库函数兼容,但与C++标准库组件的结合不如 std::string 方便。
  1. 异常处理
  • std::string:如果操作失败,std::string 通常会抛出异常,可以通过捕获异常来处理错误情况,代码更健壮。
  • C-string:C-string操作一般通过返回值或设置错误码来处理失败情况,需要手动检查,容易忽略错误处理。
  1. 性能优化
  • std::string:在现代编译器中,std::string 的实现经过了大量优化,能有效减少不必要的内存拷贝,提高性能。
  • C-string:需要开发者手动进行性能优化,如内存管理、字符串拼接等,容易出错且不易维护。

总结

使用 std::string 可以显著提高代码的安全性、可读性和可维护性,同时减少了手动内存管理带来的复杂性和风险。在现代 C++ 编程中,std::string 已成为处理字符串的首选工具,除非在特定情况下(如需要与 C 代码库兼容)才会选择使用 C-string。


以上就是本篇文章的所有内容,在此感谢大家的观看!这里是店小二呀C++笔记,希望对你在学习C++语言旅途中有所帮助!

相关文章
|
7月前
|
编译器 C++ 容器
【c++丨STL】基于红黑树模拟实现set和map(附源码)
本文基于红黑树的实现,模拟了STL中的`set`和`map`容器。通过封装同一棵红黑树并进行适配修改,实现了两种容器的功能。主要步骤包括:1) 修改红黑树节点结构以支持不同数据类型;2) 使用仿函数适配键值比较逻辑;3) 实现双向迭代器支持遍历操作;4) 封装`insert`、`find`等接口,并为`map`实现`operator[]`。最终,通过测试代码验证了功能的正确性。此实现减少了代码冗余,展示了模板与仿函数的强大灵活性。
176 2
|
8月前
|
存储 安全 C语言
C++ String揭秘:写高效代码的关键
在C++编程中,字符串操作是不可避免的一部分。从简单的字符串拼接到复杂的文本处理,C++的string类为开发者提供了一种更高效、灵活且安全的方式来管理和操作字符串。本文将从基础操作入手,逐步揭开C++ string类的奥秘,帮助你深入理解其内部机制,并学会如何在实际开发中充分发挥其性能和优势。
|
4月前
|
对象存储 C++ 容器
c++的string一键介绍
这篇文章旨在帮助读者回忆如何使用string,并提醒注意事项。它不是一篇详细的功能介绍,而是一篇润色文章。先展示重载函数,如果该函数一笔不可带过,就先展示英文原档(附带翻译),最后展示代码实现与举例可以直接去看英文文档,也可以看本篇文章,但是更建议去看英文原档。那么废话少说直接开始进行挨个介绍。
88 3
|
7月前
|
存储 算法 C++
【c++丨STL】map/multimap的使用
本文详细介绍了STL关联式容器中的`map`和`multimap`的使用方法。`map`基于红黑树实现,内部元素按键自动升序排列,存储键值对,支持通过键访问或修改值;而`multimap`允许存在重复键。文章从构造函数、迭代器、容量接口、元素访问接口、增删操作到其他操作接口全面解析了`map`的功能,并通过实例演示了如何用`map`统计字符串数组中各元素的出现次数。最后对比了`map`与`set`的区别,强调了`map`在处理键值关系时的优势。
344 73
|
8月前
|
存储 缓存 C++
C++ 容器全面剖析:掌握 STL 的奥秘,从入门到高效编程
C++ 标准模板库(STL)提供了一组功能强大的容器类,用于存储和操作数据集合。不同的容器具有独特的特性和应用场景,因此选择合适的容器对于程序的性能和代码的可读性至关重要。对于刚接触 C++ 的开发者来说,了解这些容器的基础知识以及它们的特点是迈向高效编程的重要一步。本文将详细介绍 C++ 常用的容器,包括序列容器(`std::vector`、`std::array`、`std::list`、`std::deque`)、关联容器(`std::set`、`std::map`)和无序容器(`std::unordered_set`、`std::unordered_map`),全面解析它们的特点、用法
C++ 容器全面剖析:掌握 STL 的奥秘,从入门到高效编程
|
7月前
|
存储 算法 C++
【c++丨STL】set/multiset的使用
本文深入解析了STL中的`set`和`multiset`容器,二者均为关联式容器,底层基于红黑树实现。`set`支持唯一性元素存储并自动排序,适用于高效查找场景;`multiset`允许重复元素。两者均具备O(logN)的插入、删除与查找复杂度。文章详细介绍了构造函数、迭代器、容量接口、增删操作(如`insert`、`erase`)、查找统计(如`find`、`count`)及`multiset`特有的区间操作(如`lower_bound`、`upper_bound`、`equal_range`)。最后预告了`map`容器的学习,其作为键值对存储的关联式容器,同样基于红黑树,具有高效操作特性。
282 3
|
8月前
|
C++
模拟实现c++中的string
模拟实现c++中的string
|
8月前
|
存储 算法 C++
【c++丨STL】priority_queue(优先级队列)的使用与模拟实现
本文介绍了STL中的容器适配器`priority_queue`(优先级队列)。`priority_queue`根据严格的弱排序标准设计,确保其第一个元素始终是最大元素。它底层使用堆结构实现,支持大堆和小堆,默认为大堆。常用操作包括构造函数、`empty`、`size`、`top`、`push`、`pop`和`swap`等。我们还模拟实现了`priority_queue`,通过仿函数控制堆的类型,并调用封装容器的接口实现功能。最后,感谢大家的支持与关注。
376 1
|
9月前
|
C++ 容器
【c++丨STL】stack和queue的使用及模拟实现
本文介绍了STL中的两个重要容器适配器:栈(stack)和队列(queue)。容器适配器是在已有容器基础上添加新特性或功能的结构,如栈基于顺序表或链表限制操作实现。文章详细讲解了stack和queue的主要成员函数(empty、size、top/front/back、push/pop、swap),并提供了使用示例和模拟实现代码。通过这些内容,读者可以更好地理解这两种数据结构的工作原理及其实现方法。最后,作者鼓励读者点赞支持。 总结:本文深入浅出地讲解了STL中stack和queue的使用方法及其模拟实现,帮助读者掌握这两种容器适配器的特性和应用场景。
185 21
|
8月前
|
存储 算法 C++
深入浅出 C++ STL:解锁高效编程的秘密武器
C++ 标准模板库(STL)是现代 C++ 的核心部分之一,为开发者提供了丰富的预定义数据结构和算法,极大地提升了编程效率和代码的可读性。理解和掌握 STL 对于 C++ 开发者来说至关重要。以下是对 STL 的详细介绍,涵盖其基础知识、发展历史、核心组件、重要性和学习方法。