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

相关文章
|
5天前
|
算法 C语言 C++
【c++丨STL】list的使用
本文介绍了STL容器`list`的使用方法及其主要功能。`list`是一种双向链表结构,适用于频繁的插入和删除操作。文章详细讲解了`list`的构造函数、析构函数、赋值重载、迭代器、容量接口、元素访问接口、增删查改操作以及一些特有的操作接口如`splice`、`remove_if`、`unique`、`merge`、`sort`和`reverse`。通过示例代码,读者可以更好地理解如何使用这些接口。最后,作者总结了`list`的特点和适用场景,并预告了后续关于`list`模拟实现的文章。
22 7
|
23天前
|
存储 编译器 C语言
【c++丨STL】vector的使用
本文介绍了C++ STL中的`vector`容器,包括其基本概念、主要接口及其使用方法。`vector`是一种动态数组,能够根据需要自动调整大小,提供了丰富的操作接口,如增删查改等。文章详细解释了`vector`的构造函数、赋值运算符、容量接口、迭代器接口、元素访问接口以及一些常用的增删操作函数。最后,还展示了如何使用`vector`创建字符串数组,体现了`vector`在实际编程中的灵活性和实用性。
48 4
|
24天前
|
C语言 C++ 容器
【c++丨STL】string模拟实现(附源码)
本文详细介绍了如何模拟实现C++ STL中的`string`类,包括其构造函数、拷贝构造、赋值重载、析构函数等基本功能,以及字符串的插入、删除、查找、比较等操作。文章还展示了如何实现输入输出流操作符,使自定义的`string`类能够方便地与`cin`和`cout`配合使用。通过这些实现,读者不仅能加深对`string`类的理解,还能提升对C++编程技巧的掌握。
50 5
|
24天前
|
存储 编译器 C语言
【c++丨STL】string类的使用
本文介绍了C++中`string`类的基本概念及其主要接口。`string`类在C++标准库中扮演着重要角色,它提供了比C语言中字符串处理函数更丰富、安全和便捷的功能。文章详细讲解了`string`类的构造函数、赋值运算符、容量管理接口、元素访问及遍历方法、字符串修改操作、字符串运算接口、常量成员和非成员函数等内容。通过实例演示了如何使用这些接口进行字符串的创建、修改、查找和比较等操作,帮助读者更好地理解和掌握`string`类的应用。
38 2
|
1月前
|
存储 算法 Linux
【c++】STL简介
本文介绍了C++标准模板库(STL)的基本概念、组成部分及学习方法,强调了STL在提高编程效率和代码复用性方面的重要性。文章详细解析了STL的六大组件:容器、算法、迭代器、仿函数、配接器和空间配置器,并提出了学习STL的三个层次,旨在帮助读者深入理解和掌握STL。
47 0
|
9天前
|
存储 编译器 C语言
【c++丨STL】vector模拟实现
本文深入探讨了 `vector` 的底层实现原理,并尝试模拟实现其结构及常用接口。首先介绍了 `vector` 的底层是动态顺序表,使用三个迭代器(指针)来维护数组,分别为 `start`、`finish` 和 `end_of_storage`。接着详细讲解了如何实现 `vector` 的各种构造函数、析构函数、容量接口、迭代器接口、插入和删除操作等。最后提供了完整的模拟实现代码,帮助读者更好地理解和掌握 `vector` 的实现细节。
18 0
|
2月前
|
存储 程序员 C++
C++常用基础知识—STL库(2)
C++常用基础知识—STL库(2)
79 5
|
2月前
|
存储 安全 C++
【C++打怪之路Lv8】-- string类
【C++打怪之路Lv8】-- string类
26 1
|
2月前
|
存储 自然语言处理 程序员
C++常用基础知识—STL库(1)
C++常用基础知识—STL库(1)
72 1
|
1月前
|
存储 编译器 C++
【c++】类和对象(下)(取地址运算符重载、深究构造函数、类型转换、static修饰成员、友元、内部类、匿名对象)
本文介绍了C++中类和对象的高级特性,包括取地址运算符重载、构造函数的初始化列表、类型转换、static修饰成员、友元、内部类及匿名对象等内容。文章详细解释了每个概念的使用方法和注意事项,帮助读者深入了解C++面向对象编程的核心机制。
83 5