完整教程:【C++】string类

news/2025/10/20 15:41:19/文章来源:https://www.cnblogs.com/ljbguanli/p/19152792

完整教程:【C++】string类

C++ string 类全面解析

1. 为什么学习 string 类?

1.1 C语言中的字符串局限性

在C语言中,字符串是以\0结尾的字符数组,这种表示方式存在几个明显的缺陷:

C语言字符串的主要问题:

  • 安全性问题:容易发生缓冲区溢出,导致程序崩溃或安全漏洞
  • 内存管理复杂:需要手动管理内存分配和释放,容易造成内存泄漏
  • 功能有限:标准库函数功能相对基础,复杂的字符串操作需要自行实现
  • 不符合面向对象思想:数据与操作分离,不符合现代编程范式
// C语言字符串操作的典型问题
char str[10];
strcpy(str, "这个字符串太长了会导致溢出");  // 潜在的安全风险

1.2 实际应用需求

在现代编程中,字符串处理占据了极大的比重。无论是Web开发、数据处理还是系统编程,都离不开高效的字符串操作。string类的出现正是为了解决C语言字符串的种种痛点。

面试题示例(后续详解):

  • 字符串转整型数字
  • 大数相加(字符串形式)

实践建议:在OJ题目和实际开发中,string类已成为字符串处理的首选工具,相比C字符串库函数更加安全高效。

2. 标准库中的string类

2.1 string类基础

string类是C++标准库中用于表示和操作字符串的类,封装了字符串的存储和常见操作。

基本用法:

#include <string>#include <iostream>using namespace std;int main() {string s1;              // 空字符串string s2 = "Hello";    // 直接初始化string s3("World");     // 构造函数初始化return 0;}

2.2 C++11新特性:auto和范围for

auto关键字详解

auto是C++11引入的类型推断关键字,让编译器自动推导变量类型。

auto的使用规则:

#include <iostream>#include <map>#include <string>using namespace std;int main() {// 基本类型推断auto a = 10;           // intauto b = 3.14;         // doubleauto c = 'A';          // char// 指针和引用int x = 100;auto y = &x;           // int*auto* z = &x;          // int* (与上面等价)auto& ref = x;         // int&// 容器迭代器简化map<string, string> dict = {{"apple", "苹果"}, {"banana", "香蕉"}};// 传统写法(冗长)map<string, string>::iterator it1 = dict.begin();// auto写法(简洁)auto it2 = dict.begin();// 遍历mapfor (auto it = dict.begin(); it != dict.end(); ++it) {cout << it->first << ": " << it->second << endl;}return 0;}

auto的限制:

  • 必须初始化:auto x; // 错误
  • 多变量声明必须类型一致:auto a=1, b=2.0; // 错误
  • 不能用于函数参数(但可以用于返回值)
  • 不能声明数组:auto arr[] = {1,2,3}; // 错误
范围for循环(Range-based for loop)

范围for提供了更简洁的遍历语法,特别适合容器遍历。

#include <iostream>#include <vector>#include <string>using namespace std;int main() {// 数组遍历int arr[] = {1, 2, 3, 4, 5};// 传统遍历方式for (int i = 0; i < sizeof(arr)/sizeof(arr[0]); ++i) {cout << arr[i] << " ";}cout << endl;// 范围for遍历(只读)for (auto elem : arr) {cout << elem << " ";}cout << endl;// 范围for遍历(可修改)for (auto& elem : arr) {elem *= 2;  // 修改元素}// 字符串遍历string str = "Hello";for (auto ch : str) {cout << ch << " ";}cout << endl;return 0;}

范围for的底层原理:编译器会将范围for转换为基于迭代器的普通循环。

2.3 string类常用接口详解

2.3.1 构造函数
构造函数功能说明示例
string()创建空字符串string s1;
string(const char* s)用C字符串构造string s2("hello");
string(size_t n, char c)n个字符c组成的字符串string s3(5, 'A'); // "AAAAA"
string(const string& str)拷贝构造string s4(s2);
void testConstructors() {
string s1;                    // 空字符串
string s2("Hello World");     // 从C字符串构造
string s3(s2);                // 拷贝构造
string s4(10, '*');           // "**********"
string s5 = "直接赋值";        // 赋值初始化
cout << "s2: " << s2 << endl;
cout << "s4: " << s4 << endl;
}
2.3.2 容量操作

重要容量方法:

方法功能说明
size()/length()返回字符串长度两者功能相同,推荐size()
capacity()返回分配的内存大小通常 ≥ size()
empty()判断是否为空空返回true,否则false
clear()清空内容不释放内存,size=0
reserve(size_t n)预留空间避免频繁重新分配
resize(size_t n, char c)调整大小多出部分用c填充
void testCapacity() {
string str = "Hello";
cout << "长度: " << str.size() << endl;        // 5
cout << "容量: " << str.capacity() << endl;    // 15(编译器相关)
cout << "是否为空: " << str.empty() << endl;   // 0(false)
str.resize(10, '!');
cout << "调整后: " << str << endl;             // "Hello!!!!!"
str.reserve(100);
cout << "预留后容量: " << str.capacity() << endl;
str.clear();
cout << "清空后长度: " << str.size() << endl;  // 0
}

resize()详解:

string s = "Hello";
s.resize(3);        // "Hel"(截断)
s.resize(8, '!');   // "Hel!!!!!"(扩展并填充)
s.resize(10);       // "Hel!!!!!  "(扩展,默认填充空格)
2.3.3 元素访问和遍历

多种遍历方式:

void testTraversal() {
string str = "ABCDE";
// 1. 下标操作符[]
for (size_t i = 0; i < str.size(); ++i) {
cout << str[i] << " ";  // A B C D E
}
cout << endl;
// 2. 迭代器
for (auto it = str.begin(); it != str.end(); ++it) {
cout << *it << " ";     // A B C D E
}
cout << endl;
// 3. 反向迭代器
for (auto rit = str.rbegin(); rit != str.rend(); ++rit) {
cout << *rit << " ";    // E D C B A
}
cout << endl;
// 4. 范围for(推荐)
for (auto ch : str) {
cout << ch << " ";      // A B C D E
}
cout << endl;
}
2.3.4 修改操作

常用修改方法:

方法功能示例
push_back(char c)尾部添加字符str.push_back('!')
append(const string& str)追加字符串str.append(" World")
operator+=追加(最常用)str += "!!"
insert(size_t pos, const string& str)插入字符串str.insert(5, "插入")
erase(size_t pos, size_t len)删除子串str.erase(5, 2)
replace(size_t pos, size_t len, const string& str)替换子串str.replace(0, 5, "Hi")
void testModification() {
string str = "Hello";
// 追加操作
str.push_back('!');         // "Hello!"
str.append(" World");       // "Hello! World"
str += "!!";                // "Hello! World!!"(最常用)
// 插入和删除
str.insert(6, "C++ ");      // "Hello! C++ World!!"
str.erase(0, 7);            // "C++ World!!"
str.replace(4, 5, "String"); // "C++ String!!"
cout << "最终结果: " << str << endl;
}
2.3.5 字符串操作

查找和子串操作:

void testStringOperations() {
string str = "Hello World, Hello C++";
// 查找操作
size_t pos1 = str.find("Hello");     // 0
size_t pos2 = str.find("Hello", 1);  // 13(从位置1开始找)
size_t pos3 = str.rfind("Hello");    // 13(从后往前找)
// 子串提取
string sub1 = str.substr(6, 5);      // "World"
string sub2 = str.substr(6);         // "World, Hello C++"
// 比较操作
string s1 = "apple", s2 = "banana";
int result = s1.compare(s2);         // 负数(apple < banana)
cout << "find结果: " << pos1 << ", " << pos2 << ", " << pos3 << endl;
cout << "子串: " << sub1 << ", " << sub2 << endl;
}

2.4 不同编译器下的string实现

VS下的string实现(小字符串优化)

Visual Studio采用小字符串优化(SSO)策略:

内存布局(32位平台):

优势:短字符串无需堆分配,提高性能。

// VS中小字符串优化的效果
string shortStr = "short";    // 使用内部缓冲区(栈)
string longStr = "这是一个很长的字符串...";  // 使用堆分配
g++下的string实现(写时拷贝)

g++采用写时拷贝(Copy-On-Write)技术:

内存布局:

  • 4字节指针:指向堆上的结构体
  • 结构体包含:长度、容量、引用计数、字符串数据

优势:拷贝时不立即复制数据,提高拷贝效率。

// g++中的写时拷贝
string s1 = "hello";
string s2 = s1;  // 不复制数据,只增加引用计数
s2[0] = 'H';     // 此时才真正复制数据(写时拷贝)

2.5 实战练习

示例1:仅反转字母
class Solution {
public:
bool isLetter(char ch) {
return (ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z');}string reverseOnlyLetters(string s) {if (s.empty()) return s;int left = 0, right = s.size() - 1;while (left < right) {// 找到左边的字母while (left < right && !isLetter(s[left])) ++left;// 找到右边的字母while (left < right && !isLetter(s[right])) --right;// 交换字母if (left < right) {swap(s[left], s[right]);++left;--right;}}return s;}};
示例2:字符串相加(大数加法)
class Solution {
public:
string addStrings(string num1, string num2) {
int i = num1.size() - 1, j = num2.size() - 1;
int carry = 0;
string result;
while (i >= 0 || j >= 0 || carry > 0) {
int digit1 = (i >= 0) ? num1[i--] - '0' : 0;
int digit2 = (j >= 0) ? num2[j--] - '0' : 0;
int sum = digit1 + digit2 + carry;
carry = sum / 10;
result.push_back('0' + (sum % 10));
}
reverse(result.begin(), result.end());
return result;
}
};
示例三:字符串最后一个单词的长度

在这里插入图片描述

#include <iostream>using namespace std;int main() {string s;getline(cin,s);//这里不能用流提取。流提取识别不了空格size_t pos=s.rfind(' ');cout<<s.size()-(pos+1)<<endl;}

在这里插入图片描述

getlin默认三个参数,输入两个时,默认最后一个是空

3. string类的模拟实现

3.1 浅拷贝问题

浅拷贝的危险性:

// 有问题的String类实现
class String {
public:
String(const char* str = "") {
_str = new char[strlen(str) + 1];
strcpy(_str, str);
}
~String() {
delete[] _str;
}
private:
char* _str;
};
void testProblem() {
String s1("hello");
String s2(s1);  // 浅拷贝:s1和s2指向同一内存
// 析构时:同一内存被删除两次 → 程序崩溃
}

3.2 深拷贝实现

传统版String类
class String {
public:
// 构造函数
String(const char* str = "") {
if (str == nullptr) str = "";
_str = new char[strlen(str) + 1];
strcpy(_str, str);
}
// 拷贝构造函数(深拷贝)
String(const String& other) {
_str = new char[strlen(other._str) + 1];
strcpy(_str, other._str);
}
// 赋值运算符重载
String& operator=(const String& other) {
if (this != &other) {  // 防止自赋值
char* temp = new char[strlen(other._str) + 1];
strcpy(temp, other._str);
delete[] _str;     // 释放原有资源
_str = temp;
}
return *this;
}
// 析构函数
~String() {
delete[] _str;
}
private:
char* _str;
};
现代版String类(更优雅)
class String {
public:
String(const char* str = "") {
if (str == nullptr) str = "";
_str = new char[strlen(str) + 1];
strcpy(_str, str);
}
// 拷贝构造函数:利用临时对象交换
String(const String& other) : _str(nullptr) {
String temp(other._str);  // 用C字符串构造临时对象
swap(_str, temp._str);    // 交换资源
}
// 赋值运算符:参数为值传递,利用交换技术
String& operator=(String other) {  // 注意:参数为值传递
swap(_str, other._str);       // 交换资源
return *this;                 // other析构时会释放原有资源
}
~String() {
delete[] _str;
}
private:
char* _str;
};

3.3 写时拷贝(Copy-On-Write)

写时拷贝是一种优化技术,在读取时共享数据,在修改时才进行实际拷贝。

基本原理:

  1. 多个对象共享同一数据
  2. 引用计数跟踪共享者数量
  3. 当有修改操作时,才进行实际拷贝
// 简化的写时拷贝实现
class CowString {
private:
struct StringData {
char* data;
int refCount;  // 引用计数
StringData(const char* str) {
data = new char[strlen(str) + 1];
strcpy(data, str);
refCount = 1;
}
~StringData() {
delete[] data;
}
};
StringData* _data;
public:
// 实现细节略...
};

4. 最佳实践和性能建议

4.1 字符串操作优化

// 不推荐的写法(性能差)
string result;
for (int i = 0; i < 1000; ++i) {
result += "data";  // 可能多次重新分配内存
}
// 推荐的写法
string result;
result.reserve(5000);  // 预先分配足够空间
for (int i = 0; i < 1000; ++i) {
result += "data";  // 无重新分配
}

4.2 选择合适的方法

string str = "hello";
// 尾部添加字符的三种方式
str.push_back('!');     // 方式1
str.append(1, '!');     // 方式2  
str += '!';             // 方式3(最常用)
// 查找操作选择
size_t pos1 = str.find('e');      // 查找字符
size_t pos2 = str.find("ll");     // 查找子串
size_t pos3 = str.rfind('l');     // 反向查找

5. 总结

string类是C++中最重要的工具类之一,它:

  1. 解决了C字符串的安全性问题:自动内存管理,防止缓冲区溢出
  2. 提供了丰富的操作方法:查找、替换、分割等常用操作一应俱全
  3. 具有高效的实现:小字符串优化、写时拷贝等技术提升性能

推荐的写法

string result;
result.reserve(5000);  // 预先分配足够空间
for (int i = 0; i < 1000; ++i) {
result += "data";  // 无重新分配
}

4.2 选择合适的方法

string str = "hello";
// 尾部添加字符的三种方式
str.push_back('!');     // 方式1
str.append(1, '!');     // 方式2  
str += '!';             // 方式3(最常用)
// 查找操作选择
size_t pos1 = str.find('e');      // 查找字符
size_t pos2 = str.find("ll");     // 查找子串
size_t pos3 = str.rfind('l');     // 反向查找

5. 总结

string类是C++中最重要的工具类之一,它:

  1. 解决了C字符串的安全性问题:自动内存管理,防止缓冲区溢出
  2. 提供了丰富的操作方法:查找、替换、分割等常用操作一应俱全
  3. 具有高效的实现:小字符串优化、写时拷贝等技术提升性能
  4. 支持现代C++特性:与STL算法、范围for等完美配合

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/941267.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

2025年农机带厂家权威推荐榜:旋耕机带、收割机带、拖拉机带,耐磨耐用传动带源头厂家精选

2025年农机带厂家权威推荐榜:旋耕机带、收割机带、拖拉机带,耐磨耐用传动带源头厂家精选 随着农业机械化水平的持续提升,农机传动带作为关键零部件,其性能直接影响农业机械的工作效率和可靠性。在旋耕、收割、耕作…

2025年实验室/手术室净化工程厂家推荐排行榜:涵盖无尘车间装修、洁净室建设、医院净化工程等全方位解决方案精选

2025年实验室/手术室净化工程厂家推荐排行榜:涵盖无尘车间装修、洁净室建设、医院净化工程等全方位解决方案精选 在当今科技飞速发展的时代,实验室净化、手术室净化、无尘车间建设等洁净环境工程已成为医疗健康、生物…

2025 石家庄全屋定制工厂推荐:河北森佰特木业,莫兰迪色系/工业风/意式/意式极简/中古风/侘寂风/现代简约/北欧风/奶油胡桃色全屋定制等风格任你选

随着居民生活品质提升、家居审美多元化及个性化居住需求增加,全屋定制已从高端家居消费选择逐步普及至普通家庭,覆盖新中式、意式、现代简约等多种风格,2025 年市场规模预计持续扩大。但市场增长也带来厂商设计能力…

详细介绍:网络安全防御指南:全方位抵御暴力破解攻击

pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", "Monaco", "Courier New", …

【ACM独立出版|EI稳定】第二届云计算与大数据国际学术会议(ICCBD 2025)

ICCBD 2025旨在深入分析云计算与大数据技术的最新发展趋势,探讨其在经济社会数字化进程中的重要作用,以及面临的挑战与机遇。会议为从事研究的专家、学者、工程师和技术人员提供一个国际平台,分享科研成果和尖端技术…

机器学习周报十五 - 教程

机器学习周报十五 - 教程pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", "Monaco", &q…

完整教程:【LeetCode 每日一题】2221. 数组的三角和

完整教程:【LeetCode 每日一题】2221. 数组的三角和pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas&quo…

软件设计中的需求分析——白日梦

对于我们在日常项目开发中,需求分析通常是一个在整个设计阶段处于一个举足轻重的地位, 在进行心理咨询APP端的开发和老师上课的项目成果第一阶段演示的过程中,要学会做白日梦 所谓的白日梦是我们需要去具体和客户进…

包装工位连接断开,终检产品无法进入包装

包装工位连接断开,终检产品无法进入包装在设置了COP规则的产线,如果发生包装工位连接断开,终检产品无法进入包装,问题在于某站的产品KANBAN没有选。 如下图 查询 select * from t_contex where datemodif=20241012…

2025年苹果仓厂家权威推荐榜单:苹果仓民宿,移动房苹果仓,出口苹果仓,外贸出口苹果仓,集装箱苹果仓,景区苹果仓,苹果仓房屋,网红苹果仓,可移动式苹果仓公司推荐

2025年苹果仓厂家权威推荐榜单:苹果仓民宿,移动房苹果仓,出口苹果仓,外贸出口苹果仓,集装箱苹果仓,景区苹果仓,苹果仓房屋,网红苹果仓,可移动式苹果仓公司推荐 随着模块化建筑理念的深入发展,苹果仓作为一种…

实时物化视图的新路径:从传统 Join 到跨源实时查询

探索为什么传统 join 架构在多源环境中效率低下,以及 TapData 如何通过跨源 CDC 与实时增量物化视图,实现秒级数据整合与统一查询,帮助企业快速构建实时数据层。在关系型数据库的世界里,join 是数据建模和查询优化…

2025年拉链厂家权威推荐榜:TAB拉链,大棕拉链,金属/树脂拉链,服装/尼龙拉链,防水/隐形拉链,男装/女装拉链源头精选

2025年拉链厂家权威推荐榜:TAB拉链,大棕拉链,金属/树脂拉链,服装/尼龙拉链,防水/隐形拉链,男装/女装拉链源头精选 在服装辅料行业快速发展的今天,拉链作为重要的功能性配件,其品质直接影响着服装的整体表现。随…

多轮对话中,如何判断前后两次提问是否存在依赖关系

这是一个非常关键且具有挑战性的问题,无论是在构建AI应用还是在进行人机交互研究时都至关重要。 判断多轮对话中前后提问是否存在依赖关系,通常需要一个综合的策略,结合了规则、语义理解和上下文分析。以下是详细的…

基于SpringBoot的课程信息管理系统设计与实现 - 实践

基于SpringBoot的课程信息管理系统设计与实现 - 实践pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas&quo…

2025年全自动智能点胶机厂家推荐排行榜:饰品/纽扣/拉链头/商标/钥匙扣/五金/徽章视觉定位UV胶点胶设备精选

2025年全自动智能点胶机厂家推荐排行榜:饰品/纽扣/拉链头/商标/钥匙扣/五金/徽章视觉定位UV胶点胶设备精选 随着工业4.0时代的深入推进,全自动智能点胶技术正在经历革命性变革。特别是在饰品、纽扣、拉链头、商标、钥…

2025年环氧板厂家推荐排行榜,环氧板加工,FR-4玻纤板,云母板源头厂家专业制造与品质保障

2025年环氧板厂家推荐排行榜:环氧板加工、FR-4玻纤板、云母板源头厂家专业制造与品质保障 在电子电气、航空航天、新能源等高科技产业快速发展的背景下,环氧板、FR-4玻纤板和云母板作为关键绝缘材料,其质量与性能直…

2025 钢制拖链源头厂家最新推荐排行榜:权威甄选优质品牌,破解选型难题助力企业精准采购

在工业自动化与机械制造高速升级的当下,钢制拖链作为保护电缆、油管的 "设备卫士",其结构强度、运行稳定性与环境适配性直接决定设备运维成本与生产连续性。当前市场中,超千家厂家并存导致产品质量两极分…

机器学习可扩展性:从1到百万用户的架构演进

本文详细介绍了机器学习应用从单机部署到服务百万用户的全流程架构演进,涵盖垂直与水平扩展、自动扩缩容、模型重训练、A/B测试等关键技术,帮助构建高可用的生产级机器学习系统。机器学习可扩展性:将模型扩展至服务…

SOSDP

\(\text{SOSDP: Sum over Subsets DP}\) 例子:给定一个序列长度为 \(2^n\) 的序列 \(a\),求对于 \(i = 0,1,\cdots,2^n-1\) 求 \(A_i\),其中 \(A_i = \sum\limits_{j\&i=j}a_j\),即 \(i\) 的子集和。 设 \(f_{…

2025年保洁公司推荐排行榜,驻场保洁/钟点保洁/开荒保洁/外包保洁/商场保洁/办公楼保洁/工厂保洁/医院保洁/企业保洁服务优选指南

2025年保洁公司推荐排行榜:驻场保洁/钟点保洁/开荒保洁/外包保洁/商场保洁/办公楼保洁/工厂保洁/医院保洁/企业保洁服务优选指南 随着现代商业环境的不断发展,专业保洁服务已成为各类机构日常运营中不可或缺的一环。…