在C语言中,字符串处理是编程的基础之一。本文将详细讲解两个重要的字符串处理函数:strtok
和strerror
一、strtok
函数
strtok
函数用于将字符串分割成多个子串,这些子串由指定的分隔符分隔。其原型定义如下:
char *strtok(char *str, const char *delim);
- 功能:
strtok
会将字符串s
按照delim
中定义的分隔符进行分割,并返回指向第一个分隔符后字符的指针。 - 第一个参数str指向一个字符串,它包括了0个或者多个由sep字符串中一个或多个分隔符分割的标记。
- strtok函数找到str中的下一个标记,并将其用 \0结尾,返回一个指向这个标记的指针。(注:strtok函数会改变被操作的字符串,所以被strtok函数切分的字符串一般都是临时拷贝的内容并且可修改。)
- strtok函数的第一个参数不为 NULL,函数将找到str中第一个标记,strtok函数将保存它在字符串中的位置
- strtok函数的第一个参数为 NULL,函数将在同一个字符串中被保存的位置开始,查找下一个标记。
- 如果字符串中不存在更多的标记,则返回 NULL 指针。
第二个参数delim
: 分隔符集合。可以是一个或多个字符,函数会根据这些字符分割字符串。
工作原理
strtok
会修改原始字符串:它将找到的分隔符替换为\0
(空字符),从而将原始字符串分割成多个子串。- 第一次调用时,函数会从
str
的开头开始查找分隔符;后续调用时,如果传入NULL
,函数会从上一次停止的位置继续查找。
使用示例
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <string.h>
int main()
{
char arr[] = "abcdefg@hhh.aaaa";
char sep[30] = { 0 };
strcpy(sep, arr);
const char* tmp = "@.";
char* p = strtok(sep, tmp);
printf("%s", p);
return 0;;
}
这是已经保存了@的地址,如果想继续往下运行就用到了(strtok函数的第一个参数为 NULL,函数将在同一个字符串中被保存的位置开始,查找下一个标记。)
所以要把strtok中的第一个参数修改一下,改为NULL。
如下:
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <string.h>
int main()
{
char arr[] = "abcdefg@hhh.aaaa";
char sep[30] = { 0 };
strcpy(sep, arr);
const char* tmp = "@.";
char* p = strtok(sep, tmp);//(abcdefg\0hhh.aaaa)
printf("%s\n", p);
p = strtok(NULL, tmp);//(abcdefg\0hhh\0aaaa)
printf("%s\n", p);
p = strtok(NULL, tmp);//(abcdefg\0hhh\0aaaa)
printf("%s\n", p);
return 0;;
}
注意事项
-
修改原始字符串:
strtok
会直接修改原始字符串,因此如果需要保留原始数据,建议先复制一份副本再操作。char arr[] = "abcdefg@hhh.aaaa"; char sep[30] = { 0 }; strcpy(sep, arr);
这里将arr的数据复制在sep中
-
线程安全问题:
strtok
使用静态缓冲区存储当前分割位置,因此它不是线程安全的。在多线程环境中,建议使用线程安全的替代函数strtok_r
。
-
连续分隔符处理:
- 如果字符串中有连续的分隔符(如
,,,
),strtok
会忽略这些连续的分隔符,不会返回空字符串。 -
"a,,b" → "a", "b" // 空字段被跳过
- 如果字符串中有连续的分隔符(如
-
字符串常量不可修改:
char *str = "read-only"; // 错误!应使用char[]
-
跨调用干扰:
char *t1 = strtok(str1, ","); char *t2 = strtok(str2, ";"); // 破坏str1的处理状态
-
空指针检查:
while ((token = strtok(NULL, ",")) != NULL)
简化方案
用上for循环,来省略繁琐步骤。
如下:
int main()
{
char arr[] = "abcdefg@hhh.xxx";
char sep[30] = { 0 };
strcpy(sep, arr);
const char* tmp = "@.";
char* p = NULL;
for (p = strtok(sep, tmp); p != NULL; p = strtok(NULL, tmp))
{
printf("%s\n", p);
}
return 0;
}
分析如下:
首次调用 strtok
函数,传入 sep
和 tmp
作为参数。strtok
会找到第一个分隔符 @
,并将 sep
中该位置的字符替换为 \0
,然后返回指向第一个子字符串 "abcdefg"
的指针。
这个for循环代码的判断条件是p不等于\0(而言就是NULL),当等于\0时,循环终止。
后续调用 strtok
函数时,传入 NULL
和 tmp
作为参数。strtok
会继续从上次分割的位置开始查找下一个分隔符 .
,并将该位置的字符替换为 \0
,然后返回指向下一个子字符串 "hhh"
的指针。如果找不到更多的分隔符,则返回 NULL
,循环结束。
二·stderror
函数
它的主要功能是将整数形式的系统级或库级的错误码转换为可读性更强的描述性文本 。这种机制使得程序员能够更直观地理解并处理运行过程中发生的异常情况 。
工作原理
char *stderror (int errnum)
注意:strerror生成的错误字符串取决于开发平台和编译器
-
参数:
int errnum
: 待转换的错误码 。通常情况下取值为全局变量errno
,但理论上可以接受任意整型值 。
-
返回值:该函数返回一个指向错误字符串的指针,该错误字符串描述了错误 errnum。
以下时返回值的意思。
使用示例
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
int main()
{
FILE* pf = fopen("test.txt", "r");
if (pf == NULL)
{
printf("%s\n", strerror(errno));
return 1;
}
return 0;
}
这里运用到打开文件, (fopen是打开文件的函数,在后续会提到,此处不过多解释,前参数是文件名,后参数是打开的方式)(r是读的意思)
打印文件失败的时候,会返回NULL指针
如果打开成功,返回的是非NULL指针,返回的pf中。
以r(读)的形式打开文件,文件如果不存在,则打开失败。
return1; 返回非零值,表示程序执行过程中发生了错误
return 0; 如果文件打开成功,返回0,表示程序成功执行
显然在我的电脑中是没有这个文件的,无法打开。
注意事项
1. 缓冲区覆盖问题
// 危险代码示例
char *err1 = strerror(EPERM);
char *err2 = strerror(ENOENT);
printf("%s, %s\n", err1, err2); // 可能输出相同内容
2. 无效错误码处理
printf("%s\n", strerror(9999)); // 可能输出:Unknown error 9999
3. 国际化问题
// 使用本地化版本
#include <libintl.h>
printf("%s\n", dgettext("glibc", strerror(errno)));
三·perror
函数
perror
是 C语言标准库中的一个简单而实用的工具 。它的主要功能是根据当前全局变量 errno
的值生成一条描述性错误消息 ,并将其输出到标准错误流 (stderr
) 。与 stderror
不同 , perror
直接处理了消息的格式化与输出过程 ,使得程序员能够更便捷地报告错误 。(相当于printf+sderror)
工作原理
- 检查全局变量
errno
的值 。 - 根据该值查找对应的错误描述文本 。
- 将用户提供的前缀(如果有)与错误描述拼接成完整消息 。
- 将最终结果写入标准错误流 (
stderr
) 。
void perror (const char *s)
-
参数:
const char *s
: 用户自定义的前缀字符串 。如果非空 ,该前缀会与系统提供的错误描述拼接在一起 ;如果为空 ,则仅打印系统提供的错误描述 。
-
返回值:
- 无返回值 。
使用示例
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
int main()
{
FILE* pf = fopen("test.txt", "r");
if (pf == NULL)
{
printf("%s\n", strerror(errno));
return 1;
}
return 0;
}
结语:
字符串处理函数:strtok和strerror讲解完毕,希望本章对大家有所帮助。
C语言的娴熟运用需要多练勤练,大家快去练习把!!