C语言字符串函数进阶:安全版函数 + 错误处理 + 子串查找
适用对象学过 strcpy / strcat / strcmp 的同学本章目标掌握安全版字符串函数 strstr 子串查找 strerror 错误处理引入strcpy 为什么会让人又爱又恨上一章我们学了strcpy它简单粗暴复制速度也快——但它有一个致命问题不检查目标空间是否够用。如果目标空间只有 5 字节但你拷贝了 20 字节的字符串会发生什么内存越界写入可能会把旁边的变量覆盖掉或者触发段错误Segmentation Fault。更可怕的是有时候程序不会马上崩而是在某个完全不相关的地方突然出问题——这种 Bug 极难定位。于是C 语言标准委员会给几大函数都设计了带数字版本strncpy/strncat/strncmp把拷贝/追加/比较的长度交给程序员控制——更安全但也更复杂。第一部分strncpy——安全拷贝 n 个字符1.1 函数原型char*strncpy(char*destination,constchar*source,size_tnum);第三个参数num最多拷贝num个字符。#includestdio.h#includestring.hintmain(){chararr1[20]{0};chararr2[]abcdefghi;strncpy(arr1,arr2,5);// 只拷贝前 5 个字符printf(%s\n,arr1);// 输出 abcdereturn0;}1.2 strncpy 的三个坑坑一源字符串不够 num 个字符时用\0填充chararr1[20]{0};chararr2[]hi;strncpy(arr1,arr2,10);// 源只有 2 个字符printf(%s\n,arr1);// 输出 hi后面的 8 个位置全部填 \0坑二源字符串够长时不保证在第 num 位置写\0chararr1[20]{0};chararr2[]hello;strncpy(arr1,arr2,3);// 只拷贝 3 个字符 helprintf(%s\n,arr1);// 输出 hel没有 \0arr1[3] 不是 \0⚠️提醒strncpy在源字符串长度 ≥ num 时不会自动补\0这是最容易踩的坑。如果你在后面调用printf(%s, arr1)它会继续往后读内存打印出一堆乱码。所以使用strncpy后务必手动确保目标字符串以\0结尾if(numdest_size)arr1[num]\0;1.3 strncpy vs strcpy怎么选对比strcpystrncpy安全性❌ 不检查边界✅ 可控拷贝长度何时用源字符串短小确定不确定源串长度时长度足够时的 \0一定会补不保证第二部分strncat——安全追加 n 个字符2.1 函数原型char*strncat(char*destination,constchar*source,size_tnum);追加最多num个字符但无论源多长都会追加\0这是它比strncpy更安全的地方。#includestdio.h#includestring.hintmain(){chararr1[20]hello ;chararr2[]world;strncat(arr1,arr2,3);// 只追加前 3 个字符worprintf(%s\n,arr1);// 输出 hello worreturn0;}2.2 strncat 的一个陷阱strncat追加到destination的\0位置开始所以destination本身必须以\0结尾。如果destination忘了初始化chararr1[20];// 未初始化里面是垃圾值strncat(arr1,hi,2);// 危险从哪里开始追加正确写法在使用strncat之前先确保destination有\0或者用arr1[0] \0清空。第三部分strncmp——安全比较 n 个字符3.1 函数原型intstrncmp(constchar*str1,constchar*str2,size_tnum);最多比较前num个字符返回规则同strcmp。#includestdio.h#includestring.hintmain(){chararr1[]abcdef;chararr2[]abcqw;intret1strncmp(arr1,arr2,3);// 只比较前3个abc abc → 0printf(%d\n,ret1);// 输出 0intret2strncmp(arr1,arr2,4);// 比较前4个d q → 负数printf(%d\n,ret2);// 输出负数return0;}3.2 典型应用比较字符串前缀// 判断字符串是否以 http:// 开头if(strncmp(url,http://,7)0)printf(这是 HTTP 链接\n);第四部分strstr——在字符串里找子串4.1 函数原型char*strstr(constchar*str1,constchar*str2);在str1里找str2第一次出现的位置。#includestdio.h#includestring.hintmain(){charstr[]This is a simple string;char*pchstrstr(str,simple);if(pch!NULL)printf(找到了%s\n,pch);// 输出 simple stringelseprintf(没找到\n);return0;}返回值找到则返回指向该位置的指针没找到返回NULL。4.2 手写 strstr暴力匹配核心思路双层循环外层遍历str1内层逐字符比较str1和str2。#includeassert.hchar*my_strstr(constchar*str1,constchar*str2){assert(str1!NULL);assert(str2!NULL);// 空字符串直接返回 str1标准行为if(*str2\0)return(char*)str1;constchar*s1str1;constchar*s2str2;while(*s1){// 记录当前位置constchar*curs1;// 逐字符比较while(*s1*s2*s1*s2){s1;s2;}// s2 遍历完了 → 匹配成功if(*s2\0)return(char*)cur;// 没匹配上重置 s2回到 cur 的下一个位置继续s1cur1;s2str2;}returnNULL;}第五部分strerror——把错误码翻译成人话5.1 什么是 errnoC 语言程序启动时系统会初始化一个全局变量errno定义在errno.h。当你调用标准库函数出错了函数会把对应的错误码写进errno。错误码是一个整数比如 2、5、11——直接看数字完全不知道什么意思。#includeerrno.h// 声明全局变量 errno5.2 strerror翻译错误码char*strerror(interrnum);把错误码翻译成人类可读的错误信息字符串。#includestdio.h#includestring.hintmain(){for(inti0;i10;i)printf(%d: %s\n,i,strerror(i));return0;}输出Windows VS20220: No error 1: Operation not permitted 2: No such file or directory 3: No such process 4: Interrupted function call 5: Input/output error 6: No such device or address 7: Arg list too long 8: Exec format error 9: Bad file descriptor 10: No child processes5.3 实战fopen 出错了怎么办#includestdio.h#includestring.h#includeerrno.hintmain(){FILE*pFilefopen(不存在的文件.txt,r);if(pFileNULL){printf(文件打开失败%s\n,strerror(errno));// 输出文件打开失败No such file or directoryreturn1;}// ... 正常读写文件 ...fclose(pFile);return0;}5.4 perror更简洁的写法perror是strerror的快捷版本直接把错误信息打印出来perror(文件打开失败);// 输出文件打开失败No such file or directory相当于下面这行printf(文件打开失败%s\n,strerror(errno));选哪个如果你需要打印错误用perror更简洁如果你需要存起来或者自定义前缀用strerror。第六部分经典面试题精讲面试题一strncpy 和 strcpy 的核心区别是什么strncpy 有什么坑答案strcpy以\0为结束标志拷贝整个源字符串strncpy以num为拷贝上限但有两个坑源不够长时用\0填充剩余位置有时候不是你想要的源够长时不自动补\0比strcpy更危险加分回答面试中如果能用上「源够 num 时不补\0」这个坑点面试官会觉得你理解得很深。建议使用strncpy后手动dest[num] \0收尾。面试题二strstr 返回值是什么类型的指针答案char*指向str1中首次匹配位置的指针。如果匹配失败返回NULL。charstr[]hello world;char*pstrstr(str,world);printf(%s\n,p);// worldprintf(%ld\n,p-str);// 6world 在第6个位置起进阶用法通过指针相减可以算出子串在原串中的位置。面试题三下面的代码会输出什么#includestdio.h#includestring.hintmain(){chars1[]hello;chars2[]world;charbuf[10];strncpy(buf,s1,10);strncat(buf,s2,3);printf(%s\n,buf);return0;}推演strncpy(buf, s1, 10)buf大小 10 字节s1只有 5 字符 \0所以全部拷贝再填充 4 个\0。bufhello\0\0\0\0\0strncat(buf, s2, 3)从buf的\0位置开始追加s2前 3 个字符wor。bufhellowor\0第二个\0被覆盖但后面还有 2 个\0printf(%s\n, buf)从buf[0]打印到\0输出hellowor答案hellowor本章总结安全版字符串函数函数额外参数与基础版的关键区别strncpysize_t num源够 num 时不补\0需手动处理strncatsize_t num追加 num 字符但一定会补\0strncmpsize_t num最多比较前 num 个字符strstr 用法速记找得到 → 返回指针指向匹配位置找不到 → 返回NULL指针相减 → 子串在原串中的位置错误处理速记函数用法特点errno全局变量记录最近一次错误码调用标准库函数后检查strerrorstrerror(errno)→ 字符串可存、可自定义perrorperror(提示)直接打印等价于printfstrerror

相关新闻

多模态LLM实战:从CLIP视觉编码到信息融合的Wiki技能构建

多模态LLM实战:从CLIP视觉编码到信息融合的Wiki技能构建

1. 项目概述:当大语言模型“睁开双眼”最近在折腾一个挺有意思的东西,我把它叫做“多模态 LLM Wiki Skill”。简单来说,就是给一个大型语言模型(LLM)——比如我们熟悉的 Claude 或者 GPT——装上“眼睛”和“耳朵”&am…

2026/10/17 23:52:27 阅读更多 →
android Handler , Looper , Message , MessageQueue 详解

android Handler , Looper , Message , MessageQueue 详解

一、基础Q1:请简述 Handler 机制的工作原理核心回答:Handler 发送消息 → MessageQueue 按时间排序存储 → Looper 无限循环取出 → 回调 Handler 处理。细节:MessageQueue 不是队列,是单向链表,按 when(触…

2026/10/18 19:25:27 阅读更多 →
Claude Code进阶指南:解锁Skills、Superpowers与Auto-mode,打造AI编程副驾驶

Claude Code进阶指南:解锁Skills、Superpowers与Auto-mode,打造AI编程副驾驶

1. 项目概述:从“能用”到“好用”的Claude Code进阶之路如果你已经成功在VSCode里装上了Claude Code,体验过它流畅的代码补全和对话,那么恭喜你,你已经迈出了第一步。但说实话,如果只是把它当成一个“更聪明的代码提示…

2026/10/18 8:30:40 阅读更多 →

最新新闻

24GB显存跑32B开源大模型:量化+动态卸载的春节实验

24GB显存跑32B开源大模型:量化+动态卸载的春节实验

春节我给自己找了一件挺拧巴的事:非要把一个32B参数的开源大模型,塞进家用那台只有24GB显存的消费级显卡里。拧巴的不是技术难度,而是时机——走亲访友最忙的那几天,客厅里主机风扇一响,整个年味就碎了一地。所以这场实…

2026/10/18 19:44:30 阅读更多 →
心电算法实战:Python滤波、R波识别与心率计算全链路解析

心电算法实战:Python滤波、R波识别与心率计算全链路解析

简介:这是一份以Python编写的心电信号处理算法合集,围绕滤波、R波识别、心率计算、特征提取、心律失常分类,以及房颤、室颤室速等异常心律识别构建,同时覆盖伪差干扰研究、可视化展示与测试工程,适合生物医学工程专业学…

2026/10/18 19:44:30 阅读更多 →
假期AI圈动态全解析:模型迭代、工具链与工程落地

假期AI圈动态全解析:模型迭代、工具链与工程落地

七天假期结束,把手机里这段时间攒下的AI圈消息重新捋了一遍,说实话比上班还累。人在景区排队,群里在刷权重更新;晚上躺床上刷手机,新框架的讨论又顶上热搜。这七天给我的感觉就是:AI圈真的没一天消停&#…

2026/10/18 19:44:30 阅读更多 →
Fetch MCP服务:让大模型拥有实时网页抓取能力

Fetch MCP服务:让大模型拥有实时网页抓取能力

最近帮一位朋友调试他的AI助手项目,聊到一个很现实的问题:模型明明很强,却答不上来昨天刚发布的技术文档。原因很简单,模型的知识有截止日期,而它自己又不会主动去翻网页。要解决这个问题,就得给模型接上一…

2026/10/18 19:44:30 阅读更多 →
vdw-Prks水合物模型:甲烷水合物相平衡高精度计算原理与实现

vdw-Prks水合物模型:甲烷水合物相平衡高精度计算原理与实现

简介:本资源是一份面向计算化学、能源材料与相平衡研究方向的科研人员及高年级本科生的MATLAB建模仿真工具,聚焦甲烷水合物在低温高压条件下的相平衡预测问题。它基于经典的van der Waals–Platteeuw(vdw-P)理论框架,并…

2026/10/18 19:44:30 阅读更多 →
GitHub 开源趋势日报 | 2026年10月8日:AI Agent 与 TypeScript 项目实战配置指南

GitHub 开源趋势日报 | 2026年10月8日:AI Agent 与 TypeScript 项目实战配置指南

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/18 19:43:30 阅读更多 →

日新闻

基于GMM的语音识别系统原理与MATLAB实现详解

基于GMM的语音识别系统原理与MATLAB实现详解

说到基于高斯混合模型(GMM)的语音识别系统,很多人第一反应就是一堆数学公式,觉得门槛很高。但如果你真的在MATLAB里把它落地跑通,会发现核心其实就是三件事:把声音变成特征向量,用GMM给每个类别…

2026/10/18 0:00:55 阅读更多 →
数字图像处理入门:反白、灰度化、调色板修改与导出txt实践

数字图像处理入门:反白、灰度化、调色板修改与导出txt实践

数字图像处理这四个字听起来挺唬人,但落到具体操作上,无非就是让计算机按你的想法“摆弄”像素。我在一个模拟项目X里用了一套特别经典的基础处理流程:对图像做反白、改调色板、彩色转灰度,最后把像素数据导出成txt文件。单看每一…

2026/10/18 0:00:55 阅读更多 →
机器人大脑技术盘点:具身智能的感知、决策与数据闭环

机器人大脑技术盘点:具身智能的感知、决策与数据闭环

如果你的信息流最近也天天刷到“机器人大脑”这个词,你会发现一个很有意思的现象:每个人说的“大脑”根本不是同一个东西。有人指的是大语言模型,有人指的是运动控制系统,还有人指的是能理解物理世界的端到端模型。在2026年这个时…

2026/10/18 0:00:55 阅读更多 →

周新闻

基于GMM的语音识别系统原理与MATLAB实现详解

基于GMM的语音识别系统原理与MATLAB实现详解

说到基于高斯混合模型(GMM)的语音识别系统,很多人第一反应就是一堆数学公式,觉得门槛很高。但如果你真的在MATLAB里把它落地跑通,会发现核心其实就是三件事:把声音变成特征向量,用GMM给每个类别…

2026/10/18 0:00:55 阅读更多 →
数字图像处理入门:反白、灰度化、调色板修改与导出txt实践

数字图像处理入门:反白、灰度化、调色板修改与导出txt实践

数字图像处理这四个字听起来挺唬人,但落到具体操作上,无非就是让计算机按你的想法“摆弄”像素。我在一个模拟项目X里用了一套特别经典的基础处理流程:对图像做反白、改调色板、彩色转灰度,最后把像素数据导出成txt文件。单看每一…

2026/10/18 0:00:55 阅读更多 →
机器人大脑技术盘点:具身智能的感知、决策与数据闭环

机器人大脑技术盘点:具身智能的感知、决策与数据闭环

如果你的信息流最近也天天刷到“机器人大脑”这个词,你会发现一个很有意思的现象:每个人说的“大脑”根本不是同一个东西。有人指的是大语言模型,有人指的是运动控制系统,还有人指的是能理解物理世界的端到端模型。在2026年这个时…

2026/10/18 0:00:55 阅读更多 →

月新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/18 0:55:02 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/17 17:22:31 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/18 12:16:16 阅读更多 →