strcpy及memcpy的内存重叠处理
strcpy和memcpy同是一个类型的函数,但实质上却是不同的,他们的原型分别为:
char *strcpy(char *dest, const char *src);
void *memcpy(void *dest, const void *src, size_t count);
当我们使用这两个函数时都会出现同样一个问题,内存重叠。那么我们就来分析一下内存重叠是如何产的。
现在假设有char *d = dest; char *s = src;要复制count = 5个字符,如下图所示:
1、第一种情况为 d <= s; 这种情况为d在s的后面,将s指向的东西往d指向的地方复制,d与s往后移动时内容互不干扰这是一种正常的状态。
2、第二种情况为d >= s + count; 这种情况是要复制的内容在两指针之间,此时指针移动时也不会对要复制的内容产生干扰,也不存在内重叠现象。
3、第三种情况时要复制的内容要比两指针的间距长,并且是由s往d中复制,如下图所示:
我们看到最后的结果变成了"hellh"而不是我们想要得到的"hello",于是,这就是产生内存重叠后的结果。解决内存重叠问题时我们可以将两个指针同时向后移动count-1个字节大小,让s指向要复制的最后一个元素的首地址,从后往前复制,如下图:
这样的处理后就能得到我们先要的结果了。下面时具体的代码实现。
char * strcpy(char *dst,const char *src)
{
assert(dst != NULL && src != NULL);
char *ret = dst;
MyMemMove (dst, src, strlen(src)+1);
return ret;
}
char * MyMemMove (char *dst, const char* src, int cnt)
{
assert(dst != NULL && src != NULL);
char *ret = dst;
if (dst >= src && dst <= src+cnt-1) //内存重叠,从高地址开始复制
{
dst = dst+cnt-1;
src = src+cnt-1;
while (cnt--)
*dst-- = *src--;
}
else //正常情况,从低地址开始复制
{
while (cnt--)
*dst++ = *src++;
}
return ret;
}
/*
dst >= src && dst <= src+cnt-1
dst与src比较的是地址,dst >= src代表dst位于高地址,即dst在src的后边
而dst <= src+cnt-1 代表需拷贝的内容,有一部分在dst内,即stc与dst出现重叠现象
*/
(strcpy与之很相似)这就是内存重叠的处理方法。
当使用内存拷贝函数拷贝内容到新空间时我们会发现最后的结果会出现这样的东西:“”这是由于我们没有将'\0'给拷贝过去。指针会根据首地址寻找到原来首地址后边的东西,但当指针遇到'\0'时就停止寻址,所以要解决上述问题只需在最后加上'\0'即可