当前位置: 首页 > news >正文

【C++】掌握string类操作:高效处理字符串

1. string 类对象的修改操作

函数名称功能说明
push_back在字符串的末尾插入单个字符 c
append在字符串的末尾追加一个完整的字符串(支持多种参数形式,如const string&、C 风格字符串等)
operator+=(重点)在字符串的末尾追加内容,支持追加单个字符、string对象或 C 风格字符串(语法简洁,如str += "abc")
c_str(重点)返回指向字符串的 C 风格字符数组指针(以'\0'结尾),用于兼容 C 语言接口
find + npos(重点)从字符串的pos位置(默认从 0 开始)向后查找字符或子串,返回第一次出现的位置;若未找到,返回string::npos(一个特殊的静态常量,表示未找到)
rfind从字符串的pos位置(默认从末尾开始)向前查找字符或子串,返回最后一次出现的位置;若未找到,返回string::npos
substr从字符串的pos位置开始,截取n个字符(若n超出剩余字符数,则截取到字符串末尾),返回截取得到的子串

注意:

  1. 在 string 尾部追加字符时,s.push_back(c) / s.append(1, c) / s += 'c'三种的实现方式差不多,一般情况下 string 类的+=操作用的比较多,+=操作不仅可以连接单个字符,还可以连接字符串。

  2. 对 string 操作时,如果能够大概预估到放多少字符,可以先通过 reserve 把空间预留好。

void test1()
{string url("https://cplusplus.com/reference/string/basic_string/substr/");size_t i1 = url.find(":");if (i1 != string::npos){cout << url.substr(0, i1) << endl;}size_t i2 = url.find("/",i1+3);if (i2 != string::npos){cout << url.substr(i1 + 3, i2-(i1+3)) << endl;}cout << url.substr(i2 + 1) << endl;}int main()
{test1();return 0;
}
  • find()用于查找特定字符的位置

  • substr(pos, length)用于截取子字符串,当省略 length 时,会截取从 pos 到字符串末尾的部分

  • string::npos是一个特殊值,表示查找失败(未找到指定字符)

1.1 find() 函数:查找字符 / 子串位置

功能:在字符串中查找指定字符或子串的第一个出现位置。

size_t find(const string& str, size_t pos = 0) const;  // 查找子串str
size_t find(char c, size_t pos = 0) const;              // 查找字符c

参数说明:

  • str/c:要查找的子串或字符。

  • pos(可选):从字符串的第pos个位置开始查找(默认从 0 开始)。

返回值:

  • 找到时:返回匹配的第一个字符的索引位置(size_t类型)。

  • 未找到时:返回string::npos(表示查找失败)。

string s = "hello world";
size_t pos1 = s.find('o');      // 查找字符'o',返回4(第一个'o'在索引4)
size_t pos2 = s.find("world");  // 查找子串"world",返回6
size_t pos3 = s.find('x');      // 未找到,返回string::npos

1.2substr() 函数:截取子字符串

功能:从字符串中截取指定范围的子串。

string substr(size_t pos, size_t count = npos) const;

参数说明:

  • pos:子串的起始位置(必须在字符串范围内,否则会抛出异常)。

  • count(可选):要截取的字符个数。若省略或超过剩余字符数,则截取从pos到字符串末尾的所有字符。

返回值:

  • 截取得到的子串(string类型)。

示例:

string s = "abcdefgh";
string sub1 = s.substr(2, 3);  // 从索引2开始,截取3个字符 → "cde"
string sub2 = s.substr(5);     // 从索引5开始,截取到末尾 → "fgh"
string sub3 = s.substr(3, 10); // 从索引3开始,截取10个字符(实际只有5个)→ "defgh"

1.3 string::npos:表示 “未找到” 或 “到末尾” 的特殊值

本质:string::nposstd::string类的静态成员常量,类型为size_t(无符号整数),通常定义为-1(但由于是无符号类型,实际表示为该类型的最大值)。

作为find()等查找函数的 “未找到” 标志。

if (s.find("test") == string::npos) {cout << "未找到子串" << endl;
}

1.4三者结合的典型用法

通常用find()查找位置,用string::npos判断是否找到,再用substr()截取子串,例如解析 URL 的逻辑:

string url = "https://cplusplus.com/reference/";
size_t pos = url.find("://");  // 查找"://"的位置
if (pos != string::npos) {     // 若找到string protocol = url.substr(0, pos);  // 截取协议部分("https")string rest = url.substr(pos + 3);     // 截取剩余部分("cplusplus.com/...")
}

1.5 string 类非成员函数

函数 / 运算符名称功能说明
operator+用于拼接两个字符串(或字符串与字符),返回新的字符串对象。由于采用传值返回,会触发深拷贝,效率较低,实际开发中建议优先使用 operator+= 替代。
operator>>(重点)输入运算符重载,用于从输入流(如 cin)读取字符串,默认以空白字符(空格、回车、制表符等)为分隔符,自动跳过前导空白。
operator<<(重点)输出运算符重载,用于将字符串内容输出到输出流(如 cout)。
getline(重点)从输入流中读取一整行字符串(包括空格),直到遇到换行符 '\n' 为止,换行符会被读取但不包含在结果中,常用于读取带空格的完整字符串。
relational operators(重点)关系运算符重载,包括 ==、!=、<、>、<=、>=,用于字符串之间的大小比较(按字符的 ASCII 码值逐位比较,类似字典序)。

上面的几个接口大家了解一下,下面的 OJ 题目中会有一些体现他们的使用。string 类中还有一些其他的

操作,这里不一一列举,大家在需要用到时不明白了查文档即可。

1.6vs 和 g++下 string 结构的说明

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

vs 下 string 的结构

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

符串的存储空间

  当字符串长度小于 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个字符数组的固定空间,不需要通过堆创建,效率高。

其次:还有一个size_t字段保存字符串长度,一个size_t字段保存从堆上开辟空间总的容量

最后:还有一个指针做一些其他事情。

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

g++下string的结构

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

  • 空间总大小

  • 字符串有效长度

  • 引用计数

struct _Rep_base 
{  size_type _M_length;  size_type _M_capacity;  _Atomic_word _M_refcount; 
};
  • 指向堆空间的指针,用来存储字符串

http://www.dtcms.com/a/358944.html

相关文章:

  • k230 按键拍照后,将摄像头拍照的1920*1080分辨率的图片以jpg文件格式,保存到板载TF存储卡的指定文件夹目录中
  • MinerU本地化部署
  • Java的Optional实现优雅判空新体验【最佳实践】
  • 做一个实用的节假日工具
  • MQTT 连接建立与断开流程详解(一)
  • sunset: decoy靶场渗透
  • 20250830_Oracle 19c CDB+PDB(QMS)默认表空间、临时表空间、归档日志、闪回恢复区巡检手册
  • day42-Ansible
  • 动态规划--Day05--最大子数组和--53. 最大子数组和,2606. 找到最大开销的子字符串,1749. 任意子数组和的绝对值的最大值
  • 微信小程序开发教程(三)
  • java如何保证线程安全
  • RLPD——利用离线数据实现高效的在线RL:不进行离线RL预训练,直接应用离策略方法SAC,在线学习时对称采样离线数据
  • 【OpenGL】LearnOpenGL学习笔记17 - Cubemap、Skybox、环境映射(反射、折射)
  • 【pandas】.loc常用操作
  • 【SpringMVC】SSM框架【二】——SpringMVC超详细
  • 【运维篇第三弹】《万字带图详解分库分表》从概念到Mycat中间件使用再到Mycat分片规则,详解分库分表,有使用案例
  • DAEDAL:动态调整生成长度,让大语言模型推理效率提升30%的新方法
  • 基于SpringBoot的电脑商城系统【2026最新】
  • 漫谈《数字图像处理》之分水岭分割
  • SystemVerilog学习【七】包(Package)详解
  • REST-assured获取响应数据详解
  • 数据结构 | 深度解析二叉树的基本原理
  • 访问Nginx 前端页面,接口报502 Bad Gateway
  • 【DeepSeek】ubuntu安装deepseek、docker、ragflow
  • 简历书写---自我评价怎么写
  • Day18_【机器学习—交叉验证与网格搜索】
  • Unity核心概念①
  • 【Linux】基础I/O和文件系统
  • PHP单独使用phinx使用数据库迁移
  • 全栈开源,高效赋能——启英泰伦新官网升级上线!