字符串拷贝时的内存重叠问题

字符串拷贝时的内存重叠问题

1.什么是内存重叠
拷贝的目的地址在源地址的范围内,有重叠。
如在写程序的过程中,我们用到的strcpy这个拷贝函数,在这个函数中我们定义一个目的地址,一个源地址,在拷贝的过程中如果内存重叠了,使用这个函数程序会出现问题,源地址与目的地址重叠,目的地址在源地址的范围内,发生了内存重叠。
2.如何判断内存重叠
可以将它们的地址求出来。
(1)若目的地址小于源地址,即目的地址的数据覆盖了源地址。则发生了内存重叠。(左边为低地址)
如:目的地址 地址:100 源地址 地址:104
( 2 )目的地址所指的区域是源地址的一部分。
如:目的地址 地址:100 源地址:096
3.如何解决内存重叠。
在遇到内存重叠这一问题时,要考虑拷贝的方向。当源地址和目的地址不重叠时,由低字节向高字节拷贝。当这两者重叠时,高字节向低字节拷贝。在使用strcpy和memcpy这两个函数来复制字符串时,会遇到内存重叠问题,因为这两个函数不对内存重叠进行判断。而我们可以用memmove函数来判断,这个函数对内存重叠进行了判断,我们可以看一下这三个函数的原型:
1.strcpy()原型写法: 字符串拷贝.

char *strcpy(char *strDest, const char *strSrc)
{
    assert((strDest!=NULL) && (strSrc !=NULL));
    char *address = strDest;
    while( (*strDest++ = * strSrc++)·1 != '/0')
    NULL ;
    return address ;
}

2.memcpy函数的原型写法:内存拷贝

void *memcpy(void *dest, const void *source, size_t count)
{
    assert((NULL != dest) && (NULL != source));
    char *tmp_dest = (char *)dest;
    char *tmp_source = (char *)source;
    while(count --)//不对是否存在重叠区域进行判断
    *tmp_dest ++ = *tmp_source ++;
    return dest;
}

3.memmove函数的原型写法:

void *memmove(void *dest, const void *source, size_t count)
{
    assert((NULL != dest) && (NULL != source));
    char *tmp_source, *tmp_dest;
    tmp_source = (char *)source;
    tmp_dest = (char *)dest;
    if((dest + count
    {
        while(count--)
        *tmp_dest++ = *tmp_source++;
    }
    else//如果有重叠(反向拷贝)
    {
        tmp_source += count - 1;
        tmp_dest += count - 1;
        while(count--)
            *--tmp_dest = *--tmp;
    }
    return dest;
}

在进行内存重叠的考虑时,strcpy,memcpy都要做一个内存重叠的判断:
对于strcpy需要加上一个断言:
int count = strlen(src) + 1;
Assert (dest(src+count))
对于memcpy需要加上一个断言:Assert(dst<=src || src+count

在strcpy函数中需要注意导入的形参dst,src不能有内存重叠。(尤其注意dst不能处在src字符串的内存中间,否则拷贝的时候会替换到src原有的结束字符,最终导致src字符串无结束字符,一直拷贝下去导致程序崩溃)

char *my_strcpy(char *dst,char *src)
{
    char *_src = NULL;
    char *_dst = NULL;
    int len = strlen(src);
    if(dst>src && dst < src + len) //dst内存处于src字符串内存中间,不能正向拷贝(原因见上述说明)。结果会影响到src源字符串
    {
        _src = src + len;//到最后的\0字符
        _dst = dst + len;
        while(len >= 0) //=0 走到下标0的字符
        {
            *_dst-- = *_src--;
            len--;
        }
    }
    else
    {
        _src = src;
        _dst = dst;
        while(len >= 0) //len:1-len,现在放宽一位0-len,表示从下标0-下标len,包括了\0字符
        {
            *_dst++ = *_src++; // \0
            len--;
        }
    }
 
    return dst;
}
 
int main()
{
    char a[20] = "123456789";
    char b[20] = {0};
    char *src,*dst;
    src = a;
    dst = a+5;
    my_strcpy(dst,src);//dst,src内存重叠
    my_strcpy(b,src);  //b,src内存无重叠
    printf("%s\n",src);
    printf("%s\n",b);
 
    return 0;
}
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值