两个函数都是将某一内存区域中的指定内容拷贝到目标内存中去,因此,拷贝的类型便不再受限制,不仅可以拷贝字符串内容,也可以拷贝整形,浮点数……
首先看看memcpy函数的用法:
void *memcpy( void *dest, const void *src, size_t count );
返回类型是void *;
参数 dest,src的类型都是void *(可以接收任何类型参数的地址,不限制传入参数的类型)
参数count是拷贝的字节数,类型是size_t无符号整型
实现起来也很简单,如下所示:
int main()
{
int arr1[10] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
int arr2[10] = {0};
int i = 0;
memcpy(arr2,arr1,40);
for(i=0; i<10; i++)
{
printf("%d ", arr2[i]);
}
return 0;
}
下面我们写一个函数my_memcpy来模拟实现该函数
void* my_memcpy(void* dest, const void* src, size_t count)
{
void * ret = dest;
assert(dest && src);
while (count--)
{
*(char*)dest = *(char*)src;
//不能写成(char*)dest++,因为++的优先级高于(),而dest的类型是void*,不能++或是*
//可以写成dest = (char*)dest+1,因为dest时void*的指针,可以接收任何类型的指针
//也可以写成((char*)dest)++
++(char*)dest;
++(char*)src;
}
return ret;
}
但是,当拷贝的内容所在内存有重叠时,这个函数就不再适用,结果会是这样:
什么是内存重叠呢,我画图来解释:
红色框和绿色框重叠的部分就是内存重叠的部分。因此,在上面的代码中,内存会从前向后拷贝,2->0,3->1,当4所在内存拷贝时,原内存区域内存放的早已不是2,而是拷贝后的0,导致结果出错。
当然了,如果你心存疑虑,用库里边的memcpy函数来验证,可能也会得到正确结果,不过这也不能说明我们写的这个my_memcpy函数是错的,因为c语言标准规定了memcpy函数只需要实现拷贝两块不相干的内存块即可,内存重叠的情况交给memmove去实现。我觉得为了严谨,也出于函数被制定出来的最初意义,如果内存重叠了就直接调用memmove函数。
这是在一个论坛上看到的,我觉得说的很有道理,分享给大家,希望对你们有帮助:
下面我们来看看memmove函数的用法
void *memmove( void *dest, const void *src, size_t count );
返回值和参数和memcpy函数一样,不同点就在于内存重叠部分,我们用memmove来实现一下上面所写的数组的拷贝:
这次得到了正确结果,下面我们写my_memmove来模拟实现该函数:
void* my_memmove(void* dest, const void* src, size_t count)
{
void* ret = dest;
assert(dest && src);
//分两种情况
//若目标空间在源空间之前,从前往后移动,若目标空间在源空间之后,从后往前移动
if (dest < src)
{
//从前往后
while (count--)
{
*((char*)dest) = *(char*)src;
++(char*)dest;
++(char*)src;
}
}
else
{
//从后往前
while (count--)
{
*((char*)dest + count) = *((char*)src + count);
}
}
return ret;
}
对于内存重叠的情况,我们这样处理:当目标空间在源空间之前时,从前向后拷贝;当目标空间在源空间之后,从后向前拷贝:
void* my_memmove(void* dest, const void* src, size_t count)
{
void* ret = dest;
assert(dest && src);
//分两种情况
//若目标空间在源空间之前,从前往后拷贝,若目标空间在源空间之后,从后往前拷贝
if (dest < src)
{
//从前往后
while (count--)
{
*((char*)dest) = *(char*)src;
++(char*)dest;
++(char*)src;
}
}
else
{
//从后往前
while (count--)
{
*((char*)dest + count) = *((char*)src + count);
}
}
return ret;
}
这是我对这两个函数的理解,很考察我们对内存,指针的掌握还有一些细节部分的处理。如果有写的不对的地方,敬请指正。