strcpy/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的一个子集。
memmove在copy两个有重叠区域的内存时可以保证copy的正确,而memcopy就不行了,
但memcopy比memmove的速度要快一些,如:
char s[] = "1234567890";
char* p1 = s;
char* p2 = s+2;
memcpy(p2, p1, 5)与memmove(p2, p1, 5)的结果就可能是不同的,memmove()可以将p1的头5个字符"12345"正确拷贝至p2,而memcpy()的结果就不一定正确了。
1.memmove
函数原型:void*memmove(void*dest, constvoid*source, size_t count)
返回值说明:返回指向dest的void *指针
参数说明:dest,source分别为目标串和源串的首地址。count为要移动的字符的个数
函数说明:memmove用于从source拷贝count个字符到dest,如果目标区域和源区域有重叠的话,memmove能够保证源串在被覆盖之前将重叠区域的字节拷贝到目标区域中。 可以拿它拷贝任何数据类型的对象。
2.memcpy
函数原型:void*memcpy(void*dest, constvoid*source, size_t count);
返回值说明:返回指向dest的void *指针,可以拿它拷贝任何数据类型的对象。
函数说明:memcpy功能和memmove相同,但是memcpy中dest和source中的区域不能重叠,否则会出现未知结果。
3.strcpy
原型:extern char *strcpy(char *dest,char *src);
功能:把src所指由NULL结束的字符串复制到dest所指的数组中。
说明:src和dest所指内存区域不可以重叠且dest必须有足够的空间来容纳src的字符串,返回指向dest的指针。
其实在strcpy的实现比较多,但思想是一致的,一般用C来实现,但是memcpy和memmove这样的函数可能是用汇编实现的,并且充分利用块拷贝的思想,不会单字节单字节的拷贝。所以效率strcpy<memcpy.memmove一般由于要判断内存是否重合,效率也会较memcpy低些。
strcpy
/********字符串的拷贝*****/
assert((src!=0)&&(dst!=0));//not null
memcpy
/**** @brief 以字节的方式直接拷贝
*库中实现是以汇编实现,
*其实可以直接调用strncat函数
* **/
void*memcpy(void*dst,void*src,size_t n)
{
assert((src!=0)&&(dst!=0)&&(n>0));//not null
char*dp = (char*)dst;
char*sp = (char*)src;
while(n--)
*(dp++) =*(sp++);
return dst;
}
memove
void *memmove(void *dst,const void *src,int n)
{
assert((src!=0)&&(dst!=0)&&(n>0));//not null
char *dp = (char *)dst;
char *sp = (char *)src;
//非重叠
//dp < sp
//dp > (sp+n)
if(sp>dp||(sp+n)<dp)
{
while(n--)
*(dp++) = *(sp++);
}else if(sp<dp)//重叠 (此时条件 sp<dp<(sp+n))如果sp==dp则快速的返回
{//反向拷贝
sp += n;
dp += n;
while(n--)
*(--dp) = *(--sp);
}
return dst;
}
补充:
memset原型:extern void *memset(void *buffer, int
c, int count);
用法:#include
<string.h>
功能:把buffer所指内存区域的前count个字节设置成字符c。
说明:返回指向buffer的指针。用来对一段内存空间全部设置为某个字符。
举例:char
a[100];memset(a, '\0', sizeof(a));
memset可以方便的清空一个结构类型的变量或数组。
如:
struct
sample_struct
{
char
int
int
iType;
};
对于变量
struct sample_strcut
stTest;
一般情况下,清空stTest的方法:
stTest.csName[0]='\0';
stTest.iSeq=0;
stTest.iType=0;
用memset就非常方便:
memset(&stTest,0,sizeof(struct
sample_struct));
如果是数组:
struct sample_struct
TEST[10];
则
memset(TEST,0,sizeof(struct sample_struct)*10);