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

【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.xdnf.cn/news/19203.html

相关文章:

  • 3D生成模型-NeRF:用神经辐射场定义视图合成
  • Ferris Wheel (贪心 | 双指针)
  • ubuntu 安装conda, ubuntu24安装miniConda
  • 【Pytorch】生成对抗网络实战
  • 服务器托管多少钱一年?服务器托管收费标准
  • React useState基本使用
  • 3000. 对角线最长的矩形的面积
  • linux系统学习(4.常用命令)
  • 【具身智能】【机器人动力学】台大林佩群笔记-待持续更新
  • 算法(④KMP)
  • 基于YOLO8的垃圾识别检测系统(数据集+源码+文章)
  • (双指针)Leetcode283.移动零-替换数字类别+Leetcode15. 三数之和
  • day44-Ansible变量
  • ESP32C3和ESP32S3的区别有哪些?该怎么选型?
  • React Router 6 获取路由参数
  • 无人机也能称重?电力巡检称重传感器安装与使用指南
  • 算法之x数之和
  • B树与B+树的原理区别应用
  • 第12章:推荐算法与实践
  • 揭开智能体架构面纱:90% 属软件工程,10% 为 AI 技术
  • nginx(自写)
  • 微服务搭建(SpringBoot + Dubbo + Nacos)
  • vue+Django 双推荐算法旅游大数据可视化系统Echarts mysql数据库 带爬虫
  • 【学Python自动化】 4. Python 控制流与函数学习笔记
  • 嵌入式Linux驱动开发:ICM20608六轴传感器SPI驱动
  • 深度学习核心损失函数详解:交叉熵、MSE、对比学习(InfoNCE)
  • 科技感网页计时器.html
  • Linux系统统计用户登录和注销时间的工具之ac
  • 【计算机408计算机网络】第四章:自底向上五层模型之网络层
  • 使用python格式化nginx配置文件