1 memcpy
memcpy是操作内存的,其中以
1byte
的产生内存交换,和操作和strncpy相同且不再受任何类型限制。
void * memcpy ( void * destination, const void * source, size_t num );
- memcpy不再受变量类型限制,且也不再受
\0
限制,转而和strncpy
一样受到需要拷贝的数据长度限制。 - 同样使用
1byte
作为操作单位,num
值应该是 该类型所占用的字节 * 所需数据个数,例如:拷贝五个int数据 5 * 4 = 20 个字节 - 需要保证目标空间有足额空间。
- 需要使
destination
空间和soure
空间不重叠
arr2内容初始化为0,拷贝arr1中五个数据。
部分编译器使用memcpy
操作重叠空间会出现的问题
可以看到从目标地址开始数据出现了错误。
memcpy
函数是从src
指针指向的数据开始拷贝的,为什么数据会出现错误呢?
这是因为当拷贝过程中,src
指向的数据覆盖了后续会指向的数据,使得数据最终拷贝出现错误。
2 memmove
memmove
函数是专门用来处理destination
空间和soure
空间重叠的数据,也可以处理不同空间。
void * memmove ( void * destination, const void * source, size_t num );
为什么memmove
操作重叠空间不会出错呢?
逐步分解memcpy
操作步骤
memcpy(arr + 2, arr, 20);
当第一次发生拷贝时,
arr[2]
里的数据从 3 变成了 1,当函数需要拷贝arr[2]
覆盖arr[4]
这时拷贝的是1,而非原数据 3,
memmove
就是可以避免这类问题的。
我们看看memmove
处理逻辑
src
和dest
同时加上需要拷贝的数据长度,此时我们就从需要拷贝的数据的初始位置来到了末尾位置从末尾处开始拷贝,同时两指针同时根据拷贝完的数据逐步递减。
我们知道数组首元素地址是低于末尾位置地址的
所以我们可以举一反三,得出
- 当
dest
地址大于src
地址时,memmove
函数处理是从需要拷贝的数据末尾开始往前拷贝 - 当
dest
地址小于src
地址时,memmove
函数处理是从需要拷贝的数据初始位置往后拷贝
附:memcpy
和memmove
模拟代码
memcpy
void * my_memcpy(void * dest,void * src,size_t sz){
assert(dest && src);
void * ret = dest;
while (sz--)
{
*(char *)dest = *(char *)src;
dest = (char *)dest+1;
src = (char *)src+1;
}
return ret;
}
memmove
void * my_memmove(void * dest, void * src,size_t sz){
assert(dest && src);
void * ret = dest;
if (dest < src)
{
while (sz--)
{
*(char *)dest = *(char *)src;
dest = (char *)dest+1;
src = (char *)src+1;
}
}else{
while (sz--)
{
*((char *)dest + sz) = *((char *)src +sz);
}
}
return ret;
}