前言:
来喽来喽,他们真的来喽。字符串函数以及内存函数,即将双双走来!!
今天要介绍的是:strcpy函数,strncpy函数以及memcpy函数
strcpy函数:
什么是strcpy函数?
strcpy从字面上来看就是string copy,翻译过来即字符串拷贝。它是C/C++里面的一个字符串函数,是用来将一个字符串的内容拷贝到另一个字符串中去。通常对于int,char,float等类型的变量,我们在赋值时可以直接用=就可以,但是对于字符串,比如char arr1[]="abc"和char arr2[]="def",此时我们想把arr2的内容赋给arr1,如果用arr1=arr2,那就大错特错了,因为arr1为地址,不能把内容存储在地址中,只能存储在地址所指向的空间。此时strcpy就派上了用场。
strcpy函数如何使用?
![](https://i-blog.csdnimg.cn/blog_migrate/8bb0b7290d5f09ff4a5a658de72c1d16.png)
通过查询MSDN,我们可以看到strcpy函数的返回值是char*类型,它有两个参数,一个是strDestination,另一个是strSource。翻译过来即字符串目的地,字符串源头。头文件为string.h
看实操:
![](https://i-blog.csdnimg.cn/blog_migrate/8fb3645158017711368cca00acc24ad3.png)
以上是对strcpy函数的简单调用,接下来讲一些strcpy函数的一些进阶知识
strcpy函数的进阶知识(搭配实例食用更佳哦):
例一:
![](https://i-blog.csdnimg.cn/blog_migrate/927ae78668827f491ad5d65f96371fd9.png)
![](https://i-blog.csdnimg.cn/blog_migrate/1e36bf924afae3af7cef7b1396e6a571.png)
为什么运行失败了?原因是因为作为源头字符串的arr1没有字符串结束标志\0,所以不知道copy内容从何处为止。
那如果反过来呢?(让目标字符串没有\0,源头字符串带上\0)
![](https://i-blog.csdnimg.cn/blog_migrate/db0e3f31d7da16681cb6399000c1c24e.png)
我们发现结果正常拷贝了。
(strcpy函数的返回值是目标字符串的首元素地址,所以可以链式访问)
结论1:
源头字符串必须有\0,确保拷贝到什么时候结束。目标字符串可以无\0.
例二:
![](https://i-blog.csdnimg.cn/blog_migrate/617ac54805bf5f38583d1220afd6301c.png)
我们发现明明arr1的内容是abc\0efg,但是拷贝到arr2里面打印结果是abc。
原因是strcpy函数拷贝完源头字符串的第一个\0就会停止拷贝。
结论2:
strcpy函数会在拷贝完源头字符串的第一个\0后停止拷贝。
例三:
![](https://i-blog.csdnimg.cn/blog_migrate/683cb69c1ae1663826e1ea5769fc2464.png)
很明显arr2占的内存大于arr1所占内存。这个程序运行报了错误,但是仍然正常拷贝了。
结论3:
当目标字符串的空间无法完全容纳源头字符串的内容时,会发生栈溢出。在VS里面仍然会强行拷贝,但是是很危险的。所以我们在用的时候一定要确保目标字符串这尊寺庙可以容纳的下源头字符串这尊大佛!
例四:
![](https://i-blog.csdnimg.cn/blog_migrate/88aaa7b9c32c3561471035b5e2b732a8.png)
这个程序运行出来拷贝也失败了。
解析:“abcdefg”是一个常量字符串,是无法被改变的。p存储着这串字符串的首元素a的地址。
arr是一个数组存储着字符串“hehe”,是可以被改变的。
结论4:
strcpy函数在使用时,目标字符串一定是可更改的字符串,不可使用常量字符串。
自定义strcpy函数:
![](https://i-blog.csdnimg.cn/blog_migrate/4cf2d332652b0eb80b0ccdd159c618f0.png)
其中要点就在于这个while循环,每次判断时都会进行一次赋值即*dest=*src,然后dest++,src++。
直到*src为零(即\0),然后判断条件为假跳出循环。
ret用来保存目标字符串首元素地址,最终返回ret。(这样就可以进行链式访问了)
其中assert使用来断言dest和src的,防止空指针。
strncpy函数:
![](https://i-blog.csdnimg.cn/blog_migrate/70ce4a55a2ce371a38437fedc1df8a8a.png)
strncpy比strcpy只多了一个‘n’,通过查询MSDN,我们发现它的参数也比strcpy多了一个count,类型是size_t无符号整形。头文件同样是string.h
strncpy函数如何使用?
看实操:
![](https://i-blog.csdnimg.cn/blog_migrate/de6b87d93db5c812cb1550fcfded5beb.png)
显而易见,第三个参数是用来控制拷贝字符个数的。当我们输入3时,它仅仅将arr3的前三个字符拷贝到了arr1里面。
特殊情况:
![](https://i-blog.csdnimg.cn/blog_migrate/3ceee5a20ecb4adef99b20055435c4cd.png)
在此程序中,arr1只有6个元素(算上\0),但是我们使用strncpy函数让它拷贝9个字符到arr2里面去,我们发现前6个正常拷贝了,但是剩下三个为0.
结论:
使用strncpy函数时,当拷贝的字符超出源头字符串时,多出的字符会默认以0填充。
自定义strncpy函数:
![](https://i-blog.csdnimg.cn/blog_migrate/caa4de4d9ea7b596d6169b590a083254.png)
加else是为了上面的特殊情况。
(注:此代码仅代表个人见解,有错误的地方欢迎指正,有更好的版本希望可以指点一二!不胜感激!)
memcpy函数
上面学习的strcpy函数,仅限于字符串,但下面学习的memcpy函数却可以对任意类型的数据使用。
什么是memcpy函数?
memcpy拆解出来就是memory copy,内存拷贝。我们知道数据都是存储在内存中的,所以memcpy函数可以拷贝任意类型的数据。
![](https://i-blog.csdnimg.cn/blog_migrate/48241a58aebff01a6af604138fbd9305.png)
查阅MSDN可知,memcpy函数的返回类型以及前两个参数类型都是void*,这是因为定义这个函数的人并不知道用户会用memcpy函数来拷贝什么类型的数据,所以将他定义为void*。第三个参数代表拷贝的字节数。头文件是string.h或者memory.h
memcpy函数如何使用?
老样子,实践出真知:
![](https://i-blog.csdnimg.cn/blog_migrate/a60922cbae389e90f6169e95a2912780.png)
以上程序成功的拷贝了整形和浮点型的数据。
由于memcpy函数在使用时,需要输入拷贝的字节数,所以在输入时需要计算好拷贝内容所占的字节。
特殊情况:
![](https://i-blog.csdnimg.cn/blog_migrate/69bbaadb3388cea0fbc6f3ffdf7b2ffe.png)
当输入字节数不为某个类型的倍数时,比如此程序我们拷贝arr1 21个字节到arr2里面,
结果调试发现arr2中第六个元素仍然被正常拷贝为了6.
原因分析:
![](https://i-blog.csdnimg.cn/blog_migrate/f1cdf8f4d6df575510ee9cd4a2aaa878.png)
自定义memcpy函数
![](https://i-blog.csdnimg.cn/blog_migrate/4232f00c6d0756c9e8f6168dcc286418.png)
要点在于num--控制while循环次数,并且给dest和src强制类型转换为char*类型,然后一次一个字节的拷贝。
结语:
最后总结一下,对于字符串拷贝时肯定首选strcpy函数,毕竟专业对口。
其次为了安全起见可以用strncpy函数来控制拷贝字符个数。
然后其他情况可以使用memcpy函数。
到这里本章节就结束啦!下几期会持续更新字符串函数以及内存函数之间的爱恨情仇!
还是那句老话:路漫漫其修远兮,吾将上下而求索!!!