深入解析:C语言字符串安全查找 :strchr_s、strrchr_s、strstr_s
在 C11 标准中,为了增强字符串操作的安全性,引入了一系列安全版本的字符串函数。下面详细解析 strchr_s、strrchr_s 和 strstr_s 这三个字符串安全查找函数。
1. strchr_s - 安全字符查找
函数原型
errno_t strchr_s(
const char *str,
size_t strsz,
int ch,
char **result
);
功能说明
查找字符 ch 在字符串 str 中第一次出现的位置。
参数说明
str:要搜索的字符串strsz:字符串缓冲区大小ch:要查找的字符result:指向指针的指针,用于存储找到的位置
返回值
- 成功:返回 0
- 失败:返回非零错误码
示例代码
#include <stdio.h>#include <string.h>int main() {const char *text = "Hello, World!";char *result = NULL;errno_t err;// 查找字符 'W'err = strchr_s(text, strlen(text) + 1, 'W', &result);if (err == 0 && result != NULL) {printf("找到字符 'W',位置:%ld\n", result - text);printf("剩余字符串:%s\n", result);} else {printf("未找到字符 'W'\n");}return 0;}
2. strrchr_s - 安全反向字符查找
函数原型
errno_t strrchr_s(
const char *str,
size_t strsz,
int ch,
char **result
);
功能说明
查找字符 ch 在字符串 str 中最后一次出现的位置。
示例代码
#include <stdio.h>#include <string.h>int main() {const char *filename = "document.txt.backup";char *result = NULL;errno_t err;// 查找最后一个点号err = strrchr_s(filename, strlen(filename) + 1, '.', &result);if (err == 0 && result != NULL) {printf("文件扩展名:%s\n", result + 1); // 跳过点号} else {printf("未找到文件扩展名\n");}return 0;}
3. strstr_s - 安全子串查找
函数原型
errno_t strstr_s(
const char *str,
size_t strsz,
const char *substr,
char **result
);
功能说明
查找子串 substr 在字符串 str 中第一次出现的位置。
示例代码
#include <stdio.h>#include <string.h>int main() {const char *text = "The quick brown fox jumps over the lazy dog";char *result = NULL;errno_t err;// 查找子串 "fox"err = strstr_s(text, strlen(text) + 1, "fox", &result);if (err == 0 && result != NULL) {printf("找到子串 'fox',位置:%ld\n", result - text);printf("从该位置开始的字符串:%s\n", result);} else {printf("未找到子串 'fox'\n");}return 0;}
4. 完整示例程序
#include <stdio.h>#include <string.h>#include <errno.h>void demonstrate_strchr_s() {printf("=== strchr_s 示例 ===\n");const char *text = "Programming in C";char *result = NULL;errno_t err = strchr_s(text, strlen(text) + 1, 'g', &result);if (err == 0 && result != NULL) {printf("第一个 'g' 在位置:%ld\n", result - text);} else {printf("查找失败,错误码:%d\n", err);}}void demonstrate_strrchr_s() {printf("\n=== strrchr_s 示例 ===\n");const char *path = "/home/user/documents/file.txt";char *result = NULL;errno_t err = strrchr_s(path, strlen(path) + 1, '/', &result);if (err == 0 && result != NULL) {printf("文件名:%s\n", result + 1);} else {printf("查找失败,错误码:%d\n", err);}}void demonstrate_strstr_s() {printf("\n=== strstr_s 示例 ===\n");const char *sentence = "C programming is powerful and C is widely used";char *result = NULL;errno_t err = strstr_s(sentence, strlen(sentence) + 1, "C programming", &result);if (err == 0 && result != NULL) {printf("找到子串,位置:%ld\n", result - sentence);printf("内容:%s\n", result);} else {printf("未找到子串,错误码:%d\n", err);}}int main() {demonstrate_strchr_s();demonstrate_strrchr_s();demonstrate_strstr_s();return 0;}
5. 错误处理
这些函数在发生错误时会返回相应的错误码:
#include <stdio.h>#include <string.h>void error_handling_example() {const char *text = "Hello";char *result = NULL;// 测试各种错误情况// 1. 空指针errno_t err = strchr_s(NULL, 10, 'H', &result);if (err != 0) {printf("错误:空指针,错误码:%d\n", err);}// 2. 字符串长度超过缓冲区大小err = strchr_s(text, 3, 'o', &result); // 实际字符串长度 > 3if (err != 0) {printf("错误:缓冲区大小无效,错误码:%d\n", err);}// 3. 正常情况err = strchr_s(text, strlen(text) + 1, 'l', &result);if (err == 0 && result != NULL) {printf("成功找到字符,位置:%ld\n", result - text);}}
6. 与传统函数的对比
| 特性 | 传统函数 | 安全版本 |
|---|---|---|
| 参数验证 | 无 | 有完整的参数检查 |
| 缓冲区溢出保护 | 无 | 通过 strsz 参数提供 |
| 返回值 | 直接返回指针 | 通过错误码和输出参数 |
| 空指针处理 | 未定义行为 | 明确返回错误码 |
字符串安全查找函数对比表
| 特性 | strchr_s | strrchr_s | strstr_s |
|---|---|---|---|
| 函数原型 | errno_t strchr_s(const char *str, size_t strsz, int ch, char **result) | errno_t strrchr_s(const char *str, size_t strsz, int ch, char **result) | errno_t strstr_s(const char *str, size_t strsz, const char *substr, char **result) |
| 查找方向 | 正向查找(从左到右) | 反向查找(从右到左) | 正向查找(从左到右) |
| 查找目标 | 单个字符 | 单个字符 | 字符串(子串) |
| 查找内容 | 字符 ch | 字符 ch | 子串 substr |
| 返回位置 | 第一次出现的位置 | 最后一次出现的位置 | 第一次出现的位置 |
| 主要用途 | 查找字符首次出现 | 查找字符最后出现 | 查找子串首次出现 |
| 典型应用场景 | 解析字符串前缀、查找分隔符 | 文件扩展名提取、路径解析 | 关键词搜索、模式匹配 |
| 参数类型 | int ch(字符) | int ch(字符) | const char *substr(字符串) |
| 时间复杂度 | O(n) | O(n) | O(n×m) 最坏情况 |
| 返回值机制 | 通过 result 输出参数返回位置 | 通过 result 输出参数返回位置 | 通过 result 输出参数返回位置 |
| 错误返回值 | 非零错误码 | 非零错误码 | 非零错误码 |
详细功能对比
| 功能细节 | strchr_s | strrchr_s | strstr_s |
|---|---|---|---|
| 查找范围 | 整个字符串 | 整个字符串 | 整个字符串 |
| 匹配方式 | 精确字符匹配 | 精确字符匹配 | 子串完全匹配 |
| 空字符处理 | 会找到字符串结束符 \0 | 会找到字符串结束符 \0 | 不会匹配空字符串 |
| 大小写敏感 | 是 | 是 | 是 |
| 内存安全 | 是(通过strsz参数) | 是(通过strsz参数) | 是(通过strsz参数) |
| 标准版本 | C11 | C11 | C11 |
使用示例对比
| 使用场景 | strchr_s | strrchr_s | strstr_s |
|---|---|---|---|
| 示例输入 | "hello@example.com" | "/path/to/file.txt" | "C programming is fun" |
| 查找目标 | '@' | '/' | "programming" |
| 查找结果 | "@example.com" | "/file.txt" | "programming is fun" |
| 实际应用 | 邮箱域名提取 | 文件名提取 | 关键词定位 |
错误处理对比
| 错误情况 | strchr_s | strrchr_s | strstr_s |
|---|---|---|---|
| str为NULL | 返回错误 | 返回错误 | 返回错误 |
| result为NULL | 返回错误 | 返回错误 | 返回错误 |
| strsz为0 | 返回错误 | 返回错误 | 返回错误 |
| strsz超过实际大小 | 可能返回错误 | 可能返回错误 | 可能返回错误 |
| 未找到目标 | result设为NULL,返回0 | result设为NULL,返回0 | result设为NULL,返回0 |
| substr为NULL | 不适用 | 不适用 | 返回错误 |
性能特点对比
| 性能指标 | strchr_s | strrchr_s | strstr_s |
|---|---|---|---|
| 最佳情况 | O(1) - 目标在开头 | O(n) - 必须扫描整个字符串 | O(n) - 目标在开头 |
| 最坏情况 | O(n) - 目标在末尾或不存在 | O(n) - 必须扫描整个字符串 | O(n×m) - 需要回溯匹配 |
| 平均情况 | O(n/2) | O(n) | O(n+m) |
| 内存访问 | 顺序访问 | 顺序访问(但需要记录最后位置) | 顺序访问,可能回溯 |
适用场景总结
| 场景类型 | 推荐函数 | 理由 |
|---|---|---|
| 查找分隔符 | strchr_s / strrchr_s | 单字符查找效率高 |
| 提取文件扩展名 | strrchr_s | 需要找到最后一个点号 |
| 搜索关键词 | strstr_s | 需要匹配整个子串 |
| 解析路径 | strrchr_s | 提取文件名或最后一级目录 |
| 验证字符串格式 | strchr_s | 检查特定字符是否存在 |
| 文本内容搜索 | strstr_s | 在长文本中查找短语 |
这个对比表清晰地展示了三个安全字符串查找函数在功能、性能和适用场景上的差异,帮助开发者根据具体需求选择合适的函数。
总结
安全版本的字符串查找函数提供了以下优势:
- 参数验证:检查空指针和无效参数
- 边界检查:通过
strsz参数防止缓冲区溢出 - 明确的错误处理:通过返回值提供详细的错误信息
- 一致性:统一的错误返回机制
在使用这些函数时,务必:
- 正确计算字符串缓冲区大小(通常为
strlen(str) + 1) - 检查返回值以确保操作成功
- 正确处理错误情况
这些安全函数特别适用于对安全性要求较高的应用程序,如系统软件、网络服务等。
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/956812.shtml
如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!相关文章
2025年靠谱的连锁泡菜加盟公司排名,泡菜加盟正规公司推荐
2025年餐饮加盟市场持续升温,泡菜品类凭借酸辣开胃的风味、灵活的消费场景,成为创业者青睐的赛道。但行业中加盟品牌鱼龙混杂:部分品牌无核心技术沉淀,产品同质化严重;部分快招公司圈钱跑路,让创业者血本无归;还…
2025年消雾装置冷却塔供货厂家权威推荐:消雾冷却塔/消雾冷却塔选型/消雾冷却塔变频源头厂家精选
随着国家环保政策收紧和工业节水需求提升,消雾装置冷却塔市场年增长率已连续三年超过15%,其中高效节水型产品占据市场份额的45%以上。
消雾装置冷却塔作为工业循环水系统的核心设备,正朝着高效消雾、节能降噪、智能…
深入解析:多模态医疗大模型Python编程合规前置化与智能体持续学习研究(中)
pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", "Monaco", "Courier New", …
前端图片压缩三方库browser-image-compression的使用实践
上篇文章是deepseek给出的前端图片压缩方案建议,后经过查看各第三方库的github项目和压缩后相同大小文件的对比,可以得出结论,这几个三方库其实也都是浏览器原生Canvas API的封装.当然,不管它们怎么实现的,只要用起来方…
特氟龙喷涂厂家TOP5推荐:特氟龙喷涂厂家推荐指南
在众多工业防护涂层中,特氟龙喷涂凭借其独特的性能优势,在密封圈、食品模具、化工设备等多个领域广泛应用,市场对优质特氟龙喷涂厂家的需求也日益增长。然而,企业在选择厂家时,常面临诸多困惑,如基础性能不达标、…
网络图片下载+VideCoding+DeepSeekOCR解析实践
网络图片下载+VideCoding+DeepSeekOCR解析实践背景 某高校师资网站全面采用网络图片展示,网站是禁止右键使用下载,也不允许复制信息。我们试图采集这些信息,使用目前智能体任务+VibeCoding+Deepsee-OCR解析来…
如何处理旧 iPhone:安全地回收或重新利用 - 实践
pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", "Monaco", "Courier New", …
给图片添加水印接口(文字水印和照片水印)
最近在调试的时候,发现打印出来的卡证上姓名处本来应该是中文名的地方,结果出现了三个方框。初步怀疑是再给图片加水印的时候乱码了(原本服务器是Windows的,后面换成Linux)。经过排查,发现代码中有调用Graphics2…
【Android】一种应用霸屏方式:设置固定应用
View Post【Android】一种应用霸屏方式:设置固定应用简介
Android系统中的"固定应用"功能,也常被称为"屏幕固定"或"应用固定",是一项非常实用的屏幕锁定功能。它能够将当前应用锁定在…
测试2网站收藏 - Su
学习
语雀/工作台
软件
Gitee
Git教程-廖雪峰
韦东山freeRTOS快速入门
硬件
嘉立创客户中心/PCB.SMT.3D打印等服务
立创商城/元器件
立创开源广场
画PCB必备的3D元器件模型下载地址整理
结构
练习
Learn Git Branching…
2025年密闭冷却塔品牌排名推荐:密闭冷却塔加工厂价格哪家合理
在工业冷却领域,密闭冷却塔作为关键设备,其性能直接影响工艺稳定性、能耗成本与环保合规。面对市场上良莠不齐的供应商,企业如何选择价格合理、质量可靠、服务完善的合作伙伴?以下结合技术实力、市场口碑与行业适配…
Apache SeaTunnel 支持 Metalake 开发了!避免任务配置敏感信息暴露
在2025年开源之夏活动中,我参与了Apache SeaTunnel项目的开发,目标是解决任务配置中敏感信息暴露的问题。今年的开源之夏活动已接近尾声,Apache SeaTunnel 社区的开发者们在经过漫长的开发过程也都收获了自己的成果…
2025年深圳巨量竞价开户公司权威推荐榜单:爱采购开户/爱采购运营/巨量推广源头公司精选
在数字化营销浪潮的推动下,深圳作为科技与创新前沿阵地,企业对巨量引擎平台的专业投放需求正持续攀升。根据行业统计,2025年抖音电商GMV已突破2.5万亿元,平台月活超7.8亿,流量红利显著,但规则升级速度同样惊人,…
System Exec.vi
System Exec.viLabVIEW 的 System Exec.vi 是一个非常常用的系统调用节点,用于在 VI 中执行 外部命令或程序(exe、bat、cmd、python等)。
下面是详细讲解与示例:🧩 一、System Exec.vi 功能说明
路径:Functions…
HR内耗终结者:Moka People实现招聘、人事、薪酬全流程数据一体化,提效200%
对于奋战在一线的HRBP或SSC(共享服务中心)成员而言,效率的瓶颈往往不在于工作量大,而在于流程的碎片化和数据的重复操作。每月的薪酬核对、跨系统的入职信息录入、复杂的考勤数据导入,这些低价值的事务性工作不仅…
每周读书与学习-JMeter主要元件详细介绍(四)再谈取样器
每周读书与学习是由清华大学出版社出版的《JMeter核心技术、性能测试与性能分析》一书的作者推出,分享作者多年的IT从业经历,希望对很多计算机科学技术IT类专业毕业生以及IT从业者有所帮助。
1、取样器
在前面的章节…
2025年济南靠谱龙工叉车公司推荐,专业龙工叉车平台全解析
叉车作为工业物流的核心设备,其选型、运维与管理直接影响企业的生产效率与运营成本。在济南及周边地区,龙工叉车凭借高性价比、稳定性能占据重要市场份额,但面对众多龙工叉车服务机构,如何选择专业靠谱的合作伙伴?…
AI|AI优化企业新榜单与选择指南 - 二当家
AI优化企业新势力:解码流量增长新引擎
2025年AI优化企业TOP3:东晟领跑,技术驱动全域增长
头部企业实力对决:从技术壁垒到场景深耕
在生成式AI重构搜索生态的2025年,企业流量获取逻辑已从“关键词堆砌”转向“场景…
多存储文件列表神器Alist:轻松管理你的云端资源
Alist是一个支持多种存储服务的文件列表程序,使用Gin和Solidjs构建,能够将多个网盘和存储服务聚合在一个界面中统一管理,支持WebDAV等多种协议,让你的文件管理更加高效便捷。Alist - 多存储文件列表程序:card_inde…