我们在学习c语言的过程中都多多少少接触过一些库函数, 如求字符串长度的strlen,比较两个字符串大小的strcmp,今天带大家一起来模拟实现一下c语言中的库函数
strlen - 求字符串长度
strcpy - 字符串拷贝
strcat - 字符串连接
strcmp - 比较两个字符串的大小
strncpy - 长度受限制拷贝
strncat - 长度受限制连接
strncmp - 长度受限制比较
strstr - 在str1中找str2第一次出现的位置
1.strlen
size_t strlen ( const char * str )
我们先来看看库函数中的strlen是怎么使用的
strlen用于统计\0之前出现的字符个数
![](https://img-blog.csdnimg.cn/img_convert/73187ba1b012ba842f53941ccd4a75fe.png)
字符串"abcdef"在f的后面隐藏了一个\0,所以就是统计了a-f一共6个字符
![](https://img-blog.csdnimg.cn/img_convert/5b5d1234955266435ed197f45bc0e728.png)
如果在中间就加上\0,到\0就会结束
![](https://img-blog.csdnimg.cn/img_convert/a103324bffa409d1f2d76c0837f39880.png)
给strlen的参数一定要带\0,arr数组中只有三个字符,不包含\0,那么strlen找不到\0就会一直往后找,直到出现\0为止,这时可能会出现一些意想不到的值
![](https://img-blog.csdnimg.cn/img_convert/6c1a66a96365325b6ba64717bf44b5b8.png)
值得注意的是,strlen的返回类型是size_t(无符号数),上面代码中if语句里面虽然得到的是-3,但是会把这个数看成一个无符号数,-3就变成了一个非常大的数,所以这段代码的运行结果是>
strlen函数的模拟实现
这里给大家提供三种方法
1.计数器
![](https://img-blog.csdnimg.cn/img_convert/ebab70b8e671e6fae7f797297cff7ba1.png)
我们将数组首元素地址传给str, *str 找到了数组第一个元素a,然后让计数器count++;再让指针str向后挪一位,直到找到\0循环停止.
2.递归
![](https://img-blog.csdnimg.cn/img_convert/0d6a7316a5eccf109652e9c36053ed90.png)
此方法可以用于不创建临时变量的情况,每一次递归,都让str向后走一位,并且返回1,当*str等于\0的时候递归结束
3.指针-指针
![](https://img-blog.csdnimg.cn/img_convert/f0d4a628e2feb7886aa3714a31a141ce.png)
指针-指针得到是中间的元素个数,我们让last指向\0,last - str就是中间元素的个数.
2.strcpy
char * strcpy ( char * destination, const char * source )
字符串拷贝函数
还是一样,我们先来看一下怎么使用
![](https://img-blog.csdnimg.cn/img_convert/73c961a3541a23c6a12a16c565b7d65a.png)
我们将arr1的内容拷贝到arr2中,然后打印arr2,最终出现了abcdef
注意事项:
![](https://img-blog.csdnimg.cn/img_convert/fe3582918688cc9597da5b405d620472.png)
strcpy会把\0拷贝过来,遇到\0就会结束,所以传参的时候,原字符串一定要以\0来结尾,否则就会一直向后找
![](https://img-blog.csdnimg.cn/img_convert/a27239863e4069df0c53004f8a9e4690.png)
2.目标空间必须足够大,不然就会出错
![](https://img-blog.csdnimg.cn/img_convert/76a2817fcc960baa9f1ec119ab6e3038.png)
3.目标空间必须可以改变,p是一个常量字符串,内容是不能被修改的,这段代码就会报错
strcpy函数的模拟实现
![](https://img-blog.csdnimg.cn/img_convert/c951b867fe0c80e79c646341c19ad070.png)
实现的原理也很简单,就是让两个两个指针指向两个数组下标相同的位置上,然后把内容拷贝过去就好了,*src能访问数组中的元素,然后把这个赋给*dest,这样就完成了拷贝函数
3.strcat
strcat是字符串连接函数,是将一个字符串连接到另一个字符串上
![](https://img-blog.csdnimg.cn/img_convert/9921b25fc5e5744450ec19b3b9d34cad.png)
我们将arr2连接到了arr1的后面,最终打印出来的就是hello world
注意事项:
连接是从目标空间(arr1)的\0位置开始的,strcat会从\0开始,将原空间(arr2)的首元素覆盖掉\0,然后向后连接,目标空间必须有\0,否则不知道从哪开始连接,源空间必须有\0,否则不知道什么时候结束.
目标空间必须足够大,能容纳下源字符串的内容
目标空间必须可以修改,如果目标空间是一个常量字符串,不能被修改,就会出现错误
strcat的模拟实现
![](https://img-blog.csdnimg.cn/img_convert/be10f153f4bbc334cb278b32fc76b72c.png)
其实道理很简单,就是找到目标空间\0的位置,然后进行字符串拷贝就好了,把源空间的内容拷贝过去
![](https://img-blog.csdnimg.cn/img_convert/ed25a82756161b4da769dfeb9b4cee99.png)
如果说,自己给自己进行连接会发生什么呢,结果会陷入死循环,我们来看arr1,首先让dest指向了arr的\再让\0位置处,再让src指向h,我们将src指向的内容复制给dest,\0就被复制掉了,然后这样下去,arr数组中就不存在\0了,那么循环永远都不会结束
4.strcmp
strcmp是用来比较两个字符串大小的
![](https://img-blog.csdnimg.cn/img_convert/6e411e34ec431974075ee3e978f4e897.png)
这种方式比较的不是两个字符串的大小,比较的是字符串首元素的地址
两个字符串比较的方式:对应位置比较ASCII值,比如"abcdef" 和"abcdeg"这两个字符串比较大小,首先两个字符串的首元素来比较a 和 a相等,则去找下一位,下一位是b,也相等,直到最后一个,第一个字符串是f,第二个是g,g的ASCII值比f大,所以字符串"abcdeg"比"abcdef"要大
"abcfadgahg"和"abd"这两个字符串谁大呢,虽然第一个字符串很长,但是他的第三个字符c比第二个字符串的d要小,所以最终还是第二个字符串大,所以并不是谁长谁就大
![](https://img-blog.csdnimg.cn/img_convert/fe0afdc536387d273c3ad4af07b1bc5f.png)
strcmp这个函数,比较arr1和arr2的大小,arr1大则返回一个>0的数,arr1小,则返沪一个<0的数,等于就返回0
strcmp的实现
![](https://img-blog.csdnimg.cn/img_convert/44576396937f74a6ba9611c4b6ad812a.png)
实现也比较简单,就是比较对应位置的大小,如果一直相等,就会在while循环里,找到\0则说明两个字符串的结果完全相等,只要发现str1和str2指向的内容不相等就会跳出循环
strcpy, strcat, strcmp是长度不受限制的字符串函数,比如strcpy,拷贝的时候,会把内容拷贝过去,直到找到\0,根本不会关心你\0之前有多少个元素
比如:
![](https://img-blog.csdnimg.cn/img_convert/f597dbbc4368619c0c2bca640f0ae597.png)
arr2的空间根本不够存放arr1,虽然编译器会报错,但是最终还是会把arr1的内容拷贝给arr2
所以这些函数在vs这种高级编译器中被认为是不安全的,我们就引入了几个新的函数
长度受限制字符串函数: strncpy, strncat, strncmp,这几个就是长度受限制的字符串,和前面几个字符串的区别就是中间多了个n
![](https://img-blog.csdnimg.cn/img_convert/6f25112a4d1a868a62be991d1544f7a9.png)
strncpy多了个参数,是你要拷贝的长度,使用strncpy的时候要加上你要拷贝的长度,比如这里,你只要拷贝3个,就在最后加上3,使用个数来控制长度会相对安全一点
![](https://img-blog.csdnimg.cn/img_convert/8196dfdddc7879c7a1ca26c91c2900bc.png)
strncat这个函数最后加一个3,说明我们要拷贝3个字符,拷贝完了3个字符之后会自动增加一个\0
![](https://img-blog.csdnimg.cn/img_convert/563dfcaeb67ead50cddc7ee7fd5aa180.png)
strncmp也是一样的,加个几就是比较几个元素
![](https://img-blog.csdnimg.cn/img_convert/f859e6f9443cbc37941f1bc7553e456b.png)
5.strstr
在str1中找str2第一次出现的位置,找到了返回第一次出现的位置的地址,找不到返回空指针
![](https://img-blog.csdnimg.cn/img_convert/353fe3543cb1718f2a2ebbf19823a9e5.png)
strstr函数的实现
![](https://img-blog.csdnimg.cn/img_convert/e419cae7a307d14c46140fa055176f76.png)
我们是要在str1中找到str2,所以我们让指针s1指向str1的首元素,s2指向str2的首元素,让s1往后走,如果找到了一个和s2相等的字符,那么就让s1,s2都往后走,如果在这个过程中,两个指针指向的元素都一直相等,直到s2指向了\0,也就是说明str1中能找到str2,那么我们就应该返回第一次出现的位置.
如果我们在s1和s2都往后走的过程中发现了有一次他们两个不相等,这时候我们应该让s1返回最开始的位置,所以我们重新定义一个cp,用于遍历str1
![](https://img-blog.csdnimg.cn/img_convert/4368ff56abe5d23e28d7d8f1829d1d96.png)
比如此时str1指向的元素等于str2指向的元素,那么就让str1和str2同时往后走,观察是否相等
![](https://img-blog.csdnimg.cn/img_convert/f757dc533e2f221b9bd2eb6ee285cd83.png)
当str2指向\0的时候说明能在str1中找到str2
![](https://img-blog.csdnimg.cn/img_convert/bc3c8fb1d43603a084fa13a42ab8e041.png)
这时候我们直接返回cp,就是str2在str1首次出现的位置
![](https://img-blog.csdnimg.cn/img_convert/f6ea5e4fd89430d994a16e2f42af2861.png)
此时str1和str2相等就让str1和str2都想后走
![](https://img-blog.csdnimg.cn/img_convert/7dabae1e788d0760256fa5c8ba78c2bc.png)
走到这一步的时候发现str1和str2指向的内容不相同了,这时候应该让str1返回开始比较的位置也就是cp指向的位置,然后重新开始比较
![](https://img-blog.csdnimg.cn/img_convert/2e048becdb4fbeb88d8ce605eee32071.png)
如果str1走到尾了都没有找到str2,就返回NULL