这篇文章给大家介绍一些C语言中处理字符串的进阶详解 库函数以及它们的使用和注意事项,一起来学习吧!中常字符作函!串操!数及
本篇文章介绍的其模函数需要包含的头文件都是#include
文章目录
- 前言
- 1.求字符串长度——strlen
- 1.1 使用及注意事项
- 1.2 strlen的模拟实现
- 2.字符串拷贝——strcpy
- 2.1 使用及注意事项
- 2.2 strcpy的模拟实现
- 3.字符串追加函数——strcat
- 3.1使用及注意事项
- 3.2 strcat的模拟实现
- 3.3思考
- 4.字符串比较函数——strcmp
- 4.1使用及注意事项
- 4.2strcmp 的模拟实现
- 5.小结
- 6. strncpy
- 6.1 与strcpy对比
- 6.2 使用及注意事项
- 7. strncat
- 7.1与strcat对比
- 7.2使用及注意事项
- 7.3上述3.3思考解答
- 8. strncmp
- 8.1演示练习
- 9.字符串查找函数——strstr
- 9.1使用及注意事项
- 9.2strstr的模拟实现
- 10. strtok
- 10.1功能解释及使用说明
- 10.2 代码演示及优化
- 11. strerror
- 11.1功能解释及使用说明
- 11.2 应用场景
前言
C语言中对字符和字符串的处理很是频繁,但是拟实C语言本身是没有字符串类型的,字符串通常放在 常量字符串 中或者 字符数组 中。进阶详解
字符串常量 适用于那些对它不做修改的中常字符作函字符串函数.
1.求字符串长度——strlen
strlen是库函数,我们要知道库函数的串操参数和它的功能是C语言标准规定好的,那我们怎么看它的数及参数是什么呢?
之前的文章里给大家提到过一个查询库函数的网站(cplusplus.com):
链接: link
那我们来看一下C语言标准规定strlen的参数和功能是怎么样的的:
1.1 使用及注意事项
相信这个函数大家以及比较熟悉了,但这里还是其模带大家一起来复习一下,并强调一些注意事项:
字符串以 ‘\0’ 作为结束标志,拟实strlen函数返回的进阶详解是在字符串中 ‘\0’ 前面出现的字符个数(不包含 ‘\0’ )。
举个例子:
#include #include int main(){ char arr[] = "abcdef"; char arr2[] = { 'a',中常字符作函'b','c','d','e','f','\0' }; printf("%d\n", strlen(arr)); printf("%d\n", strlen(arr2)); return 0;}
看下结果:
字符’\0’之前有6个字符,所以结果是串操6,相信大家都能明白。
参数指向的字符串必须要以 ‘\0’ 结束。
我们知道字符串的结束标志是’\0’,那如果一个字符串中没有’\0’,还能用strlen计算它的长度吗?
int main(){ char arr[] = { 'a','b','c','d','e','f' }; char arr2[] = { 'a','b','f'}; printf("%d\n", strlen(arr)); printf("%d\n", strlen(arr2)); return 0;}
大家思考一下结果会是什么?
19和31,为什么会是这个结果,是巧合吗?我们再运行一次:
又一个不同的结果,为啥呢?
因为如果我们不加’\0’,去求一个没有结束标志的字符串,它的结果将会是一个随机值,为什么呢?
因为函数strlen 求的是字符串中’\0’之前的字符个数,但是上面的两个字符串(C语言没有字符串类型,我们放到了字符数组中)中没有’\0’,所以strlen函数就会一直向后寻找,直至遇到’\0’,但数组后面的内存空间放的是什么我们是不知道的,所以我们不知道什么时候会遇到’\0’,因此结果是一个随机值。
注意函数的返回值为size_t,是无符号的( 易错 )
大家可能不是太明白,我们来先看一段代码:
#include int main(){ const char*str1 = "abcdef"; const char*str2 = "bbb"; if(strlen(str2)-strlen(str1)>0) { printf("str2>str1\n"); } else { printf("srt1>str2\n"); } return 0; }
大家思考一下结果是啥?
str1的长度为6,str2的长度为3,所以
strlen(str2)-strlen(str1)
的结果是-3,小于0,if判断为假,所以打印"srt1>str2"
如果你是这样想的那就错了!!!
我们来看一下结果是啥?
结果是str2>str1
,与我们想的不一样,原因就在于函数strlen的返回值为size_t。
解释:
不知道大家有没有注意到,库函数strlen的返回类型是size_t。
那什么是size_t呢?我们来看一下:
怎么看,在vs2022中输入一个size_t,鼠标右键转到定义或直接按F12即可查看:
我们看到,size_t其实就是unsigend int (无符号整型),因为typedef unsigned int size_t
的意思其实就是把类型unsigned int 重命名为 size_t。
由于strlen的返回类型是size_t,所以strlen(str2)-strlen(str1)
的结果就也是size_t了。
那么3-6=-3,我们知道内存中存的是补码:
那如果11111111111111111111111111111101被当作一个无符号整型,转化为10进制将是一个非常大的正数,肯定大于0,所以结果才是str2>str1
。
1.2 strlen的模拟实现
那我们现在已经知道了函数strlen的参数以及它的功能,我们是不是可以尝试去模拟实现一下strlen呢?
这里我们介绍三种方法去模拟实现strlen:
- 计数器方式
怎么实现呢?
把字符串的首字符地址传给函数,用指针接收,用该指针遍历字符串,如果指针指向的内容不是’\0’,计数器++,指针继续向后移动,直至遇到’\0’停止,返回计数器的值。
size_t my_strlen(const char* str) { int count = 0; while (*str) { count++; str++; } return count;}
看一下能不能达到效果:
- 递归实现
怎么递归呢?
我们对传过来的首字符地址直接解引用,如果是’\0’,那就返回0。
如果不是’\0’,那说明至少有一个有效字符,让指针+1,返回1+my_strlen(str+1)
,直至遇到’\0’,开始回归得出结果。
size_t my_strlen(const char* str) { if (*str == '\0') return 0; else return 1 + my_strlen(str + 1);}
也能得到正确结果:
- 指针-指针
在指针的学习中我们已经知道,指针-指针得到的是两个指针之间的元素个数,那我们让一个指针指向首字符,另一个指针指向’\0’,后者减前者,得到的元素个数不就是字符串长度吗?
size_t my_strlen(char* s) { char* p = s; while (*p != '\0') p++; return p - s;}
这样依然可行:
2.字符串拷贝——strcpy
先来认识一下它吧:
网站上都是英文的,不过我们可以翻译一下(当然有些地方可能翻译的不太准确):
2.1 使用及注意事项
- 源字符串必须以 ‘\0’ 结束
我们知道字符串的结束标志是’\0’,也就是说,strcpy在拷贝源字符串时,遇到’\0’才会停止拷贝,而跟字符串的长度无关,只要不遇到’\0’,就一直往后继续拷贝,那如果我们的源字符串中没有’\0’,会出现什么后果呢?
int main(){ char arr1[20] = { 0 }; char arr2[] = { 'a','b','c'}; strcpy(arr1, arr2); return 0;}
将arr2中的字符串拷贝到arr1中,但是arr2中的字符串并没有’\0’,会出现什么样的结果呢?
我们调试可以发现,这样是会发生错误的,因为在字符’a’、‘b’、‘c’的后面并没有放’\0’,所以strcpy会一直向后拷贝,我们不知道什么时候才会遇到’\0’停止下来,而且arr1我们申请的空间也是有限的,也不能无限的向里面放东西,所以这样就有可能造成越界,而且在’a’、‘b’、'c’后面会拷贝什么内容我们也不知道,这是不可行的。
因此,源字符串必须以 ‘\0’ 结束。
- 会将源字符串中的 ‘\0’ 拷贝到目标空间
strcpy在拷贝的时候会将源字符串的’\0’也拷贝到目标空间
我们来验证一下:
int main(){ char arr1[20] = "