1.memcpy
功能:把source指向的前num个字节内容拷贝到destination指向的位置去,可以拷贝任意类型的数据。
注:1.memcpy并不关心\0,毕竟传的也不一定是字符串,因此拷贝过程中遇到\0也不会停下来。
2.num的单位是字节,并不是要拷贝的元素个数
3.如果source和destination有任何的重叠,拷贝的结果都是未定义的。什么意思呢?举个例子,我现在要把arr1中的12345拷贝到34567的位置上去。
打印结果却并没有如愿,这是因为当我们把1拷贝到了3的位置上,2拷贝到了4的位置上,数组arr1的内容已经被改变了,当我们要拷贝3到5的位置上时,3已经变成了1,于是就把1拷贝过去了。于是出现了上图所示的情况。
也就是说memcpy只用于处理不重叠内存的数据。
模拟实现memcpy
像这种能够操作各种类型数据的函数,其底层实现原理基本上都和char*类型的指针有关系,比如memcpy,还有我们前面已经模拟实现过的库函数qsort。因为char*类型的指针走一步就跳过一个字节,字节又是内存单元的最小单位,不管是什么类型的数据,只要一个字节一个字节的操作,最终都可以达成目的。
因此在这里我们就把des和src两个指针强制类型转换成char*类型的,然后解引用对他们指向的那一个字节单元的内容进行赋值操作,赋值完一个字节之后再进行下一个字节单元的操作。注意强制类型转换只是一个临时的操作,并不是说我们在进行赋值的时候把des和src强制类型转换成char*类型的了,他就一直是char*类型的了,因此要让des和src指向下一个字节单元,应该写成des=(char*)des+1。
2.memmove
功能:也是拷贝内存数据
和memcpy的差别就是memmove函数处理的源内存块和目标内存块是可以重叠的。如果源空间和目标空间出现重叠,就得使用memmove函数处理。
像刚才那个例子,我们就可以使用memmove解决
模拟实现memmove
思路:要在有重叠的数据里面实现拷贝,最大的问题就是在拷贝的过程中会改变原来位置的内容,第一想法是可以申请一块内存在里面存放原本数据的相同内容,这样当然可以,但是第一这种写法比较麻烦,第二会造成内存的浪费。能不能不申请内存就实现在同一块内存中拷贝内容呢?
当然可以,举个例子,12345678这串数字,现在我要把345处的内容拷贝成123,也就是最终让数字变成12123678,此时des在src的后面,如果我先把1拷贝到3的位置,那么后面在想把3拷贝到6处时就很尴尬,因为此时的3已经变成了1,但是如果我倒着拷贝,先把3拷贝到6的地方,再把2拷贝到5的地方,再把1拷贝到3的地方,不就行了吗?
再举一个例子,如果我要把345拷贝到123的位置,此时des在src的前面,我们直接把3拷贝到1的位置,4拷贝到2的位置,5拷贝到3的位置即可。
也就是说,如果dessrc,就从后往前拷贝。如果两块数据没有重叠,那从前或者从后都可以。
在代码中从后往前找的时候,先判断num是否为0,然后--,第一次的时候num是20,进入循环之后已经--了,变成了19,因此(char*)des + num与(char*)src + num都指向了最后一个要拷贝的位置。并随着num的减小不断指向前面位置。
注:memcpy能做的,memmove都能做。但是memmove能做的,memcpy不一定能做。