C语言字符串函数详解:字符处理、strlen、strcpy、strcat等使用与模拟实现
✨ 用 清晰易懂的图解 帮你建立直观认知 ,用通俗的 代码语言 帮你落地理解, 让每个知识点都能 轻松get !
🚀 个人主页 :0xCode小新 · CSDN
🌱 代码仓库 :0xCode小新· Gitee
📌 专栏系列
- 📖 《c语言》
💬 座右铭 : “ 积跬步,以致千里。”
在程序设计的过程中,字符与字符串的处理是一项非常基础且频繁的任务。为了简化开发者的工作,提高代码的效率与可维护性,C 语言标准库贴心地提供了一整套丰富的字符与字符串操作函数。
这些函数涵盖了字符分类、字符转换以及字符串处理等多个维度,能够满足各种场景下的开发需求。在接下来的内容中,我将为大家系统讲解这一系列常用函数:从判断字符类型的字符分类函数、实现大小写转换的字符转换函数,到处理字符串的核心函数(如
strlen
、strcpy
、strcat
、strcmp
等)。对于每一个函数,我们不仅会深入解析其基本用法、参数含义与返回值特性,还会通过模拟实现的方式,带大家探究函数背后的实现逻辑与设计思想。这不仅能帮助大家更好地理解函数的工作原理,更能提升对字符串操作本质的认知,为编写高效、安全的代码打下坚实基础。
文章目录
- 1. 字符分类函数
- 2. 字符转换函数
- 3. [strlen](https://legacy.cplusplus.com/reference/cstring/strlen/?kw=strlen)的使用和模拟实现
- 3.1 功能与核心要点
- 3.2 重要注意事项(易错点)
- 3.3 strlen的模拟实现
- 4. [strcpy](https://legacy.cplusplus.com/reference/cstring/strcpy/)的使用和模拟实现
- 4.1 功能与核心要点
- 4.2 关键约束与注意事项(安全使用的前提)
- 4.3 strcpy的模拟实现
- 5. [strcat](https://legacy.cplusplus.com/reference/cstring/strcat/)的使用和模拟实现
- 5.1 功能与核心要点
- 5.2 关键约束与注意事项
- 5.3 strcat的模拟实现
- 6. [strcmp](https://legacy.cplusplus.com/reference/cstring/strcmp/)的使用和模拟实现
- 6.1 功能与核心要点
- 6.2 返回值标准
- 6.3 strcmp函数的模拟实现
- 7. [strncpy](https://legacy.cplusplus.com/reference/cstring/strcpy/)函数的使用
- 7.1 功能与核心要点
- 7.2 与 strcpy 的关键区别
- 7.3 重要注意事项
- 7.4 strncpy函数的模拟实现
- 8. [strncat](https://legacy.cplusplus.com/reference/cstring/strncat/)函数的使用
- 8.1 功能与核心要点
- 8.2 与strcat的关键区别
- 8.3 重要行为特点
- 8.4 **strncat函数的模拟实现**
- 9. [strncmp](https://legacy.cplusplus.com/reference/cstring/strncmp/)函数的使用
- 9.1 功能与核心要点
- 9.2 与strcmp的关键区别
- 9.3 返回值标准
- 9.4 strncmp函数的模拟实现
- 10. [strstr](https://legacy.cplusplus.com/reference/cstring/strstr/)的使用和模拟实现
- 10.1 功能与核心要点
- 10.2 重要特性
- 10.3 strstr函数的模拟实现
- 11. [strtok](https://legacy.cplusplus.com/reference/cstring/strtok/)函数的使用
- 11.1 功能与核心要点
- 11.2 关键特性与行为
- 11.3 参数说明
- 11.4 返回值
- 11.5 使用模式与示例
- 12. [strerror](https://legacy.cplusplus.com/reference/cstring/strerror/)函数的使用
- 12.1 功能与核心要点
- 12.2 错误处理机制上下文
- 12.3 函数参数与返回值
- 12.4 基本使用模式
- 12.5 perror函数
- **perror 的功能:**
- 结语:
1. 字符分类函数
C语言中有⼀系列的函数是专门做字符分类的,也就是一个字符是属于什么类型的字符的。这些函数的使用都需要包含一个头文件是 ctype.h
功能概述:
字符分类函数用于判断字符的类型归属,每个函数检查字符是否属于特定类别,符合条件返回非0值(真),否则返回0。
主要函数列表:
函数 | 功能描述 |
---|---|
iscntrl | 检查是否为控制字符 |
isspace | 检查是否为空白字符(空格、换页、换行、回车、制表符等) |
isdigit | 检查是否为十进制数字(0-9) |
isxdigit | 检查是否为十六进制数字(0-9, a-f, A-F) |
islower | 检查是否为小写字母(a-z) |
isupper | 检查是否为大写字母(A-Z) |
isalpha | 检查是否为字母(a-z或A-Z) |
isalnum | 检查是否为字母或数字 |
ispunct | 检查是否为标点符号(非数字/字母的图形字符) |
isgraph | 检查是否为任何图形字符 |
isprint | 检查是否为任何可打印字符(包括图形字符和空白字符) |
- 所有函数使用方法相似,参数为
int
类型(字符的ASCII码值) - 返回值:符合条件返回非0整数,不符合返回0
- 通常与字符转换函数(
tolower
、toupper
)配合使用
我们举其中一个例子来讲解:
int islower ( int c );
islower
是能够判断参数部分的 c 是否是小写字母的。通过返回值来说明是否是小写字母,如果是小写字母就返回非0的整数,如果不是小写字母,则返回0。
练习: 写一个代码,将字符串中的小写字母转大写,其他字符不变。
void my_islower(char* str1)
{while (*str1 != '\0'){//if (*str1>= 'a' && *str1 <= 'z')if (islower(*str1)){//*str1 -= 32;*str1 = toupper(*str1); //toupper函数在下面会讲到}str1++;}
}int main()
{char arr[20] = { "aBcDeF" };my_islower(arr);printf("%s ", arr);return 0;
}
其余函数的学习也同样重要。建议大家自行练习其余函数的使用与实现 —— 通过这种举一反三的实践,才能真正吃透字符串处理函数的精髓,在实际编程中做到灵活运用、得心应手。
2. 字符转换函数
头文件: #include <ctype.h>
功能概述:
字符转换函数用于对字符进行大小写转换。它们通常与字符分类函数(如
islower
,isupper
)配合使用,先判断字符类型,再进行安全的、与本地字符集无关的转换。
函数 | 功能描述 |
---|---|
int tolower ( int c ); | 将传入的大写字母转换为对应的小写字母。如果参数不是大写字母,则返回原字符。 |
int toupper ( int c ); | 将传入的小写字母转换为对应的大写字母。如果参数不是小写字母,则返回原字符。 |
在上面注释掉的代码中,我们将小写转大写,是-32完成的效果(大小写字母的ASCII码值相差32),有了转换函数,就可以直接使用 tolower
函数。
int main()
{printf("%c\n", tolower('A'));printf("%c\n", tolower('a'));printf("%c\n", toupper('a'));printf("%c\n", toupper('A'));return 0;
}
3. strlen的使用和模拟实现
头文件: #include <string.h>
函数原型:
size_t strlen ( const char * str );
3.1 功能与核心要点
strlen
函数用于计算字符串的长度。
- 工作原理:从传入的指针开始,顺序扫描字符串,直到遇到字符串结束标志 ‘\0’ 为止。返回值是 ‘\0’ 之前出现的字符个数(不包含 ‘\0’)。
- 关键约束:参数
str
必须指向一个以 ‘\0’ 结尾的有效字符串。否则,函数会越界访问内存,导致未定义行为。- 返回值类型:返回类型是
size_t
,这是一个无符号整型。这是导致编程错误的一个常见原因。
3.2 重要注意事项(易错点)
由于 size_t
是无符号的,在表达式中使用 strlen
的返回值进行算术运算时需要特别小心,特别是当它参与比较时:
int main()
{if ((int)strlen("abc") - (int)strlen("abcdef") > 0) //strlen的返回值为size_t类型(无符号整型),在计算是可能会存在负数,所以需要强转为int类型printf(">");elseprintf("<");return 0;
}size_t my_strlen(const char* str)
{int count = 0;while (*str != '\0'){count++;str++;}return count;
}
3.3 strlen的模拟实现
方式一:计数器方式(最直观)
- 思路:创建一个计数器
count
,遍历字符串,每过一个字符计数器加一,遇到\0
时停止。 - 优点:逻辑清晰,易于理解。
size_t my_strlen(const char* str)
{int count = 0;while (*str != '\0'){count++;str++;}return count;
}
方式二:递归方式(不创建临时变量)
- 思路:将问题分解。字符串的长度 = 1(当前字符) + 后面子串的长度。递归基准情况是遇到
\0
时返回 0。 - 缺点:递归有栈开销,效率不高,不适合长字符串。
size_t my_strlen(const char* str)
{if (*str == '\0')return 0;elsereturn 1 + my_strlen(str + 1);
}
方式三:指针减指针方式(最简洁)
- 思路:使用一个指针
p
从字符串开头遍历到\0
的位置。字符串长度就是尾指针p
减去起始指针str
。 - 优点:代码非常简洁,体现了指针运算的强大。
size_t my_strlen(const char* str)
{assert(str);const char* p = str;while (*p != '\0'){p++;}return p - str;
}
4. strcpy的使用和模拟实现
头文件: #include <string.h>
函数原型:
char* strcpy ( char * destination, const char * source );
4.1 功能与核心要点
strcpy
函数用于将一个字符串(包括结束符)复制到另一个内存空间。核心功能:将 source(源字符串) 指向的 C 字符串(包括终止空字符
\0
)完整地复制到 destination(目标空间) 指向的数组中。复制过程在遇到源字符串的\0
后停止,并会将该\0
一同拷贝过去。
4.2 关键约束与注意事项(安全使用的前提)
使用 strcpy
时必须严格遵守以下规则,否则会导致严重的运行时错误:
- 源字符串约束:源字符串
source
必须以\0
结束。这是函数判断复制何时停止的唯一依据。 - 目标空间约束:
- 必须足够大:目标空间必须足够容纳整个源字符串(包括
\0
)。这是导致缓冲区溢出漏洞的最常见原因。 - 必须可修改:目标空间不能是字符串常量或常量指针(如 char* dest = “hello”),必须是一个可写的字符数组或已分配的内存。
- 必须足够大:目标空间必须足够容纳整个源字符串(包括
- 返回值:函数返回目标空间的起始地址 (destination)。它允许函数链式访问,例如 printf(“%s”, strcpy(dest, src));。
4.3 strcpy的模拟实现
char* my_strcpy(char* dest, const char* src)
{assert(dest && src);char* p = dest;while (*dest++ = *src++);return p;
}
- 参数设计:
- 目标指针
dest
不加const
,因为需要修改它。 - 源指针
src
用const
修饰,防止意外修改源字符串。
- 目标指针
- 断言检查:使用
assert
对dest
和src
进行非空断言,提高代码健壮性。 - 复制逻辑:核心代码 while (*dest++ = *src++); 是一个高度精简的写法,它同时完成了:
- 赋值:
*dest = *src
- 判断:赋值表达式的值就是所赋字符的值,遇到
\0
时循环条件为假,终止循环。 - 指针后移:
dest++
,src++
- 赋值:
- 返回值:在操作指针
dest
之前,先保存其起始地址到ret
,最后返回ret
,以符合原函数的行为。
5. strcat的使用和模拟实现
头文件: #include <string.h>
函数原型:
char* strcat ( char * destination, const char * source );
5.1 功能与核心要点
strcat
函数用于将一个字符串**追加(连接)**到另一个字符串的末尾。核心功能:将 source(源字符串) 的完整内容(包括终止空字符
\0
)追加到 destination(目标字符串) 的末尾。操作会覆盖目标字符串原有的终止空字符\0
,并在新形成的字符串末尾添加一个新的\0
。
5.2 关键约束与注意事项
使用 strcat
时必须严格遵守以下规则:
- 源字符串约束:源字符串
source
必须以\0
结束。 - 目标字符串约束:
- 必须包含
\0
:目标字符串也必须以\0
结尾,这样函数才能找到追加的起始位置(即覆盖掉这个\0
)。 - 必须足够大:目标空间必须足够容纳目标字符串本身(不含原
\0
) + 源字符串完整内容(含\0
)。这是导致缓冲区溢出的常见原因。 - 必须可修改。
- 必须包含
- 返回值:函数返回目标空间的起始地址 (
destination
),支持链式访问。
5.3 strcat的模拟实现
char* my_strcat(char* dest, const char* src)
{assert(dest && src);char* p = dest;while (*dest)dest++;while (*dest++ = *src++);return p;
}
strcat
的模拟实现可以看作是两个步骤的组合:
- 第一步:寻找目标字符串的结尾(类似
strlen
的逻辑)- 使用循环,将
dest
指针移动到目标字符串的\0
处。这是追加操作的起点。
- 使用循环,将
- 第二步:从该点开始复制源字符串(类似
strcpy
的逻辑)- 从当前
dest
位置开始,执行与strcpy
完全相同的复制操作:while(*dest++ = *src++);,将源字符串(包括\0
)复制过去。
- 从当前
- 关键点:
- 不能自己给自己追加(未定义行为):PDF中提出了“字符串自己给自己追加,如何?”的问题。这是一个重要陷阱。因为
strcat
会覆盖结束符,如果源和目标重叠(特别是自己追加自己),在复制过程中会破坏源字符串的内容,导致未定义行为。要实现安全的自身追加,必须使用memmove
等允许内存重叠操作的函数,或者使用strncat
并谨慎计算长度。
- 不能自己给自己追加(未定义行为):PDF中提出了“字符串自己给自己追加,如何?”的问题。这是一个重要陷阱。因为
6. strcmp的使用和模拟实现
头文件: #include <string.h>
函数原型:
int strcmp ( const char * str1, const char * str2 );
6.1 功能与核心要点
strcmp
函数用于比较两个字符串的内容是否相等,而不是比较它们的地址。
- 核心功能:按字典序(lexicographical order) 比较两个字符串。函数从两个字符串的第一个字符开始,逐个比较对应位置字符的ASCII码值。
- 比较规则:
- 如果对应字符相等,则继续比较下一对字符。
- 如果遇到不相等的字符,或者遇到字符串的结束符
\0
,则停止比较。
6.2 返回值标准
函数的返回值反映了比较的结果,标准规定:
返回值 | 含义 |
---|---|
< 0 | 字符串 str1 小于 字符串 str2 |
= 0 | 字符串 str1 等于 字符串 str2 |
> 0 | 字符串 str1 大于 字符串 str2 |
重要理解:"大于"或"小于"指的是在字典中的先后顺序。具体来说,是由第一对不相等的字符的ASCII码值之差决定的。例如,"apple"
和 "banana"
比较,第一对字符 'a'
和 'b'
不同,因为 'a'
的ASCII码(97)小于 'b'
(98),所以 strcmp("apple", "banana")
返回一个负数。
6.3 strcmp函数的模拟实现
int my_strcmp(const char* str1, const char* str2)
{assert(str1 && str2);while (*str1 == *str2){if (*str1 == '\0')return 0;str1++;str2++;}if (*str1 > *str2)return 1;elsereturn -1;
}
- 参数设计:两个源指针都用
const
修饰,保证不修改原字符串。 - 核心循环:while(*str1 == *str2) 是实现的精髓。只要对应字符相等,就继续循环。
- 循环体内检查:如果此时
*str1
是\0
,说明两个字符串同时结束且所有字符都相等,直接返回0
表示相等。 - 如果字符相等但不是
\0
,则指针后移,比较下一对字符。
- 循环体内检查:如果此时
- 循环结束后的处理:当循环条件 *str1 == *str2 不成立时,说明遇到了不相等的字符。此时,根据结果返回1或-1
- 断言检查:使用
assert
确保传入的指针有效。
7. strncpy函数的使用
头文件: #include <string.h>
函数原型:
char * strncpy ( char * destination, const char * source, size_t num );
7.1 功能与核心要点
strncpy
是strcpy
的安全增强版本,允许限制复制的字符数量。
- 核心功能:将源字符串的前
num
个字符复制到目标空间。- 两种复制模式:
- 正常情况:如果源字符串长度 ≥
num
,则复制前num
个字符(不会自动添加\0
)- 特殊情况:如果源字符串长度 <
num
,则先复制整个源字符串(包括\0
),然后在目标空间后用\0
填充,直到写满num
个字符。
7.2 与 strcpy 的关键区别
特性 | strcpy | strncpy |
---|---|---|
安全性 | 不安全,容易缓冲区溢出 | 相对安全,可控制复制长度 |
终止条件 | 遇到 \0 停止 | 达到 num 个字符停止 |
自动添加 \0 | 总是自动添加 | 不保证目标字符串以 \0 结尾 |
填充行为 | 无 | 源字符串较短时用 \0 填充 |
7.3 重要注意事项
- 不自动添加终止符:这是
strncpy
最容易被误解的地方。如果源字符串长度 ≥num
,目标字符串可能不以\0
结尾。 - 手动添加终止符:安全的使用模式是复制后手动添加终止符:
strncpy(dest, src, dest_size - 1);
dest[dest_size - 1] = '\0'; // 确保字符串正确终止
7.4 strncpy函数的模拟实现
char* my_strncpy(char *dest, const char *src, size_t n)
{assert(dest && src);char *ret = dest;while (n-- && (*dest++ = *src++));while (n-- > 0)*dest++ = '\0';return ret;
}
- 参数验证:使用
assert
确保指针有效性 - 两阶段复制:
- 第一阶段:复制源字符串内容,直到达到
n
个字符或遇到\0
- 第二阶段:如果还有剩余空间,用
\0
填充
- 第一阶段:复制源字符串内容,直到达到
- 返回值:返回目标字符串起始地址,与标准库保持一致
8. strncat函数的使用
头文件: #include <string.h>
函数原型:
char * strncat ( char * destination, const char * source, size_t num );
8.1 功能与核心要点
strncat
是strcat
的安全增强版本,允许限制追加的字符数量。
- 核心功能:将源字符串的前
num
个字符追加到目标字符串的末尾。- 智能终止:无论复制多少个字符,函数总是会在结果字符串的末尾添加一个
\0
。- 安全机制:如果源字符串长度小于
num
,则只复制到源字符串的\0
为止。
8.2 与strcat的关键区别
特性 | strcat | strncat |
---|---|---|
安全性 | 不安全,可能缓冲区溢出 | 相对安全,可控制追加长度 |
终止保证 | 自动添加 \0 | 总是自动添加 \0 |
长度控制 | 无限制 | 限制最大追加字符数 num |
自身追加 | 导致未定义行为 | 可以安全处理(需谨慎) |
8.3 重要行为特点
- 总是以
\0
结尾:这是strncat
与strncpy
最重要的区别。strncat
保证结果字符串正确终止。 - 实际复制字符数:实际复制的字符数是
min
(num, 源字符串剩余长度)。 - 目标空间计算:目标空间必须至少能容纳:目标原长度 + min(num, 源字符串长度) + 1(用于
\0
)。
8.4 strncat函数的模拟实现
char* my_strncat(char *dest, const char *src, size_t n)
{assert(dest && src);char *ret = dest;while (*dest) dest++;while (n-- && (*dest++ = *src++));*dest = '\0'; //确保以\0结尾return ret;
}
9. strncmp函数的使用
头文件: #include <string.h>
函数原型:
int strncmp ( const char * str1, const char * str2, size_t num );
9.1 功能与核心要点
strncmp
是strcmp
的安全增强版本,允许限制比较的字符数量。
- 核心功能:比较两个字符串的前
num
个字符。- 比较规则:逐个比较对应位置的字符ASCII码值,最多比较
num
个字符。- 提前终止:如果在比较完
num
个字符之前就发现不匹配的字符,立即返回结果。
9.2 与strcmp的关键区别
特性 | strcmp | strncmp |
---|---|---|
比较范围 | 整个字符串(直到 \0 ) | 最多前 num 个字符 |
安全性 | 可能比较过长字符串 | 可控制最大比较长度 |
使用场景 | 完整字符串比较 | 前缀比较、固定长度字段比较 |
9.3 返回值标准
与 strcmp
相同,遵循标准规定:
返回值 | 含义 |
---|---|
< 0 | str1 小于 str2 (在前 num 个字符内) |
= 0 | 两个字符串的前 num 个字符相等 |
> 0 | str1 大于 str2 (在前 num 个字符内) |
9.4 strncmp函数的模拟实现
int my_strncmp(const char *s1, const char *s2, size_t n)
{assert(s1 && s2);if (n == 0) return 0;while (n-- && *s1 && (*s1 == *s2)) {s1++;s2++;}return *(unsigned char*)s1 - *(unsigned char*)s2;
}
- 边界条件处理:
- 检查
num == 0
的情况,直接返回相等 - 使用断言确保指针有效性
- 检查
- 核心比较逻辑:
- 使用
while (num-- && *s1 && (*s1 == *s2))
同时检查:- 是否还有剩余比较次数 (
num--
) - 两个字符串是否都未结束 (
*s1 && *s2
) - 当前字符是否相等 (
*s1 == *s2
)
- 是否还有剩余比较次数 (
- 使用
- 返回值处理:
- 使用
unsigned char
转换避免符号扩展问题 - 正确处理三种结束情况:
- 发现不匹配字符
- 达到比较长度限制
- 某个字符串提前结束
- 使用
10. strstr的使用和模拟实现
头文件: #include <string.h>
函数原型:
char * strstr ( const char * str1, const char * str2 );
10.1 功能与核心要点
strstr
函数用于在字符串中查找子字符串。
- 核心功能:在
str1
(主字符串)中查找str2
(子字符串)第一次出现的位置。- 返回值:
- 如果找到,返回指向
str1
中第一次出现str2
位置的指针- 如果未找到,返回
NULL
指针- 匹配规则:匹配过程不包含终止空字符,但会在空字符处停止。
10.2 重要特性
- 空子字符串处理:如果
str2
是空字符串,函数返回str1
的起始地址。 - 大小写敏感:匹配是区分大小写的。
- 部分匹配:查找的是完整的子字符串,不是单个字符。
10.3 strstr函数的模拟实现
char* my_strstr(const char* str1, const char* str2)
{const char* cur = str1;if (*str2 == '\0')return (char*)str1;while (*cur){const char* s1 = cur;const char* s2 = str2;while (*s1 != '\0' && *s2 != '\0' && *s1 == *s2){s1++;s2++;}if (*s2 == '\0')return (char*)cur;if (*s1 == '\0') break;cur++;}return NULL;
}
- 双重循环结构:
- 外层循环:遍历主字符串的每个可能起始位置
- 内层循环:从当前起始位置开始与子字符串逐个字符比较
- 边界情况处理:
- 空子字符串的特殊处理
- 主字符串提前结束的优化
- 算法复杂度:
- 最坏情况:O(n×m),其中n是主字符串长度,m是子字符串长度
- 实际应用中可以通过更高级算法(如KMP)优化(下期预告!)
11. strtok函数的使用
头文件: #include <string.h>
函数原型:
char * strtok ( char * str, const char * delimiters );
11.1 功能与核心要点
strtok
函数用于将字符串分割成多个标记(tokens),是字符串分词的核心函数。
- 核心功能:根据指定的分隔符集合,将字符串分割成一系列子字符串。
- 工作原理:在字符串中查找分隔符,将其替换为
\0
,并返回指向当前标记的指针。- 状态保持:函数内部维护静态变量来记录分割位置,支持多次调用完成整个字符串的分割。
11.2 关键特性与行为
- 修改原字符串:
strtok
会直接修改输入的字符串,将分隔符替换为\0
。 - 两次调用模式:
- 首次调用:传入待分割的字符串指针
- 后续调用:传入
NULL
,继续从上次位置分割
- 分隔符集合:
delimiters
参数是一个字符串,包含所有可能的分隔字符。
11.3 参数说明
参数 | 说明 |
---|---|
str | 待分割的字符串(第一次调用),或 NULL (后续调用) |
delimiters | 分隔符集合字符串,如 " ,." 表示空格、逗号、句号都是分隔符 |
11.4 返回值
- 成功:返回指向当前标记的指针
- 结束:没有更多标记时返回
NULL
11.5 使用模式与示例
基本使用模式:
int main()
{char str[] = "apple,banana,orange,grape"; // 必须可修改(不能是字符串常量)char delimiters[] = ","; // 分隔符:逗号char *token;// 第一次调用:传入字符串token = strtok(str, delimiters);// 后续调用:传入NULLwhile (token != NULL) {printf("标记: %s\n", token);token = strtok(NULL, delimiters); // 继续分割}return 0;
}
复杂分隔符示例:
int main()
{char text[] = "Hello, World! This is-a test.";char delims[] = " ,!-."; // 多种分隔符char *token;printf("原字符串: %s\n", text);printf("分割结果:\n");token = strtok(text, delims);while (token != NULL) {printf(" '%s'\n", token);token = strtok(NULL, delims);}return 0;
}
注意: 使用
strtok
函数会修改源字符串的数据,所以必要时创建临时拷贝保护原数据
char original[] = "data1,data2,data3";
char working_copy[100]; // 创建临时拷贝strcpy(working_copy, original); // 复制到可修改的内存
char *token = strtok(working_copy, ",");while (token) {printf("%s\n", token);token = strtok(NULL, ",");
}
12. strerror函数的使用
头文件: #include <string.h>
错误码定义: #include <errno.h>
函数原型:
char * strerror ( int errnum );
12.1 功能与核心要点
strerror
函数用于将错误码转换为可读的错误描述信息。
- 核心功能:将整数错误码转换为其对应的文本描述字符串。
- 桥梁作用:在系统调用/库函数返回数字错误码和人类可读的错误信息之间建立桥梁。
- 国际化支持:返回的字符串通常是本地化的,符合当前系统的语言设置。
12.2 错误处理机制上下文
要理解 strerror
,需要了解C语言的错误处理机制:
-
errno 全局变量:
- 定义在
errno.h
中 - 程序启动时
errno = 0
(表示无错误) - 当标准库函数执行失败时,会设置相应的错误码
- 定义在
-
错误码类型:
errno
是一个整数,不同的值代表不同的错误类型
12.3 函数参数与返回值
项目 | 说明 |
---|---|
参数 | errnum - 错误码(通常是 errno 的值) |
返回值 | 指向错误描述字符串的指针(静态内存,不要free) |
12.4 基本使用模式
- 查看所有错误码描述
#include <stdio.h>
#include <string.h>
#include <errno.h>int main()
{for (int i = 0; i <= 10; i++) {printf("错误码 %d: %s\n", i, strerror(i));}return 0;
}
- 实际错误处理示例
#include <stdio.h>
#include <string.h>
#include <errno.h>int main()
{FILE *pFile;pFile = fopen("test.txt", "r");if (pFile == NULL) {printf("打开文件失败: %s (错误码: %d)\n", strerror(errno), errno);}return 0;
}
12.5 perror函数
perror
函数是 strerror
的便捷包装:
perror 的功能:
- 自动获取当前
errno
- 调用
strerror
获取错误描述 - 直接打印格式化的错误信息
// 使用 strerror
fprintf(stderr, "错误: %s\n", strerror(errno));// 使用 perror(更简洁)
perror("错误");
正确使用
strerror
可以大大改善程序的调试体验和用户友好性,是编写健壮C程序的重要工具。
结语:
那么本期内容到此为止,建议大家多动手实践或者查阅官方文档来加深理解,同时在使用字符串函数时要注重边界条件!
下期见(预告:KMP高效查找字符串匹配的算法)。
继续探索,持续编程,让每一行代码都体现你对细节的掌控和对质量的追求。