当前位置: 首页 > news >正文

【C语言】字符串与字符函数详解(下)

C语言学习

字符函数和字符串函数下
友情链接:C语言专栏


文章目录

  • C语言学习
  • 前言:
  • 一、strcmp的使用和模拟实现
  • 二、strncmp函数的使用
  • 三、strstr的使用和模拟实现
  • 四、strtok函数的使用
  • 五、strerror函数的使用
  • 总结
  • 附录
    • 上文链接
    • 专栏


前言:

承接上篇内容,本文将继续深入讲解C语言中更复杂的字符串处理函数,包括字符串比较函数strcmp/strncmp、字符串查找函数strstr、字符串分割函数strtok以及错误处理函数strerror/perror。通过详细的代码示例和模拟实现,帮助读者全面掌握这些关键函数的特性和使用场景,提升字符串处理的编程能力。


一、strcmp的使用和模拟实现

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函数的使用

strncmp函数是C语言中的一个标准库函数,用于比较两个字符串的前n个字符。这个函数定义在<string.h>头文件中。
函数原型:

int strncmp(const char *str1, const char *str2, size_t n)

解释:

str1:指向要比较的第一个字符串的指针。
str2:指向要比较的第二个字符串的指针。
n:要比较的字符数。

返回值的判断咱们可以与strcmp函数对比,strcmp函数对比的是整个字符串,而strncmp函数对比的是前n个字符。
使用示例:

#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的使用和模拟实现

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++;
}
  1. 初始化 s1 为当前 p1 的位置,s2 为 str2 的起始位置。
  2. 如果 *s1 和 *s2 相等,则继续比较下一个字符。
  3. 如果任一字符串结束或字符不匹配,退出循环。

关于strstr函数,还有一种效率比较高的实现方法KMP算法,咱们这里不讲这个,不是咱们这里的重点,后续有机会会专门出一期讲解的。

四、strtok函数的使用

strtok函数是C标准库中的一个函数,用于将字符串分割成一系列的子串。它定义在<string.h>头文件中。
该函数的原型如下:

char *strtok(char *str, const char *delim);

解释:

str:要分割的字符串。第一次调用strtok时,这个参数应该是你想要分割的字符串。随后的调用应该将此参数设置为NULL,以便继续从上次的位置分割。
delim:一个包含多个分隔符的字符串。这些字符被用作分隔符,将str分割成多个子串。
返回值:strtok函数返回下一个子串的首地址,如果没有更多的子串,则返回NULL。

使用示例:

#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函数的使用

strerror函数可以把参数部分错误码对应的错误信息的字符串地址返回来。它定义在<string.h>头文件中。
函数原型:

char * strerror ( int errnum );

在不同的系统和C语言标准库的实现中都规定了⼀些错误码,⼀般是放在errno.h这个头文件中说明
的,C语言程序启动的时候就会使用⼀个全面的变量errno来记录程序的当前错误码,只不过程序启动
的时候errno是0,表示没有错误,当我们在使用标准库中的函数的时候发生了某种错误,就会讲对应
的错误码,存放在errno中,而⼀个错误码的数字是整数很难理解是什么意思,所以每⼀个错误码都是
有对应的错误信息的。strerror函数就可以将错误对应的错误信息字符串的地址返回。

  • 那我们来打印一下0~10这些错误码对应的信息:
#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环境下)。

使用示例:

#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语言标准库中最核心的字符串处理函数,为进一步学习内存操作函数和开发复杂字符串处理程序奠定了坚实基础。

附录

上文链接

《字符串与字符函数详解(上)》

专栏

C语言专栏

http://www.dtcms.com/a/289491.html

相关文章:

  • Shell脚本-cut工具
  • 从零到一MCP快速入门实战【1】
  • 疯狂星期四第13天运营日报
  • Java拓扑排序:2115 从给定原材料中找到所有可以做出的菜
  • Linux 基本指令详解
  • Self-Consistency:跨学科一致性的理论与AI推理的可靠性基石
  • WebDriver 对象中的方法
  • C++STL系列之list
  • Vue DIY 内容文本超出组件
  • Numpy库,矩阵形状与维度操作
  • 矩阵算法题
  • ZYNQ创新实践:免IIC驱动直控MCP4661T数字电位器
  • ollama基本配置
  • 仙盟数据库应用-外贸标签打印系统 前端数据库-V8--毕业论文-—-—仙盟创梦IDE
  • 数据库操作丨C++ 操作 数据库——SQLServer 篇
  • 数据库技术总结
  • 激光雷达和相机在线标定
  • 试用SAP BTP 06:AI服务-Data Attribute Recommendation
  • Java行为型模式---解释器模式
  • 30天打牢数模基础-XgBoost讲解
  • 第四章第一节 OLED 调试工具
  • 【LeetCode 热题 100】200. 岛屿数量——DFS
  • 20250720-3-Kubernetes 调度-资源限制对Pod调度的影响(2)_笔记
  • 隧道无线调频广播与“群载波”全频插播技术在张石高速黑石岭隧道中的应用
  • 数据结构第二章:线性表之顺序表
  • Kubernetes (K8S)知识详解
  • 【k8s集群管理平台】k8s运维管理的新玩法,让运维电脑随时不离身的现状成为过去
  • 【论文研读】SlowFast Networks for Video Recognition
  • 2024年全国青少年信息素养大赛Scratch算法创意实践挑战赛 小高组 初赛 真题
  • http基础一