前言:
书接上回,咱们继续来讲解字符串函数和内存函数。本期要讲的是memmove函数,此函数可比上一节的memcpy函数好用多了!!!话不多说,开讲!
什么是memmove函数?
![](https://img-blog.csdnimg.cn/img_convert/5c3d47adde3d76b6110bccb92faa5b81.png)
通过查阅MSDN(C语言万法宝典!),我们可以看到memmove的返回值类型,参数类型和memcpy函数简直一模一样!头文件是string.h
通过字面意思可以得知memmove即memory move,翻译过来就是内存移动。那显而易见,memmove就是把源头内存块count个字节的内容移动到目标内存块。
注意:
src参数使用了const修饰,那么意味着不可通过src去改变src所指向的内容。
那么此处的移动并非是将源头拿到目标之后,源头就没了。而是将源头内存块的内容拷贝了一份然后移动到目标内存块。
见实例:
![](https://img-blog.csdnimg.cn/img_convert/95fe0f7eb7ba3a28fba357b7df545504.png)
此程序的数组arr1即为目标内存块,数组arr2即为源头内存块。显而易见,arr1被改变,但arr2仍然是原来的数组。
memmove函数如何使用?
memove的使用方法和memcpy函数使用方法一模一样,这里就不多说了。不懂的去看上一节。
memmove函数和memcpy函数的区别在哪?
来看实例:
![](https://img-blog.csdnimg.cn/img_convert/e445e3dd502689aba30a34f08d335f5e.png)
此程序中,我们用自己定义的memcpy函数来将arr1数组内存块的20个字节
拷贝到arr1+2所指向的内存块中,理想打印结果应该是1 2 1 2 3 4 5 8 9 10
但实际结果却成了 1 2 1 2 1 2 1 8 9 10。
原因分析:
![](https://img-blog.csdnimg.cn/img_convert/ce8f8fed089a5351027bab4fc8069877.png)
这里不用memcpy函数的原因是经过实验,在VS编译器中memcpy会正常拷贝成
1 2 1 2 3 4 5 8 9 10(但是其他编译器就不一定了),所以用自定义的my_memcpy函数来举例。那么为了解决在内存块重叠情况下的拷贝时,memmove函数就派上了用场。
接下来我们同样场景下,看看使用memmove函数拷贝会是怎样的情况?
![](https://img-blog.csdnimg.cn/img_convert/1cd6c6265be359772ed305cadf6f28b0.png)
我们发现使用memmove就正常的进行了拷贝。那么为什么memmove函数可以正常拷贝呢?
这就取决于memmove相对于memcpy的一个优化。
因为总有特殊情况下,源头内存块和目标内存内存块会重叠,在这些内存重叠的情况下,有的时候从前往后拷贝就可以正常拷贝,有的时候从后往前就可以正常拷贝,还有的时候都可以正常拷贝。
那么接下来我就带大家分析一下什么时候该用什么样的顺序拷贝:
![](https://img-blog.csdnimg.cn/img_convert/235f345490a0a229dd0e4c3372fce35b.png)
值得一提的是:
当内存重叠时,有时候src指向的内容被改变了,这并非是定义错误了。而是src和dest指向的内存块重叠时,通过dest改变了那部分内容,而非通过src改变。所以还是没问题的。
那么学会区分拷贝顺序之后,那么我们就可以轻松的自定义出my_memmove函数了!
自定义memmove函数
![](https://img-blog.csdnimg.cn/img_convert/026c19ef338b97d06a19354264093df1.png)
其中从前往后拷贝的定义和memcpy函数是一样的,从后往前拷贝主要是num--来控制拷贝的次数。
void* my_memmove(void* dest, const void* src, size_t num)
{
assert(dest && src);
void* ret = dest;
if (dest < src)//从前向后拷贝
{
while (num--)
{
*(char*)dest = *(char*)src;
dest = (char*)dest + 1;
src = (char*)src + 1;
}
}
else//从后向前拷贝
{
while (num--)
{
//*(char*)dest = *(char*)src;
//dest = (char*)dest - 1;
//src = (char*)src - 1;
*((char*)dest + num) = *((char*)src + num);//这样更简洁
}
}
return ret;
}
int main()
{
int arr1[] = { 1,2,3,4,5,6,7,8,9,10 };
int arr2[8] = { 0 };
memmove(arr1 + 2, arr1, 20);
for (int i = 0; i < 10; i++)
{
printf("%d ", arr1[i]);//1 2 1 2 3 4 5 8 9 10
}
return 0;
}
自定义函数代码自取。
结语:
到这里,此章关于memmove函数的的内容就结束啦,以后遇到memcpy无法解决的地方就可以用memmove喽。喜欢的就点个赞吧!期待我们的下一次相遇!
最后还是那句老话:路漫漫其修远兮,吾将上下而求索!!!