【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++语言旅途中有所帮助!

相关文章
|
1天前
|
存储 搜索推荐 C++
【C++篇】深度剖析C++ STL:玩转 list 容器,解锁高效编程的秘密武器2
【C++篇】深度剖析C++ STL:玩转 list 容器,解锁高效编程的秘密武器
21 2
【C++篇】深度剖析C++ STL:玩转 list 容器,解锁高效编程的秘密武器2
|
1天前
|
存储 算法 C++
C++ STL 初探:打开标准模板库的大门
C++ STL 初探:打开标准模板库的大门
35 9
|
1天前
|
安全 测试技术 C++
【C++篇】从零实现 C++ Vector:深度剖析 STL 的核心机制与优化2
【C++篇】从零实现 C++ Vector:深度剖析 STL 的核心机制与优化
18 6
|
1天前
|
安全 测试技术 C++
【C++篇】从零实现 C++ Vector:深度剖析 STL 的核心机制与优化1
【C++篇】从零实现 C++ Vector:深度剖析 STL 的核心机制与优化
18 7
|
1天前
|
存储 C++ 容器
【C++篇】深度剖析C++ STL:玩转 list 容器,解锁高效编程的秘密武器1
【C++篇】深度剖析C++ STL:玩转 list 容器,解锁高效编程的秘密武器
23 5
|
1天前
|
安全 C语言 C++
【C++篇】探寻C++ STL之美:从string类的基础到高级操作的全面解析
【C++篇】探寻C++ STL之美:从string类的基础到高级操作的全面解析
18 4
|
1天前
|
编译器 C语言 C++
【C++篇】解密 STL 动态之魂:全面掌握 C++ vector 的高效与优雅
【C++篇】解密 STL 动态之魂:全面掌握 C++ vector 的高效与优雅
17 3
|
1天前
|
存储 编译器 C++
【C++篇】揭开 C++ STL list 容器的神秘面纱:从底层设计到高效应用的全景解析(附源码)
【C++篇】揭开 C++ STL list 容器的神秘面纱:从底层设计到高效应用的全景解析(附源码)
18 2
|
1天前
|
存储 编译器 程序员
【C++篇】手撕 C++ string 类:从零实现到深入剖析的模拟之路
【C++篇】手撕 C++ string 类:从零实现到深入剖析的模拟之路
17 2
|
1天前
|
C++
【C++】C++ STL 探索:List使用与背后底层逻辑(三)
【C++】C++ STL 探索:List使用与背后底层逻辑