
🏠个人主页:黎雁
🎬作者简介:C/C++/JAVA后端开发学习者
❄️个人专栏:C语言、数据结构(C语言)、EasyX、游戏、规划
✨ 从来绝巘须孤往,万里同尘即玉京

文章目录
-
- [一、字符处理函数:分类+转换 📚](#一、字符处理函数:分类+转换 📚)
-
- [1. 字符分类函数:精准判断字符属性](#1. 字符分类函数:精准判断字符属性)
- [2. 字符转换函数:快速切换大小写](#2. 字符转换函数:快速切换大小写)
- [二、strlen:字符串长度计算的坑与实现 🚨](#二、strlen:字符串长度计算的坑与实现 🚨)
-
- [1. 函数核心要点:必须掌握的3个细节](#1. 函数核心要点:必须掌握的3个细节)
- [2. strlen三种模拟实现:笔面试高频考点](#2. strlen三种模拟实现:笔面试高频考点)
- [写在最后 📝](#写在最后 📝)
在C语言的字符串操作领域,字符处理函数和 strlen 是绕不开的基础内容。它们不仅是日常代码编写的常用工具,更是笔面试中考察字符串基础能力的高频考点。今天这篇文章,就带大家吃透字符分类、转换函数,以及 strlen 的使用陷阱和三种模拟实现方式!
一、字符处理函数:分类+转换 📚
字符分类与转换函数是处理单个字符的核心工具,使用时需要包含头文件 <ctype.h>。掌握这些函数,能让我们对字符的筛选、转换操作变得简洁高效。
1. 字符分类函数:精准判断字符属性
这类函数的参数是字符的ASCII码值(传入char类型会自动提升为int),返回值为非零(真) 或 0(假)。常用函数及功能如下表所示:
| 函数 | 功能说明 | 典型应用场景 |
|---|---|---|
iscntrl |
判断是否为控制字符(ASCII 0~31、127) | 过滤不可打印的控制字符 |
isspace |
判断是否为空白字符(空格、\n、\t、\r等) | 去除字符串首尾空格 |
isdigit |
判断是否为十进制数字 0-9 |
提取字符串中的数字字符 |
islower |
判断是否为小写字母 a-z |
字符串统一转大写 |
isupper |
判断是否为大写字母 A-Z |
字符串统一转小写 |
isalpha |
判断是否为字母(a-z / A-Z) |
校验输入是否为纯字母 |
isalnum |
判断是否为字母或数字 | 校验账号密码合法性 |
ispunct |
判断是否为标点符号(非字母、数字、空格) | 文本符号的筛选统计 |
💡 实战示例:提取字符串中的数字字符
c
#include <stdio.h>
#include <ctype.h>
int main()
{
char arr[] = "abcdef1w2#gty78";
int i = 0;
while (arr[i] != '\0')
{
if (isdigit(arr[i])) // 判断当前字符是否为数字
{
printf("%c ", arr[i]);
}
i++;
}
// 运行输出:1 2 7 8
return 0;
}
2. 字符转换函数:快速切换大小写
C语言提供了两个专门用于字母大小写转换的函数,用法简单且高效:
tolower(int c):将大写字母转为小写,非字母字符返回原值toupper(int c):将小写字母转为大写,非字母字符返回原值
✨ 优化示例:将字符串中的小写字母转为大写
对比手动计算ASCII码差值的方式,使用toupper函数的代码更简洁易读:
c
#include <stdio.h>
#include <ctype.h>
int main()
{
char arr[] = "aCbCdeF12w#gTy78";
int i = 0;
while (arr[i] != '\0')
{
if (islower(arr[i])) // 先判断是否为小写字母
{
arr[i] = toupper(arr[i]); // 转为大写
}
printf("%c", arr[i]);
i++;
}
// 运行输出:ACBCDEF12W#GTY78
return 0;
}
二、strlen:字符串长度计算的坑与实现 🚨
strlen 是用来计算字符串长度的库函数,使用时需要包含头文件 <string.h>。这个函数看似简单,但暗藏不少易错点,同时它的模拟实现也是笔面试的常客。
1. 函数核心要点:必须掌握的3个细节
- 函数原型 :
size_t strlen(const char* str);
这里的返回值size_t是一个无符号整数类型 (本质是unsigned int),这是最容易踩坑的地方! - 计算规则 :从传入地址开始,向后统计字符个数,直到遇到
\0停止,不包含\0本身。 - 打印格式 :推荐使用
%zd来匹配size_t类型,避免格式不匹配导致的输出错误。
❌ 经典踩坑:无符号数的比较陷阱
由于 strlen 返回无符号数,直接用它的返回值做减法比较,会出现和直觉相反的结果:
c
#include <stdio.h>
#include <string.h>
int main()
{
char arr1[] = "abcdef"; // 长度6
char arr2[] = "abc"; // 长度3
// 坑点:3-6 = -3,无符号数中-3会被视为极大值
if (strlen(arr2) - strlen(arr1) >= 0)
{
printf("arr2>arr1\n"); // 错误输出!
}
else
{
printf("arr2<=arr1\n");
}
// 正确解法1:改为直接比较
if (strlen(arr2) >= strlen(arr1)) {}
// 正确解法2:强制转为有符号整数
if ((int)strlen(arr2) - (int)strlen(arr1) >= 0) {}
return 0;
}
2. strlen三种模拟实现:笔面试高频考点
模拟实现 strlen 有三种经典思路,分别对应不同的编程思想,我们逐一讲解并实现。
实现前要注意:传入的字符串指针可能为NULL ,所以需要用 assert 断言来保证代码健壮性,使用时需包含 <assert.h>。
方式1:计数器法(最易理解)
核心思路 :定义一个计数器变量,遍历字符串,每访问一个非 \0 字符,计数器加1,直到遇到 \0 停止。
c
size_t my_strlen1(const char* str)
{
assert(str != NULL); // 防止传入空指针
size_t count = 0;
while (*str++) // 先判断*str是否为\0,再让指针后移
{
count++;
}
return count;
}
方式2:指针-指针法(空间最优)
核心思路 :利用指针运算的特性------两个指向同一数组的指针相减,结果为指针之间的元素个数。
c
size_t my_strlen2(const char* str)
{
assert(str); // 简写:str为NULL时断言失败
const char* p = str; // 保存起始地址
while (*p) // 找到\0的位置
{
p++;
}
return p - str; // 指针差值即字符串长度
}
方式3:递归法(无临时变量)
核心思路 :递归的本质是把大问题拆成小问题。计算 str 的长度 = 1 + 计算 str+1 的长度,直到 str 指向 \0 时返回0。
c
size_t my_strlen3(const char* str)
{
assert(str);
if (*str == '\0')
return 0;
else
return 1 + my_strlen3(str + 1); // 递归调用
}
💡 测试三种实现方式
c
#include <stdio.h>
#include <assert.h>
// 上面的三个my_strlen函数写在这里
int main()
{
char arr[] = "abcdef";
printf("%zd\n", my_strlen1(arr)); // 输出:6
printf("%zd\n", my_strlen2(arr)); // 输出:6
printf("%zd\n", my_strlen3(arr)); // 输出:6
return 0;
}
写在最后 📝
字符分类和转换函数是字符串处理的"基本功",熟练使用它们能大幅提升代码效率;而 strlen 函数的核心陷阱在于无符号返回值,笔试时一定要警惕这个易错点。
三种模拟实现 strlen 的方法,分别体现了"迭代""指针运算"和"递归"三种编程思路,笔面试中很可能会要求手写其中一种,建议大家都动手敲一遍加深理解。
下一篇文章,我们将聚焦字符串操作的核心函数------strcpy 和 strcat,讲解它们的使用规则、注意事项以及模拟实现,帮你吃透长度不受限制的字符串函数!