八叶一刀·无仞剑

万物流转,无中生有,有归于无

导航

strcpy的实现

Posted on 2020-11-19 12:00  闪之剑圣  阅读(375)  评论(0编辑  收藏  举报

实现strcpy是一道常见的C++面试题,林锐的《高质量程序设计指南——C/C++语言》给出的实现如下:

char * strcpy(char *dst,const char *src) 
{
      assert(dst != NULL && src != NULL);
      char* address = dst;
      while((*dst++ = *src++)!='\0');
      return address;
}

这个代码看着简单,一共只有四句,但实际上大有玄机。
第一句assert是对传入的dst和src进行非法检查,确认是否传入的指针为空值。
第二句将dst的地址传到address中,因为之后dst就会递增了。
第三句是一个while循环,将src指向的字符依次赋值给dst,然后检查赋值的字符是否为字符串结束符'\0',以此决定是否结束循环。然后个指针各自自增。
之后返回address地址。之所以要return一个char*指针,是为了给这个函数支持链式表达式的操作:int l=strlen(strcpy(strA,strB))。

这个代码实际上仍然有bug,它无法处理dst和src内存重叠的情况,如下图所示:

图中src位于低地址,dst位于高地址,src和dst的字符串存在重叠。此时按照上面的代码,最终会覆盖src字符串自己所属的内存区域导致报错。
C函数自带的memcpy自带内存重叠检测功能,下面给出我实现的my_memcpy:

char * strcpy(char *dst,const char *src)
{
      assert(dst != NULL && src != NULL);
      char* address = dst;
      my_memcpy(dst, src, strlen(src)+1);
      return address;
}

char *my_memcpy(char *dst, const char* src, int cnt)
{
    assert(dst != NULL && src != NULL);

    char *address = 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;
}