【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功能:
- 从流中得到字符串,解决了读取字符串遇到空格或者换行符终止问题,当然也可以使用getchar完成.
- C++ 取不到空格和换行 ,默认为换行和空格是一个分隔符,自动忽略
- 在C++中,尽管可以使用C语言中的标准库函数如
getchar
和getc
,但是在纯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*
)通常是一个更好的选择。以下是几个关键原因:
- 安全性:
std::string
:自动管理内存,避免了手动分配和释放内存的风险,减少了内存泄漏和缓冲区溢出的可能性。- -C-string:需要手动管理内存,容易出现缓冲区溢出和内存泄漏问题,尤其是在处理长字符串或动态字符串时。
- 简洁性和易用性:
std::string
:提供了丰富的成员函数,如拼接、查找、替换、截取等操作,这些操作使用方便且更符合面向对象的编程风格。- -C-string:需要使用标准库函数(如
strcpy
、strcat
、strlen
等)进行操作,语法较为繁琐,不易于阅读和维护。
- 动态扩展:
std::string
:自动处理字符串的大小,支持动态扩展,无需担心容量不足问题。- -C-string:需要预先定义长度,动态扩展时需要手动重新分配内存,这增加了代码的复杂性和出错的可能性。
- 兼容性与集成:
std::string
:与C++标准库和STL容器无缝集成,能够更好地与其他C++标准库组件协同工作。- C-string:虽然与C标准库函数兼容,但与C++标准库组件的结合不如
std::string
方便。
- 异常处理:
std::string
:如果操作失败,std::string
通常会抛出异常,可以通过捕获异常来处理错误情况,代码更健壮。- C-string:C-string操作一般通过返回值或设置错误码来处理失败情况,需要手动检查,容易忽略错误处理。
- 性能优化:
std::string
:在现代编译器中,std::string
的实现经过了大量优化,能有效减少不必要的内存拷贝,提高性能。- C-string:需要开发者手动进行性能优化,如内存管理、字符串拼接等,容易出错且不易维护。
总结
使用 std::string
可以显著提高代码的安全性、可读性和可维护性,同时减少了手动内存管理带来的复杂性和风险。在现代 C++ 编程中,std::string
已成为处理字符串的首选工具,除非在特定情况下(如需要与 C 代码库兼容)才会选择使用 C-string。
以上就是本篇文章的所有内容,在此感谢大家的观看!这里是店小二呀C++笔记,希望对你在学习C++语言旅途中有所帮助!