先上代码
memcpy
void* my_memcpy(void* dest,const void* src,size_t num)
{
void* ret = dest;
assert(dest && src);
while (num--)
{
*(char*)dest = *(char*)src;
dest = (char*)dest + 1;
src = (char*)src + 1;
}
return ret;
}
int main()
{
int arr1[] = { 1,2,3,4,5,6 };
int arr2[10] = {0};
my_memcpy(arr2,arr1,12);
int i = 0;
for (i = 0; i < 3; i++)
{
printf("%d ", arr2[i]);
}
return 0;
}
memmove
void* my_memmove(void* dest,const void* begin, size_t size)
{
void* tmp = dest;
assert(dest && begin);
if (dest < begin)
{
while (size--)
{
*(char*)dest = *(char*)begin;
dest = (char*)dest + 1;
begin = (char*)begin + 1;
}
}
else
{
while (size--)
{
*((char*)dest + size) = *((char*)begin + size);
}
}
return tmp;
}
int main()
{
int arr1[] = { 1,2,3,4,5,6 };
my_memmove(arr1+2,arr1,12);
int i = 0;
for (i = 0; i < 6; i++)
{
printf("%d ", arr1[i]);
}
return 0;
}
memcpy:
首先memcpy有三个参数:拷贝目标地址,拷贝数据的源头地址和需要拷贝的字节个数。它们的类型分别对应void* (因为其可以接受任意类型的地址), const void* (同上,const是因为源头的数据不需要被改变),以及size_t (单位为字节,因为是内存)。函数的整体返回类型是void*,是因为在实现内存拷贝后,我们需要将拷贝目标的起始地址返回过来,所以同样是可以接受任意类型的地址。
memcpy的实现:首先在进行逐字节拷贝的过程中,目标地址dest会发生变化,于是这里我们创建了一个临时的 void* 变量 ret 来记录一下目标的起始地址,以便于整个函数完成后的地址返回。接下来就是进行逐个字节拷贝中要进行的问题:void* 类型的指针不能直接被检引用或加减,于是我们需要进行强制类型转换,其中 char* 类型被检引用只能获取一个字节十分合适,于是才有了 *(char*)dest = *(char*)begin; 。在进行了一个字节的拷贝后,地址需要转到下一个需要被拷贝的字节,于是要用++操作,强制类型转换是临时的,所以这里需要重新强制类型转换成 char*,加一后再赋值给下一个 void* 类型的地址。此循环操作取决于需要拷贝的字节数量,也就是传过来的num,于是可以用while循环解决。最终函数返回之前存的拷贝目标起始地址。
memmove:
此函数的实现与memcpy十分相似,甚至可以说是memcpy的升级版。三个参数的功能与memcpy一致: 拷贝目标地址,拷贝数据的源头地址和需要拷贝的字节个数。并且memmove还解决了在同一字符串中移动数据可能会被覆盖的困难。设想一下:我们要将12345中的123移动(本质也是拷贝)到345的位置变成12123。在使用memcpy的过程中:1拷贝到3,2拷贝到4,当我们想把3移到5时,我们会发现3的位置已经被拷贝到这里的1霸占了,结果会改变(不同编译器结果不同,但代码是有问题的)。于是乎memmove应运而生。
memmove的实现:首先,按照惯例创建临时void*变量tmp记录一下目标的起始地址。接下来便是不一样的操作,我们首先需要比较一下目标地址和拷贝起始地址的大小,这一步的原因如下:
在上面例子里3会被拷贝过来的1霸占,所以这时拷贝的顺序需要颠倒过来,3拷贝到5,2拷贝到4,1拷贝到3,一切正常。其前提就是 拷贝起始地址begin < 目标地址dest 。这里我先使用了if函数:目标地址比拷贝起始地址小时,这种情况下就不需要我们以颠倒顺序来进行字节拷贝,所以它的实现就和memcpy一模一样,这里直接照搬。那么else中实现的便是颠倒顺序的字节拷贝,这里不需要像memcpy那么复杂,我们首先要在强制类型转换成char*时直接加上我们需要转换的字节个数size后检引用,随后这个循环将会随着size--来进行逐字节拷贝,直至结束。
本人这里还使用了memmove测试两个不同字符串之间的字符拷贝,由于不同字符串占的地址空间不同,所以无论是进行顺序还是逆序拷贝,都不存在数据的覆盖。这边个人想法是memcpy可以直接被memmove所取代,也就是完爆,请问您怎么看?