C++从入门到实战(十七)String(下)详细讲解String的常用接口(string修饰函数,处理字符串的成员函数,npos常量与string类非成员函数)

C++从入门到实战(十七)String(下)详细讲解String的常用接口(string修饰函数,处理字符串的成员函数,npos常量与string类非成员函数)

C++从入门到实战(十七)String(下)详细讲解String的常用接口


前言

  • 在上一篇博客中,我们探讨了string实战的部分接口,涵盖构造接口、析构接口、迭代器、遍历修改、容量管理以及数据访问等内容。
  • 本篇博客将延续string实战的主题,聚焦于解析string类的常用接口,助力读者深入理解其核心用法与实践技巧。
我的个人主页,欢迎来阅读我的其他文章
https://blog.ZEEKLOG.net/2402_83322742?spm=1011.2415.3001.5343
我的C++知识文章专栏
欢迎来阅读指出不足
https://blog.ZEEKLOG.net/2402_83322742/category_12880513.html?spm=1001.2014.3001.5482

C++string的官方讲解网站

https://cplusplus.com/reference/string/string/?kw=string

一、string的修饰函数

1. 追加内容(Append)

operator+=(重要)

  • 作用:直接在字符串末尾添加内容。

示例

string s ="Hello"; s +=" World";// s = "Hello World" s +='!';// s = "Hello World!"

append()

  • 作用:追加字符串、子串或重复字符。

示例

string s ="Hello"; s.append(" World");// s = "Hello World" s.append("12345",2);// 追加前2个字符 → s = "Hello World12" s.append(3,'!');// 追加3个'!' → s = "Hello World12!!!"
在这里插入图片描述

push_back()

  • 作用:在字符串末尾添加单个字符。

示例

string s ="abc"; s.push_back('d');// s = "abcd"
在这里插入图片描述

2. 赋值操作(Assign)

assign()(实践中不太常用)

  • 作用:替换字符串内容,支持多种赋值方式。

示例

string s ="old"; s.assign("new");// s = "new" s.assign("12345",3);// 取前3个字符 → s = "123" s.assign(5,'a');// 重复5个'a' → s = "aaaaa"
在这里插入图片描述

3. 插入操作(Insert)

insert()

  • 作用:在指定位置插入内容。

示例

string s ="Hello World"; s.insert(6,"Beautiful ");// 在位置6插入 → s = "Hello Beautiful World" s.insert(0,2,'!');// 在开头插入2个'!' → s = "!!Hello Beautiful World"
在这里插入图片描述

4. 删除操作(Erase)

erase()

  • 作用:删除指定位置的字符或子串。

示例

string s ="Hello World"; s.erase(5);// 删除位置5及之后的字符 → s = "Hello" s.erase(2,2);// 从位置2开始删除2个字符 → s = "Heo"

pop_back()

  • 作用:删除字符串的最后一个字符(C++11起)。

示例

string s ="abc"; s.pop_back();// s = "ab"

5. 替换操作(Replace)(谨慎使用,效率极低!!!)

replace()

  • 作用:替换指定位置的子串。
  • 为什么效率极低?
  • 对于字符串替换,每次调用replace()都可能引发内存重新分配,尤其是在字符串变长的时候
  • 若进行全局替换(如替换所有匹配项),由于需要多次遍历字符串,时间复杂度会达到 O (n²)。
  • 建议谨慎使用替换操作,特别是在处理大规模数据的时候。

示例

string s ="Hello World"; s.replace(6,5,"Universe");// 从位置6开始的5个字符替换为"Universe"// s = "Hello Universe"

6. 交换操作(Swap)

swap()

  • 作用:交换两个字符串的内容(高效操作,常数时间复杂度)。

示例

string s1 ="apple"; string s2 ="banana"; s1.swap(s2);// s1 = "banana", s2 = "apple"

对比表格

函数名功能描述示例代码
operator+=追加字符串、字符或C风格字符串s += "test";
append()追加字符串、子串或重复字符s.append("abc", 2);s += "ab"
push_back()追加单个字符s.push_back('!');
assign()替换字符串内容s.assign("new", 2);s = "ne"
insert()在指定位置插入内容s.insert(0, "pre");"pre" + s
erase()删除指定位置的字符或子串s.erase(1, 2); → 删除位置1开始的2个字符
replace()替换指定位置的子串s.replace(0, 3, "ABC");
swap()交换两个字符串的内容s1.swap(s2);
pop_back()删除最后一个字符(C++11起)s.pop_back();

二、string类中 npos 常量

一句话理解
npos就像字符串世界里的“无限远”或“找不到”:

  • 当查找失败时,它告诉你“没找到”;
  • 当指定范围时,它帮你“直达字符串终点”。

1. npos的定义与含义

定义

staticconst size_t npos =-1;
  • 类型size_t(无符号整数,通常是unsigned long long)。
  • -1,但由于无符号类型,实际表示为该类型的最大值(如64位系统为18446744073709551615)。

作用

  • 表示“不存在”或“直到末尾”:在字符串操作中,用于标记查找失败或指定范围到字符串末尾。

2. npos的常见用途

(1)查找失败的返回值

  • 场景:当find()rfind()等函数未找到目标时,返回npos

示例

string s ="hello"; size_t pos = s.find("world");if(pos == string::npos){ cout <<"未找到"<< endl;// 输出此行}
在这里插入图片描述

(2)指定“直到字符串末尾”

  • 场景:在substr()erase()等函数中,若长度参数为npos,表示操作到字符串末尾。

示例

string s ="hello world";// 从位置6开始截取到末尾 string sub = s.substr(6);// 等价于 s.substr(6, string::npos) → "world"// 删除从位置5开始的所有字符 s.erase(5);// 等价于 s.erase(5, string::npos) → "hello"
在这里插入图片描述

(3)构造子串时的默认长度

  • 场景:在子串构造函数中,若未指定长度,默认截取到末尾。

示例

string s ="hello world"; string sub(s,6);// 从位置6开始截取到末尾 → "world"

3. 为什么用npos而不是直接用-1?

  • 类型安全npossize_t类型,与字符串函数的返回值类型匹配,避免隐式类型转换导致的问题。
  • 代码可读性npos直观表达“不存在”或“末尾”的语义,比-1更易理解。

4. 注意事项

    • npos是极大的无符号数,参与运算可能导致意外结果。

避免数值运算

size_t x = string::npos -10;// 结果是一个极大的数,而非-10

比较时必须用==

// 正确if(s.find("x")== string::npos){...}// 错误(无符号数比较)if(s.find("x")<0){...}// 永远不成立!

三、String 处理字符串的成员函数

1. 查找操作:find()

作用:在字符串中查找指定内容的第一次出现位置
常用重载形式

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

示例

string s ="hello world";// 查找字符串 size_t pos1 = s.find("world");// pos1 = 6("world"的起始位置)// 从位置5开始查找字符'o' size_t pos2 = s.find('o',5);// pos2 = 7(第二个'o'的位置)// 未找到时返回string::npos(通常是-1,但类型为size_t)if(s.find("xyz")== string::npos){ cout <<"未找到"<< endl;}
在这里插入图片描述

2. 反向查找:rfind()

作用:在字符串中查找指定内容的最后一次出现位置(从后往前找)。
示例

string s ="hello world";// 查找最后一个'l'的位置 size_t pos = s.rfind('l');// pos = 9
在这里插入图片描述

3. 子串提取:substr()

作用:从原字符串中截取子串。
语法

string substr(size_t pos =0, size_t len = npos)const;
  • pos:起始位置(默认为0)。
  • len:子串长度(默认为npos,表示截取到字符串末尾)。

示例

string s ="hello world";// 从位置6开始截取3个字符 string sub1 = s.substr(6,3);// sub1 = "wor"// 从位置6开始截取到末尾 string sub2 = s.substr(6);// sub2 = "world"

4. 复制到字符数组:copy()

作用:将字符串的部分内容复制到字符数组中。
语法

size_t copy(char* dest, size_t len, size_t pos =0)const;
  • dest:目标字符数组。
  • len:复制的最大字符数。
  • pos:起始位置(默认为0)。

示例

string s ="hello";char buffer[10];// 从位置1开始复制3个字符到buffer size_t copied = s.copy(buffer,3,1);// copied = 3,buffer内容为"ell" buffer[copied]='\0';// 手动添加字符串结束符

5. 字符串比较:compare()

作用:比较两个字符串的大小(字典序)。
常用重载形式

intcompare(const string& str)const;// 与另一个string比较intcompare(constchar* s)const;// 与C风格字符串比较
  • 返回值
    • 0:相等。
    • 正数:当前字符串 > 参数。
    • 负数:当前字符串 < 参数。

示例

string s1 ="apple"; string s2 ="banana";if(s1.compare(s2)<0){ cout <<"s1 < s2"<< endl;// 输出此行}// 更简单的比较方式(直接用运算符)if(s1 < s2){ cout <<"s1 < s2"<< endl;// 效果同上}

总结

函数名功能描述示例代码
find()查找首次出现位置s.find("abc") → 返回"abc"的起始位置,未找到返回string::npos
rfind()查找最后一次出现位置s.rfind('x') → 返回最后一个’x’的位置
substr()截取子串s.substr(2, 3) → 从位置2开始截取3个字符(如s="hello""ell"
copy()复制到字符数组s.copy(buffer, 5, 0) → 复制前5个字符到buffer(需手动添加\0
compare()字符串比较(字典序)s1.compare(s2) → 等价于s1 < s2(但返回值为整数)

注意事项

  1. string::npos:所有查找函数未找到目标时返回该值,判断时需用==
  2. substr()越界:若pos + len超过字符串长度,自动截取到末尾。
  3. copy()无结束符:复制后需手动添加\0才能作为C风格字符串使用。
  4. compare() vs 运算符:直接用==<等运算符更直观,推荐使用。

四、string类非成员函数

1. operator+尽量少用

为什么?
operator+用于拼接字符串,但它的效率较低。因为它采用传值返回,每次使用都会创建新的string对象,涉及深拷贝(复制整个字符串内容),尤其在循环中频繁拼接时,性能损耗明显。

示例(低效写法):

string result;for(int i =0; i <1000; i++){ result = result +"a";// 每次都创建新对象,慢!}

替代方案:
使用+=append(),它们直接在原字符串后追加,避免频繁深拷贝。

string result;for(int i =0; i <1000; i++){ result +="a";// 高效:直接追加}// 或用 append() result.append("abc");

2. operator>> 输入运算符重载

作用:
从输入流(如键盘)读取字符串,遇到空格或换行符停止。

示例:

#include<iostream>#include<string>usingnamespace std;intmain(){ string name; cout <<"请输入姓名:"; cin >> name;// 输入 "John Doe",实际只读取 "John" cout <<"你好,"<< name << endl;return0;}

注意:

  • operator>>会自动跳过开头的空格。
  • 遇到空格后停止读取,适合读取单个单词。

3. operator<< 输出运算符重载

作用:
将字符串输出到流(如屏幕)。

示例:

string message ="Hello, World!"; cout << message << endl;// 输出:Hello, World!

进阶:
可与其他流操作符连用:

int age =20; cout <<"我今年"<< age <<"岁了。"<< endl;// 输出:我今年20岁了。

4. getline() 获取一行字符串

作用:
读取整行文本,包括空格,直到遇到换行符

基本语法:

getline(cin, str);// 从标准输入读取一行到 str

示例:

string address; cout <<"请输入地址:";getline(cin, address);// 输入 "北京市海淀区",完整读取 cout <<"你的地址是:"<< address << endl;

注意:

如果之前使用过cin读取其他数据(如数字),需用cin.ignore()清除缓冲区的换行符:

int num; string line; cin >> num;// 输入数字后按回车,换行符留在缓冲区 cin.ignore();// 清除换行符getline(cin, line);// 此时能正确读取下一行

5. 关系运算符(relational operators)

作用:
比较两个字符串的大小,基于字典序(即字母表顺序)。

常用运算符:
==!=<><=>=

示例:

string a ="apple"; string b ="banana"; cout <<(a == b)<< endl;// 输出 0(false) cout <<(a < b)<< endl;// 输出 1(true),因为 'a' < 'b' cout <<(a >"apple")<< endl;// 输出 0(false),内容相同

进阶:
比较规则:

  1. 逐字符比较 ASCII 码值。
  2. 若某字符不同,该位置字符大的字符串更大。
  3. 若所有字符相同,长度长的字符串更大。
"apple"<"banana"// true('a' < 'b')"apple"<"apples"// true(长度不同)"apple">"Apples"// true(小写 'a' 比大写 'A' 大)

总结

操作符/函数作用示例注意事项
operator+拼接字符串(低效)s = s1 + s2避免频繁使用,用+=替代
operator>>读取单个单词cin >> s遇到空格停止
operator<<输出字符串cout << s可链式输出
getline()读取整行getline(cin, s)注意清除缓冲区换行符
关系运算符字典序比较s1 == s2s1 < s2基于 ASCII 码逐字符比较

以上就是这篇博客的全部内容,下一篇我们将继续探索STL中String里更多精彩内容。

我的个人主页,欢迎来阅读我的其他文章
https://blog.ZEEKLOG.net/2402_83322742?spm=1011.2415.3001.5343
我的C++知识文章专栏
欢迎来阅读指出不足
https://blog.ZEEKLOG.net/2402_83322742/category_12880513.html?spm=1001.2014.3001.5482
非常感谢您的阅读,喜欢的话记得三连哦
在这里插入图片描述

Read more

在 NVIDIA DGX Spark部署 Stable Diffusion 3.5 并使用ComfyUI

在 NVIDIA DGX Spark部署 Stable Diffusion 3.5 并使用ComfyUI

📖 前言 随着 NVIDIA Blackwell 架构的问世,DGX Spark (Personal AI Supercomputer) 将桌面级 AI 算力推向了新的巅峰。这台怪兽级设备搭载了 GB200/GB10 级别的 GPU 和 NVIDIA Grace CPU (ARM64),并运行在最新的 CUDA 13 环境下。 然而,“最强硬件"往往伴随着"最难环境”。由于 Grace CPU 采用 ARM (aarch64) 架构,且 CUDA 13 过于前沿,传统的 PyTorch 安装方法极易失败。 本文将手把手教你如何在这台超级计算机上部署 Stable Diffusion

By Ne0inhk

AI助力FPGA开发:Vivado下载与智能编程实践

快速体验 1. 打开 InsCode(快马)平台 https://www.inscode.net 2. 点击'项目生成'按钮,等待项目生成完整后预览效果 输入框内输入如下内容: 创建一个AI辅助FPGA开发的工具,支持自动生成Vivado项目配置代码,包括IP核集成、约束文件生成和仿真测试脚本。工具应能根据用户输入的硬件描述(如'需要实现一个UART通信模块')自动推荐最佳实践代码,并支持与Vivado无缝集成。提供错误检测和优化建议功能,帮助开发者快速定位问题。 作为一名FPGA开发者,我经常需要花费大量时间在Vivado的环境配置和代码调试上。最近我发现了一些AI辅助工具,可以显著提升开发效率,今天就和大家分享一下我的实践经验。 Vivado下载与基础配置 1. 首先需要从Xilinx官网下载Vivado设计套件。建议选择最新版本,因为AI工具通常对新版本的支持更好。下载时要特别注意选择适合自己操作系统的版本,Windows和Linux版本在功能上会有一些差异。 2. 安装过程中,建议选择"Vivado HL WebPACK&

By Ne0inhk

机器人 - 关于MIT电机模式控制

目录 一、MIT电机模式简单介绍 1.1 简单介绍 1.2 MIT模式的控制参数 1.3 使用场景 二、调试时建议 2.1 调试 2.2 问题定位 一、MIT电机模式简单介绍 1.1 简单介绍 Mixed Integrated Torque为一种混合控制模式,在同一帧CAN数据里包含 位置、速度、扭矩三类的闭环指令。驱动器里面把位置环、速度环、前馈扭矩相加,得到一个参考电流,然后再交给电流环完成精准扭矩输出。 1.2 MIT模式的控制参数 参数含义取值范围(常见)说明kp位置比例系数(刚度)0 ~ 500 (单位视驱动器而定)kp = 0 时位置环失效,

By Ne0inhk
【火】Spatial Joy 2025 全球 AR&AI 赛事:开发者要的资源、玩法、避坑攻略都在这

【火】Spatial Joy 2025 全球 AR&AI 赛事:开发者要的资源、玩法、避坑攻略都在这

Spatial Joy 2025 Rokid乐奇 全球 AR&AI 开发大赛 值不值得参加?不少参加过连续两届 Rokid乐奇 赛事的老兵,纷纷表示非常值得参加。 先说最实在的——奖金。 AR赛道分为应用和游戏两个赛道,金奖各20万人民币,而且是现金!交完税全是你自己的!这还不够,AR赛道总共设了27个奖项,据我打听到的往年数据,能正常跑进初赛的作品大概就60-70个,这意味着获奖比例相当高。 20万就封顶了吗?远远没有!亚马孙科技给使用Kiro并获奖的开发者,在原奖金基础上再加20%现金奖励! AI赛道同样设置了27个奖项,奖金从1万到5万不等,主要以智能体开发为主,支持市面上所有智能体平台的适配。也就是说,你之前做的智能体微调一下就能参赛! 更重要的是,现在正是智能眼镜行业爆发前夜。据我观察,未来2-3年将是空间计算应用落地的关键窗口期,提前布局的开发者将占据绝对先发优势。 好了,重磅消息说完,下面是我为大家整理的详细参赛指南: 先给开发者交个底:这赛事值得花时间吗? 对技术人来说,一场赛事值不值得冲,就看三点:资源给不给力、

By Ne0inhk