
承接上篇内容,本文将继续深入讲解C语言中更复杂的字符串处理函数,包括字符串比较函数strcmp/strncmp、字符串查找函数strstr、字符串分割函数strtok以及错误处理函数strerror/perror。通过详细的代码示例和模拟实现,帮助读者全面掌握这些关键函数的特性和使用场景,提升字符串处理的编程能力。
strcmp是 C 语言中的一个库函数,用于比较两个字符串的大小。它的全称是 “string compare”,定义在<string.h>头文件中。该函数接受两个参数,分别是要比较的两个字符串的指针,并返回一个整数值,表示两个字符串的大小关系。(在比较字符串时,需要确保字符串以'\0' 结尾,否则可能会导致比较结果不正确。)
函数原型:
int strcmp(const char *str1, const char *str2);参数解释:
str1:要比较的第一个字符串。str2:要比较的第二个字符串。
返回值解释:
如果返回值小于 0,则表示 str1 小于 str2。 如果返回值大于 0,则表示 str1 大于 str2。 如果返回值等于 0,则表示 str1 等于 str2。
那么如何判断两个字符串? 原理是什么呢:
本质上比较的是两个字符串中对应位置上字符ASCII码值的大小。
strcmp的使用:
#include <stdio.h>
#include <string.h>
int main() {
char str1[] = "apple";
char str2[] = "banana";
int ret = strcmp(str1, str2);
if (ret == 0)
{
printf("str1 和 str2 相等\n");
}
else if (ret > 0)
{
printf("str1 大于 str2\n");
}
else
{
printf("str1 小于 str2\n");
}
return 0;
}strcmp的模拟实现:
#include<assert.h>
int my_strcmp(const char* str1, char* str2)
{
assert(str1 && str2);
while (*str1 || *str2)//遇到字符串结尾退出循环
{
if (*str1 != *str2)//找到不同的字符
return *str1 - *str2;
str1++;
str2++;
}
return *str1 - *str2;//不需要知道是哪个字符串遇到\0了
}这个模拟实现展示了strcmp函数的基本工作原理,即逐个字符比较两个字符串,直到找到不同的字符或遇到字符串结尾。
strncmp函数是C语言中的一个标准库函数,用于比较两个字符串的前n个字符。这个函数定义在<string.h>头文件中。 函数原型:
int strncmp(const char *str1, const char *str2, size_t n)。解释:
str1:指向要比较的第一个字符串的指针。str2:指向要比较的第二个字符串的指针。n:要比较的字符数。
返回值的判断咱们可以与strcmp函数对比,strcmp函数对比的是整个字符串,而strncmp函数对比的是前n个字符。
strncmp的使用:
#include <stdio.h>
#include <string.h>
int main()
{
char str1[15];
char str2[15];
int ret;
strcpy(str1, "abcdef");
strcpy(str2, "ABCDEF");
ret = strncmp(str1, str2, 4);
if (ret < 0)
{
printf("str1 小于 str2");
}
else if (ret > 0)
{
printf("str1 大于 str2");
}
else
{
printf("str1 等于 str2");
}
return 0;
}在这个例子中,strncmp函数比较了str1和str2的前4个字符。由于str1和str2前4个字符不相等,函数将返回一个非零值,具体是正数还是负数取决于它们第一个不同字符的ASCII值。
strstr函数用于在一个字符串中搜索另一个字符串的第一次出现。如果找到了子字符串,函数返回指向子字符串首字符的指针;如果没有找到,则返回NULL。此函数对于\0的处理:字符串的比较匹配不包含\0字符,以\0作为结束标志。
函数原型:
char * strstr ( const char * str1, const char * str2);咱们直接来实践一下。 strstr的使用:
int main() {
const char* str1 = "Hello, World!";
const char* str2 = "World";
char* result;
result = strstr(str1, str2);
if (result)
{
printf("子字符串 '%s' 出现的位置下标: %d\n", str2, result - str1);
}
else
{
printf("在字符串中未找到子字符串 '%s'.\n", str2);
}
return 0;
}输出:

strstr的模拟实现:
char* my_strstr(const char* str1, const char* str2) {
assert(str1 && str2);
if (*str2 == '\0')
return (char*)str1; // 处理空字符串,如果 str2 是空字符串(""),直接返回 str1 的起始地址
for (const char* p1 = str1; *p1; p1++) //从 str1 的第一个字符开始,逐个字符尝试匹配 str2。
{
const char* s1 = p1;
const char* s2 = str2;
while (*s1 && *s2 && (*s1 == *s2))
{
s1++;
s2++;
}
if (*s2 == '\0')
return (char*)p1; // 如果 str2 的所有字符均匹配(*s2 == '\0'),返回当前 p1(即匹配的起始位置)
}
return NULL; // 如果遍历完 str1 仍未找到 str2,返回 NULL。
}关键点解释:
const char* s1 = p1;
const char* s2 = str2;
while (*s1 && *s2 && (*s1 == *s2))
{
s1++;
s2++;
}关于strstr函数,还有一种效率比较高的实现方法KMP算法,咱们这里不讲这个,不是咱们这里的重点,后续有机会会专门出一期讲解的。
strtok函数是C标准库中的一个函数,用于将字符串分割成一系列的子串。它定义在<string.h>头文件中。 该函数的原型如下:
char *strtok(char *str, const char *delim);解释:
str:要分割的字符串。第一次调用strtok时,这个参数应该是你想要分割的字符串。随后的调用应该将此参数设置为NULL,以便继续从上次的位置分割。delim:一个包含多个分隔符的字符串。这些字符被用作分隔符,将str分割成多个子串。返回值:strtok函数返回下一个子串的首地址,如果没有更多的子串,则返回NULL。
strtok的使用:
#include <stdio.h>
#include <string.h>
int main()
{
char str[] = "Hello, World! Let's explore strtok.";
const char* delimiters = " ,!.";
// 获取第一个子串
char* token = strtok(str, delimiters);
// 继续获取其他的子串
while (token != NULL)
{
printf("%s\n", token);
token = strtok(NULL, delimiters); // 注意传递NULL来获取下一个子串
}
return 0;
}输出:

注意事项:
咱们会发现:strtok函数找到str中的下一个标记,会将其用
\0结尾,返回⼀个指向这个标记的指针。(注:strtok函数会改变被操作的字符串,所以在使⽤strtok函数切分的字符串⼀般都是临时拷贝的内容并且可修改。)
**strerror **函数可以把参数部分错误码对应的错误信息的字符串地址返回来。它定义在<string.h>头文件中。 函数原型:
char * strerror ( int errnum );在不同的系统和C语言标准库的实现中都规定了⼀些错误码,⼀般是放在errno.h这个头文件中说明
的,C语言程序启动的时候就会使用⼀个全面的变量errno来记录程序的当前错误码,只不过程序启动
的时候errno是0,表示没有错误,当我们在使用标准库中的函数的时候发生了某种错误,就会讲对应
的错误码,存放在errno中,而⼀个错误码的数字是整数很难理解是什么意思,所以每⼀个错误码都是
有对应的错误信息的。strerror函数就可以将错误对应的错误信息字符串的地址返回。
#include <errno.h>
#include <string.h>
#include <stdio.h>
int main()
{
int i = 0;
for (i = 0; i <= 10; i++)
{
printf("%d -> %s\n",i, strerror(i));
}
return 0;
}输出:

我使用的依旧是VS2022(Windows11环境下)。
strerror使用:
#include <stdio.h>
#include <string.h>
#include <errno.h>
int main()
{
//fopen 以读的形式打开文件的时候,如果文件不存在,就打开失败
FILE* pFile;
pFile = fopen("test.txt", "r");
if (pFile == NULL)
printf("%s\n", strerror(errno));
return 0;
}输出:

因为该程序工作目录下在我没有test.txt文件,所以打开失败。
接着怎么可以再看一下perror函数
perror函数:
perror函数相当于⼀次将上述代码中的printf("%s\n", strerror(errno));一次性完成了,直接将错误信息打
印出来。perror函数打印完参数部分的字符串后,再打印⼀个冒号和⼀个空格,再打印错误信息。
示例:
#include <stdio.h>
#include <errno.h>
int main()
{
//fopen 以读的形式打开文件的时候,如果文件不存在,就打开失败
FILE* pFile;
pFile = fopen("test.txt", "r");
if (pFile == NULL)
perror("fopen");
return 0;
}输出:

可见,perror可以直接将错误信息打印出来,也可以说:perror = printf + strerror。
本文完整介绍了C语言中字符串比较、查找、分割和错误处理相关函数,重点分析了strstr函数的实现逻辑和strtok函数的使用注意事项。理解这些函数的工作原理,能够帮助开发者编写更健壮、高效的字符串处理代码。结合上下两篇内容,读者现已掌握C语言标准库中最核心的字符串处理函数,为进一步学习内存操作函数和开发复杂字符串处理程序奠定了坚实基础。