您的位置:首页 > 编程语言 > C语言/C++

C/C++ Prime学习要点1——实现memcpy库函数

2015-08-04 09:16 483 查看
实现一个Memcpy函数。

Memcpy函数用于 把资源内存(src所指向的内存区域) 拷贝到目标内存(dest所指向的内存区域);

拷贝多少个?有一个size变量控制拷贝的字节数。

函数原型:void *memcpy(void *dest, void *src, unsigned int count);

用法:(1)可以拷贝任何类型的对象,因为函数的参数类型是void*(未定义类型指针),也就是说传进去的实参可以是int*,short*,char*等等,

但是由于函数拷贝的过程是一个字节一个字节的拷贝的,所以实际操作的时候要把void*强制转化为char*,这样在指针加的时候才会保证每次加一个字节。

一开始我们很可能写出如下错误代码:

void memcpy(void *dest, void *src, int len)
{
void *p = dest;
void *q = src;
if( dest == NULL ||src == NULL)
{
return;
}

for (int i=0; i<len; i++)
{
*p++ = *q++;
}
}


上面错误代码原因:

函数原型应该是 void*memcpy(void* dest,const void* src,size_t count)
按照ANSI(American National Standards Institute)标准,不能对void指针进行算法操作,即不能对void指针进行如p++的操作,所以需要转换为具体的类型指针来操作,例如char *。
memcpy是对内存进行操作,可能遇到内存重叠的情况,同样的问题存在于memmove中, 但是源代码中这两个函数的处理方式不一样:memcpy中dest和source中的区域不能重叠,否则会出现未知结果中dest和source中的区域重叠,否则会出现未知结果。函数没做任何内存的处理,内存是否重叠由程序员自己控制。memmove里面则判断了内存重叠的情况,当内存重叠时从后往前复制,以确保复制正常处理。

考虑内存重叠情况:
1、若没有内存重叠,则从低地址往高地址复制
2、若有内存重叠,则从高地址往低地址复制
代码如下:(这其实也是memmove代码)
void *memcpy(void *dst, const void *src, size_t len)
{
if(NULL == dst || NULL == src){
return NULL;
}

void *ret = dst;

if(dst <= src || (char *)dst >= (char *)src + len){
//没有内存重叠,从低地址开始复制
while(len--){
*(char *)dst = *(char *)src;
dst = (char *)dst + 1;
src = (char *)src + 1;
}
}else{
//有内存重叠,从高地址开始复制
src = (char *)src + len - 1;
dst = (char *)dst + len - 1;
while(len--){
*(char *)dst = *(char *)src;
dst = (char *)dst - 1;
src = (char *)src - 1;
}
}
return ret;
}


memcpy 与 memmove区别:

memcpy和memmove()都是C语言中的库函数,在头文件string.h中,作用是拷贝一定长度的内存的内容,原型分别如下:

void *memcpy(void *dst, const void *src, size_t count);

void *memmove(void *dst, const void *src, size_t count);

作用是一样的,唯一的区别是,当内存发生局部重叠的时候,memmove保证拷贝的结果是正确的,memcpy不保证拷贝的结果的正确。



情况一,拷贝重叠的区域不会出现问题,内容均可以正确的被拷贝。

情况二,问题出现在右边的两个字节,这两个字节的原来的内容首先就被覆盖了,而且没有保存。所以接下来拷贝的时候,拷贝的是已经被覆盖的内容,显然这是有问题的。

实际上,memcpy只是memmove的一个子集。

memcpy没有考虑内存重叠的实现方法:

void *memcpy(void *dest, const void *src, unsigned int count)
{
assert((dest != NULL) && (src != NULL));
void *address = dest;
while (count --)
{
*(char *) dest = *(char *) src;
dest = (char *) dest + 1;
src = (char *) src + 1;
}
return address;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: