第八章:字符串与字符串函数
欢迎来到第八章在上一章中我们学习了指针。从这一章开始我们将把指针和数组结合起来深入学习 C 语言中最常用的数据之一 ——字符串。字符串在编程中无处不在用户输入、文件内容、网络数据、界面文字…… 几乎所有和 文字 相关的东西本质上都是字符串。但 C 语言比较特别 —— 它没有专门的 字符串类型而是用字符数组 结束符来表示字符串。这种设计既灵活又容易出错是新手踩坑的重灾区。本章我们将系统学习字符串的本质是什么\0到底是干嘛的字符串怎么输入、怎么输出常用的字符串函数有哪些怎么用字符数组和字符指针有什么区别字符串操作有哪些常见的坑学完本章你就能熟练处理各种字符串操作了准备好了吗让我们开始一、字符串的本质1.1 什么是字符串C 语言中字符串就是以 \0 结尾的字符数组。两个关键点它是一个字符数组—— 每个元素是一个 char末尾必须有一个结束标志 \0\0是一个特殊字符叫空字符它的 ASCII 码值是 0。它不算字符串的内容只是用来标记 字符串到这里结束了。比如字符串Hello看起来是 5 个字符实际在内存中占 6 个字节H e l l o \0 ┌─────┬─────┬─────┬─────┬─────┬─────┐ │ 72 │ 101 │ 108 │ 108 │ 111 │ 0 │ └─────┴─────┴─────┴─────┴─────┴─────┘⚠️重要提醒\0是必须的没有它就不是合法的字符串。很多字符串相关的 bug都是因为少了这个结束符导致的。1.2 字符串的两种写法写法一逐个字符初始化不推荐char str[6] {H, e, l, l, o, \0};要手动加\0麻烦容易忘。写法二用双引号推荐char str[] Hello;用双引号括起来的叫字符串字面量。编译器会自动在末尾加上\0不用你手动写。注意用双引号初始化时数组大小要记得给结束符留位置。比如 Hello 有 5 个字符数组至少要 6 个字节。写成char str[5] Hello是不对的会越界。1.3 字符串字面量用双引号括起来的Hello就是一个字符串字面量。它有几个特点存储在只读内存区不能修改类型是const char[]直接写Hello代表的是这个字符串首字符的地址char *p Hello; // p指向字符串字面量的首地址⚠️注意字符指针指向字符串字面量时不要尝试修改内容否则会崩溃char *p Hello; p[0] h; // ❌ 错误字符串字面量是只读的修改会崩溃但如果是字符数组就可以改char arr[] Hello; arr[0] h; // ✅ 没问题数组在栈上可以修改这是字符数组和字符指针的一个重要区别后面还会详细讲。二、字符串的输入输出2.1 输出字符串printf % s用printf的%s格式符可以输出字符串。#include stdio.h int main() { char str[] Hello World; printf(%s\n, str); // 输出Hello World return 0; }%s的工作原理从你给的地址开始一个字符一个字符地输出直到遇到\0为止。 所以如果你的字符串没有\0%s就会一直往后打打出一堆乱码直到碰巧遇到一个 0 为止 —— 这就是越界了。2.2 输入字符串scanf % s用scanf的%s可以读入字符串。#include stdio.h int main() { char name[20]; printf(请输入你的名字); scanf(%s, name); // 注意数组名前面不用加 printf(你好%s\n, name); return 0; }⚠️scanf 的 % s 有两个大坑坑 1遇到空格就停止输入Zhang San 输出你好Zhangscanf(%s)遇到空格、回车、Tab 就会停止所以它读不了带空格的句子。坑 2不检查数组长度容易越界如果你的数组只有 20 个字节用户输入了 100 个字符scanf照样往里写直接越界 —— 这就是著名的缓冲区溢出问题非常危险。2.3 gets 和 puts了解即可puts输出一行字符串char str[] Hello; puts(str); // 输出字符串自动加换行和printf(%s\n)差不多更简单但只能输出字符串。gets读入一行字符串不推荐char str[100]; gets(str); // 读一整行包括空格gets可以读一整行遇到回车才停止但它完全不检查缓冲区长度比scanf还危险已经被 C 标准废弃了。安全建议实际开发中更推荐用fgets来读字符串可以指定最大读多少更安全。初学阶段先用scanf没问题知道有这个坑就行。三、字符数组 vs 字符指针很多新手搞不清这两个的区别char arr[] Hello; // 字符数组 char *p Hello; // 字符指针它们看起来都能当字符串用但区别很大对比项char arr[] Hellochar *p Hello存储位置栈上局部变量时只读数据区内容可修改吗✅ 可以修改❌ 不能修改arr/p 是什么常量指针地址不能改指针变量可以改指向大小整个数组的大小6 字节指针本身的大小4 或 8 字节3.1 修改内容char arr[] Hello; arr[0] h; // ✅ 没问题数组内容可以改 char *p Hello; p[0] h; // ❌ 崩溃字符串字面量是只读的3.2 修改指向char arr[] Hello; arr World; // ❌ 错误数组名是常量不能改 char *p Hello; p World; // ✅ 没问题p可以指向别的地方3.3 简单总结想修改字符串内容→ 用字符数组只是读字符串→ 两种都可以需要改变指向不同的字符串→ 用字符指针新手建议初学阶段如果你不确定用哪个就用字符数组更安全不容易出问题。四、常用字符串函数C 语言标准库提供了很多处理字符串的函数都在string.h头文件里。下面我们一个个来讲。4.1 strlen求字符串长度size_t strlen(const char *s);作用计算字符串的长度不包括末尾的\0。#include stdio.h #include string.h int main() { char str[] Hello; printf(长度%zu\n, strlen(str)); // 输出 5 return 0; }注意返回值是size_t类型无符号整数用%zu格式化输出长度不包括\0Hello 长度是 5 不是 64.2 strcpy字符串复制char *strcpy(char *dest, const char *src);作用把src字符串复制到dest中包括\0。#include stdio.h #include string.h int main() { char src[] Hello; char dest[20]; strcpy(dest, src); // 把src复制到dest printf(%s\n, dest); // 输出Hello return 0; }⚠️注意dest必须有足够的空间否则会越界会覆盖dest原来的内容4.3 strcat字符串拼接char *strcat(char *dest, const char *src);作用把src拼接到dest的末尾。#include stdio.h #include string.h int main() { char dest[20] Hello ; char src[] World; strcat(dest, src); // 把src拼到dest后面 printf(%s\n, dest); // 输出Hello World return 0; }原理先找到dest末尾的\0把src从那里开始覆盖过去最后加\0。⚠️ 同样要注意dest空间要足够大。4.4 strcmp字符串比较int strcmp(const char *s1, const char *s2);作用比较两个字符串的大小按 ASCII 码逐位比较。返回值s1 s2 → 返回0s1 s2 → 返回正数s1 s2 → 返回负数#include stdio.h #include string.h int main() { printf(%d\n, strcmp(abc, abc)); // 0相等 printf(%d\n, strcmp(abc, abd)); // 负数abc abd printf(%d\n, strcmp(abd, abc)); // 正数abd abc return 0; }⚠️新手常错比较字符串不能用if (s1 s2) { ... } // ❌ 这比的是地址不是内容 if (strcmp(s1, s2) 0) { ... } // ✅ 这样才是比内容比的是两个指针的值地址而不是字符串内容。比较内容一定要用strcmp。4.5 带 n 的安全版本上面的strcpy、strcat、strcmp都有一个 安全版本—— 可以指定最多操作多少个字符防止越界。普通版安全版区别strcpystrncpy最多复制 n 个字符strcatstrncat最多拼接 n 个字符strcmpstrncmp最多比较前 n 个字符比如strncpychar dest[10]; strncpy(dest, Hello World, 9); // 最多复制9个字符防止越界 dest[9] \0; // 注意strncpy不一定自动加\0最好手动补虽然用起来麻烦一点但更安全。实际开发中推荐优先用带 n 的版本。4.6 strchr查找字符char *strchr(const char *s, int c);作用在字符串s中查找字符c第一次出现的位置。找到了 → 返回该位置的指针没找到 → 返回 NULL#include stdio.h #include string.h int main() { char str[] Hello World; char *p strchr(str, o); if (p ! NULL) { printf(找到了位置%td\n, p - str); // 4第5个字符 printf(从这里开始%s\n, p); // o World } return 0; }4.7 strstr查找子串char *strstr(const char *haystack, const char *needle);作用在字符串haystack中查找子串needle第一次出现的位置。找到了 → 返回子串起始位置的指针没找到 → 返回 NULL#include stdio.h #include string.h int main() { char str[] Hello World; char *p strstr(str, World); if (p ! NULL) { printf(找到了%s\n, p); // World } return 0; }五、自己实现字符串函数光会用还不够最好能理解它们是怎么实现的。我们来手写几个加深理解。5.1 实现 strlen思路从开头往后数直到遇到\0。// 自己实现strlen size_t my_strlen(const char *s) { size_t len 0; while (*s ! \0) // 没到结束符就继续 { len; s; } return len; }更简洁的版本size_t my_strlen(const char *s) { const char *p s; while (*p) p; // 一直走到\0 return p - s; // 两个指针相减就是长度 }5.2 实现 strcpy思路一个字符一个字符地复制直到把\0也复制过去。// 自己实现strcpy char *my_strcpy(char *dest, const char *src) { char *p dest; while ((*dest *src)) ; // 空循环体赋值表达式的值就是复制的字符遇到\0就结束 return p; }这个写法很经典 ——*dest *src一步完成了取值、赋值、两个指针后移循环条件就是赋值的结果遇到\0值为 0循环就结束。5.3 实现 strcmp思路逐位比较遇到不同的或者结束符就停下来。// 自己实现strcmp int my_strcmp(const char *s1, const char *s2) { while (*s1 *s2 *s1 *s2) { s1; s2; } return *s1 - *s2; }建议自己动手实现一遍这些函数你对字符串和指针的理解会上一个台阶。这也是面试常考题哦六、字符串常见的坑字符串是新手踩坑的重灾区我们来盘点一下最常见的几个。坑 1忘记 \0char str[5] {H, e, l, l, o}; // 没有\0 printf(%s\n, str); // ❌ 会输出乱码直到遇到0才停解决用双引号初始化或者手动加\0。坑 2数组空间不够char str[5] Hello; // ❌ Hello要6个字节含\05个不够解决数组大小要留够或者直接写char str[] Hello让编译器自己算。坑 3修改字符串字面量char *p Hello; p[0] h; // ❌ 崩溃字面量是只读的解决要修改就用字符数组不要用指针指向字面量然后改。坑 4用 比较字符串char s1[] abc; char s2[] abc; if (s1 s2) { ... } // ❌ 比的是地址不是内容解决用strcmp比较内容。坑 5越界写入char str[5]; strcpy(str, Hello World); // ❌ 严重越界解决确保目标数组足够大或者用strncpy限制长度。七、综合示例示例 1统计字符出现次数#include stdio.h #include string.h int main() { char str[100]; char ch; int count 0; printf(请输入一个字符串); scanf(%s, str); getchar(); // 吃掉回车 printf(请输入要统计的字符); scanf(%c, ch); for (int i 0; str[i] ! \0; i) { if (str[i] ch) { count; } } printf(字符%c出现了%d次\n, ch, count); return 0; }示例 2字符串反转#include stdio.h #include string.h int main() { char str[100]; printf(请输入字符串); scanf(%s, str); int len strlen(str); int left 0; int right len - 1; while (left right) { // 交换左右两个字符 char temp str[left]; str[left] str[right]; str[right] temp; left; right--; } printf(反转后%s\n, str); return 0; }八、本章小结本章我们深入学习了 C 语言中的字符串1. 字符串的本质字符串 字符数组 末尾的\0\0是结束标志不算内容但占一个字节用双引号初始化时编译器自动加\02. 字符数组 vs 字符指针字符数组内容可修改地址不可改字符指针指向字面量内容不可修改指针可以改指向需要修改内容就用数组只读可以用指针3. 常用字符串函数都在 string.h函数作用strlen求字符串长度不含 \0strcpy/strncpy复制字符串strcat/strncat拼接字符串strcmp/strncmp比较字符串strchr查找字符strstr查找子串4. 常见坑点忘记加\0数组空间不够修改字符串字面量用比较字符串内容越界写入学习建议字符串是编程的基本功一定要多练。建议你把常用的字符串函数都自己实现一遍既能加深对指针的理解又能记住函数的用法 —— 一举两得。九、写在最后Talk is cheap. Show me the code.——Linus Torvalds林纳斯・托瓦兹Linux 之父翻译成中文就是废话少说放码过来。这句话是 Linux 之父林纳斯的名言也成为了程序员圈的经典梗。道理很简单说得再多不如直接看代码。学字符串也是一样。看十遍讲解不如自己动手写一遍。写代码、调 bug、踩坑、爬坑 —— 这个过程才是真正的学习。⚠️ 关于本文由于笔者水平有限文中难免存在疏漏、错误或表述不够准确的地方。如果你在阅读过程中发现了任何问题 —— 无论是概念错误、代码 bug、还是表述不清 —— 都欢迎在评论区留言指正我会及时修正。技术之路道阻且长行则将至。我们互相学习共同进步

相关新闻

AI模型压缩实战:剪枝、量化与知识蒸馏技术详解

AI模型压缩实战:剪枝、量化与知识蒸馏技术详解

这次我们来深入探讨AI模型压缩与轻量化的实战技术。如果你在本地部署AI模型时遇到过显存不足、推理速度慢的问题,或者想把大模型集成到移动端、边缘设备中,那么模型压缩技术就是你的必备技能。本文将重点介绍剪枝、量化、知识蒸馏三大核心方法&#xff0…

2026/7/12 2:34:11 阅读更多 →
排序算法稳定性深度解析:从 5 大经典案例到 408 真题陷阱

排序算法稳定性深度解析:从 5 大经典案例到 408 真题陷阱

排序算法稳定性深度解析:从5大经典案例到408真题陷阱1. 稳定性概念的本质与工程意义排序算法的稳定性(Stability)是指当待排序序列中存在多个相同关键字的记录时,排序后这些记录的相对次序是否保持不变。这个看似简单的定义背后&a…

2026/7/12 2:32:10 阅读更多 →
计算机视觉完整学习路径:从CNN到Transformer的实战指南

计算机视觉完整学习路径:从CNN到Transformer的实战指南

最近在辅导一些刚入门计算机视觉的同学时,发现大家普遍面临一个困境:网上资料零散不成体系,从CNN基础到Transformer进阶缺少一条清晰的学习路径。本文基于2026年最新技术趋势,系统梳理从CNN图像分类到U-Net分割,再到Re…

2026/7/12 2:30:10 阅读更多 →

最新新闻

向量数据库实战-利用PostgreSQL+pgvector构建AI 智能应用:AI-Agent集成-智能对话系统

向量数据库实战-利用PostgreSQL+pgvector构建AI 智能应用:AI-Agent集成-智能对话系统

第四章:AI Agent集成 - 从FAQ到智能对话 本章目标: 构建基于RAG架构的智能客服Agent 学习时间: 90分钟 难度等级: ⭐⭐⭐⭐ 高级 本章导读 上一章我们实现了FAQ搜索,但用户真正想要的是"聊天式"的智能回答,而不是冷冰冰的FAQ列表。 这一章,我们把pgvector和大语言模…

2026/7/12 3:28:28 阅读更多 →
VSCode C/C++ 调试输入问题:MinGW32 vs MinGW64 环境配置 3 步根因排查

VSCode C/C++ 调试输入问题:MinGW32 vs MinGW64 环境配置 3 步根因排查

VSCode C/C 调试输入问题:MinGW32 与 MinGW64 环境配置深度解析 当你在 Windows 平台上使用 VSCode 调试 C/C 程序时,是否遇到过 DEBUG CONSOLE 无法进行输入输出的困扰?这个问题看似简单,实则背后隐藏着 MinGW 环境选择的玄机。…

2026/7/12 3:28:28 阅读更多 →
Mythos Preview:AI驱动的自动化渗透测试范式革命

Mythos Preview:AI驱动的自动化渗透测试范式革命

1. 项目概述:一场静默却震耳欲聋的AI能力跃迁 这周,整个AI安全圈没有爆炸性新闻稿,没有铺天盖地的发布会直播,只有一份措辞克制、数据密集的系统卡片(System Card)和一份由英国AI安全研究所(AIS…

2026/7/12 3:26:27 阅读更多 →
Conda vs Pip 包管理深度对比:5个场景下的选择策略与性能影响

Conda vs Pip 包管理深度对比:5个场景下的选择策略与性能影响

Conda与Pip的终极对决:5个深度学习场景下的智能选择指南当你在深夜调试一个复杂的深度学习模型时,突然遭遇"Could not find a version that satisfies the requirement"错误——这种时刻,选择正确的包管理工具可能比算法本身更影响…

2026/7/12 3:26:27 阅读更多 →
CTF Web备份泄露实战:Python脚本+3款工具(御剑/Dirsearch/ihoney)对比评测

CTF Web备份泄露实战:Python脚本+3款工具(御剑/Dirsearch/ihoney)对比评测

CTF Web备份泄露实战:三款工具与Python脚本深度评测在CTF竞赛和实际渗透测试中,Web备份文件泄露是最常见的安全漏洞之一。这类漏洞往往源于开发人员的疏忽——将包含敏感信息的备份文件遗留在Web目录中。本文将深入分析御剑、Dirsearch和ihoneyBakFileSc…

2026/7/12 3:22:25 阅读更多 →
AI音乐创作指南:用Suno制作国歌风格原创音乐的完整流程

AI音乐创作指南:用Suno制作国歌风格原创音乐的完整流程

1. 先搞清楚 Suno 能做什么,不能做什么Suno 是一个 AI 音乐生成平台,它最核心的能力是让你用文字描述(比如“一段激昂的管弦乐,带有爱国情怀”)来生成一段完整的音乐,包括旋律、和声,甚至 AI 演…

2026/7/12 3:20:25 阅读更多 →

日新闻

互联网大厂 Java 求职面试:燕双非的搞笑回答与技术探讨

互联网大厂 Java 求职面试:燕双非的搞笑回答与技术探讨

互联网大厂 Java 求职面试:燕双非的搞笑回答与技术探讨 在一个阳光明媚的上午,互联网大厂的面试官坐在桌前,准备迎接他的面试候选人——燕双非,一个以搞笑和幽默著称的程序员。第一轮提问 面试官:燕双非,作…

2026/7/12 0:03:13 阅读更多 →
车载以太网PMA测试设备选型:示波器、VNA、信号源3类仪器关键参数与预算评估

车载以太网PMA测试设备选型:示波器、VNA、信号源3类仪器关键参数与预算评估

车载以太网PMA测试设备选型:示波器、VNA、信号源3类仪器关键参数与预算评估在智能驾驶和车联网技术快速发展的今天,车载以太网作为新一代车载网络的核心传输技术,其物理层性能直接决定了数据传输的可靠性和稳定性。1000BASE-T1作为当前主流的…

2026/7/12 0:03:14 阅读更多 →
VSCode EIDE 插件 2.0:APM32/STM32 项目迁移实战,5步完成Keil工程转换

VSCode EIDE 插件 2.0:APM32/STM32 项目迁移实战,5步完成Keil工程转换

VSCode EIDE 插件 2.0:APM32/STM32 项目迁移实战指南嵌入式开发领域正经历一场工具链的静默革命。当传统Keil用户首次打开VSCode的扩展市场搜索EIDE时,往往会惊讶于这个看似简单的插件竟能重构十余年的开发习惯。本文将揭示如何用五个精准步骤&#xff0…

2026/7/12 0:03:14 阅读更多 →

周新闻

互联网大厂 Java 求职面试:燕双非的搞笑回答与技术探讨

互联网大厂 Java 求职面试:燕双非的搞笑回答与技术探讨

互联网大厂 Java 求职面试:燕双非的搞笑回答与技术探讨 在一个阳光明媚的上午,互联网大厂的面试官坐在桌前,准备迎接他的面试候选人——燕双非,一个以搞笑和幽默著称的程序员。第一轮提问 面试官:燕双非,作…

2026/7/12 0:03:13 阅读更多 →
车载以太网PMA测试设备选型:示波器、VNA、信号源3类仪器关键参数与预算评估

车载以太网PMA测试设备选型:示波器、VNA、信号源3类仪器关键参数与预算评估

车载以太网PMA测试设备选型:示波器、VNA、信号源3类仪器关键参数与预算评估在智能驾驶和车联网技术快速发展的今天,车载以太网作为新一代车载网络的核心传输技术,其物理层性能直接决定了数据传输的可靠性和稳定性。1000BASE-T1作为当前主流的…

2026/7/12 0:03:14 阅读更多 →
VSCode EIDE 插件 2.0:APM32/STM32 项目迁移实战,5步完成Keil工程转换

VSCode EIDE 插件 2.0:APM32/STM32 项目迁移实战,5步完成Keil工程转换

VSCode EIDE 插件 2.0:APM32/STM32 项目迁移实战指南嵌入式开发领域正经历一场工具链的静默革命。当传统Keil用户首次打开VSCode的扩展市场搜索EIDE时,往往会惊讶于这个看似简单的插件竟能重构十余年的开发习惯。本文将揭示如何用五个精准步骤&#xff0…

2026/7/12 0:03:14 阅读更多 →

月新闻