Hi~!这里是奋斗的小羊,很荣幸各位能阅读我的文章,诚请评论指点,欢迎欢迎~~
💥个人主页:小羊在奋斗
💥所属专栏:C语言
本系列文章为个人学习笔记,在这里撰写成文一为巩固知识,二为一些学友们展示一下我的学习过程及理解。文笔、排版拙劣,望见谅。
6、strcmp 的使用和模拟实现
7、strncpy、strncat 和 strncmp
8、strtok 的使用和模拟实现
9、strstr 的使用和模拟实现
10、strerror 函数的使用
6、strcmp 的使用和模拟实现
6.1 strcmp 的用法
其实对于 strcmp 函数我们并不陌生,在之前的学习中已经不止一次用到过。
strcmp 函数的作用是比较两个字符串的大小,当结果是大于时返回一个正值,小于时返回一个负值,等于时返回0。所以 strcmp 函数的返回值是int类型,我们在使用字符串函数的时候一定要清楚每个函数的返回值是什么。
要特别注意的是,strcmp 函数比较两个字符串比较的不是字符串的长度,而是对应位置字符的ASCII码值。
可以看到,当对应位置字符的ASCII码值前者大于后者时,strcmp 函数返回了1;当小于时,strcmp 函数返回了-1;当等于时,strcmp 函数返回了0。来看下面代码示例:
这个代码有没有什么问题呢?其实,上面的代码在VS中是没有任何问题的,但是在其他编译器中可能就会发生错误。其中的原因在 strcmp 函数的返回值上,我们说当前面的字符串大于后面的字符串时返回一个正值,但这个正值可以是任意正值,而在VS上规定这个正值为1,但是在其他编译器上并不见得这个正值都为1。
6.2 strcmp 的模拟实现
有了前几个模拟实现字符串函数的经验,模拟 strcmp 函数难度也不是太大。
#include <stdio.h>
#include <assert.h>int my_strcmp(const char* str1, const char* str2)
{assert(str1 != NULL);assert(str2 != NULL);while (*str1 == *str2){if (*str1 == '\0'){return 0;}str1++;str2++;}if (*str1 > *str2){return 1;}else{return -1;}
}int main()
{char str1[] = "abcdef";char str2[] = "abcijk";int ret = my_strcmp(str1, str2);printf("%d\n", ret);return 0;
}
特别的,还可以简化成下面的形式。
7、strncpy、strncat 和 strncmp
出了 strcpy、strcat 和 strcmp 外,C语言还提供了更加灵活的 strncpy、strncat 和 strncmp,它们算是前三者的升级版,使用起来更加灵活。以 strncpy 为例:
可以看到 strncpy 相较于 strcpy 多了一个参数,用于指定拷贝多少个字符。另外两个也是类似。
虽然它们的逻辑表面上看起来是一样的,但是 strcnpy 和 strncat 之间还是有一点差异的。
可以看到 strncpy 不会给目标字符串主动添加 ‘\0’,但 strncat 就会主动给目标字符串添加 ‘\0’,这是两个函数间的差异。
那既然有了 strncat 函数,我们就能弥补上一小节中未能实现字符串自己拼接到自己后面的遗憾了。
8、strtok 函数的使用
更多详细介绍请跳转阅读 —> strtok, strtok_s - cppreference.com
看了上面的介绍好像还是云里雾里的,我用通俗的话来解释一下。delim 指向一个字符串,定义了用作分隔符的字符集合;第一个参数指定一个字符串,它包含了0个或多个由delim字符串中的一个或多个分隔符分割的标记;strtok 函数找到str中的下一个标记,并将其用\0结尾,返回一个指向这个标记的指针(strtok 函数会改变被操作的字符串,所以被 strtok 函数切分的字符串一般都是临时拷贝的内容并且可修改);strtok 函数的第一个参数不为NULL,函数将找到str中第一个标记,strtok 函数将保存它在字符串中的位置;strtok 函数的第一个参数为NULL,函数将在同一个字符串中被保存的位置开始,查找下一个标记;如果字符串中不存在更多标记,则返回NULL指针。也就是说,只需要传递一次指向字符串的非空指针,剩下的都传空指针。
上面的描述其实说的是 strtok 函数是一个过滤指定字符,提取出你想要的部分的函数。比如,有一个邮箱地址 18655404590@163.com,我们想要剔除其中的特殊字符 ‘@’ 和 ‘.’ ,提取出18655404590、163和com,那我们就可以使用 strtok 函数来实现。其中字符指针str指向目标字符串“18655404590@163.com”,delim 指向指定的分隔符“@、.”。
但是,上面是我们事先知道字符串中有两个分隔符,所以写了三个打印函数,那如果我们不知道一个字符串中有多少个分隔符呢?这里可以用for循环来解决,之前我们在介绍for循环的文章中说过这么一句话,for循环通常用来解决循环次数未知的情况。
9、strstr 的使用和模拟实现
9.1 strstr 的使用
更多详细介绍请跳转阅读 —> strstr - cppreference.com 简单来说,strstr 函数的作用是在一个字符串中查找另一个字符串,找到了就返回这个字符串第一次出现的起始地址,没找到就返回一个空指针。来看示例:
9.2 strstr 的模拟实现
模拟实现 strstr 函数之前,我们需要想清楚怎么在一个字符串中找另一个字符串是否存在呢?容易想到的是两个字符串通过指针解引用来一个一个的比较来判断是否存在一个相同的字符串,大致思路如下:
(1)逐个字符地访问被查找的字符串,当访问到与目标字符串首字符相同的字符时记住这个可能的地址,方便后面返回;
(2)当两个字符串的字符两两比较一直到目标字符串访问到 ‘\0’ 时说明找到了,返回之前记住的地址;
(3)当被查找的字符串访问到 ‘\0’ 时说明被查找的字符串不存在,返回一个空指针;
(4)综上,需要创建三个指针,其中两个指向被查找字符串,一个用来逐个访问字符,一个用来记住可能的地址,第三个指针指向目标字符串并且在改变了指针的指向后重新让其指向目标字符串的首地址。
#include <stdio.h>
#include <assert.h>char* my_strstr(const char* str1, const char* str2)
{assert(str1 && str2);const char* s1 = NULL;const char* s2 = NULL;const char* cur = str1;//用于返回可能的地址if (*str2 == '0')//当目标字符串是空字符串时{return cur;}while (*cur != '\0'){ s1 = cur;s2 = str2;while (*s1 && *s2 && *s1 == *s2){s1++;s2++;}if (*s2 == '\0')//找到了目标字符串{return cur;}cur++;}return NULL;//没找到
}int main()
{char str1[] = "abcdddeab";char str2[] = "deab";char* ps = my_strstr(str1, str2);if (NULL == ps){printf("不存在\n");}else{printf("%s\n", ps);}return 0;
}
10、 strerror 函数的使用
更多详细介绍请跳转阅读 —> strerror, strerror_s, strerrorlen_s - cppreference.com
简单地说,strerror 函数可以把参数部分错误码对应的错误信息的字符串地址返回来。
在不同的系统和C语言标准库的实现中都规定了一些错误码,一般是放在 errno.h 这个头文件中说明的,C语言程序启动的时候就会使用一个全局的变量 errno 来记录程序当前的错误码,只不过程序启动的时候 errno 是0,表示没有错误,当我们在使用标准库中的函数的时候发生了某种错误,就会将对应的错误码存放在 errno 中,而一个错误码的数字是整数很难理解是什么意思,所以每一个错误码都是有对应的错误信息的,strerror 函数就可以将错误对应的错误信息字符串的地址返回来。
整数0~10对应的错误信息如下:
再来举一个例子,其中涉及到一些我们之前还没学到的内容,请不要在意,主要是 strerror 函数的用法。
C语言函数中还有一个函数和 strerror 函数的功能是相似的,它就是 perror 函数。来看一下它的介绍:
它和 strerror 函数的区别在哪里呢?
strerror 函数的功能是将错误码对应的错误信息的字符串的地址返回,而 perror 函数的功能是将 errno 中错误码对应的错误信息打印出来。那它是怎样打印的呢?perror 函数打印的规则是先打印字符指针s指向的字符串,再打印一个冒号和一个空格,然后打印错误码对应的错误信息。
可以看到上面 printf 函数和 perror 函数打印的内容是一样的。
也就是说 perror == printf + strerror。我们可以根据自己的选择选用这两个函数。
如果觉得我的文章还不错,请点赞、收藏 + 关注支持一下,我会持续更新更好的文章。