实现strcpy

##strcpy和memcpy
很容易写出下面的实现

char *my_strcpy(char *dst,const char *src)
{
    if(dst == NULL || src == NULL)
        return NULL;
    char *ret = dst;
    while((* dst++ = * src++) != '\0') 
        ;
    return ret;
}

上面的代码已经考虑到了

  1. 检查指针有效性;

  2. 返回目的指针des;

  3. 源字符串的末尾 ‘\0’ 需要拷贝。

但是这个字符串拷贝函数有很大缺陷

  1. 不能保证目标字符串有足够空间存放src

  2. 如果dst和src内存重叠,那输出是未定义的

但是即使是系统实现的strcpy好像也没有改正这两个bug。

在linux上man strcpy得到描述是:

DESCRIPTION

The strcpy() function copies the string pointed to by src, including the terminat-
ing null byte (‘\0’), to the buffer pointed to by dest. The strings may not over-
lap, and the destination string dest must be large enough to receive the copy.

The strncpy() function is similar, except that at most n bytes of src are copied.
Warning: If there is no null byte among the first n bytes of src, the string placed
in dest will not be null terminated.

If the length of src is less than n, strncpy() pads the remainder of dest with null
bytes.

BUGS

If the destination string of a strcpy() is not large enough, then anything might happen. Overflowing fixed-length string buffers is a favorite cracker technique
for taking complete control of the machine. Any time a program reads or copies
data into a buffer, the program first needs to check that there is enough space.
This may be unnecessary if you can show that overflow is impossible, but be care-
ful: programs can get changed over time, in ways that may make the impossible pos-
sible.

strcpy和strncpy都需要程序员来保证dst有足够的空间来容纳将被拷贝的字符串,如果dst空间不足,得到的结果是未定义的;同样也需要程序员来保证他们的空间没有重叠。strncpy只是增加了一个拷贝长度的参数,针对这个参数也要做一些判断。

  • 如果src长度不足n,那么dst不足n的部分将会用null byte来补齐

    char* strncpy(char *dest, const char *src, size_t n){
        size_t i;
    
        for (i = 0 ; i < n && src[i] != '\0' ; i++)
            dest[i] = src[i];
        for ( ; i < n ; i++)
            dest[i] = '\0';
    
        return dest;
    }
    

strcpy是高危函数,因为它遇到’\0’才停止运行,遇到没有’\0’的字符串,它就会一直运行下去。建议使用strncpy代替strcpy,它接收一个最大长度的参数。strcmp和strncmp也是如此。

##memcpy

上面提出的缺陷1确实想不到好方法来解决(只能交给程序员了),但是缺陷2在memcpy中已经解决了。memcpy在实现的时候考虑到了内存重叠的问题。

char *my_memcpy(char *dst,const char *src,unsigned int count)
{
     if(dst == NULL || src == NULL) 
        return NULL;
     char * ret = dst;
     //源地址和目的地址不重叠,低字节向高字节拷贝
     if (dst <= src || dst >= (src + count))
     {
         while(count--)
         {
             *dst = *src;
             dst++;
             src++;
         }
     }
     //源地址和目的地址重叠,高字节向低字节拷贝
     //这个时候src字符串的值会被改变,声明为const只是说不能通过
     //src修改src指向的值。这里是通过dst改变了src的值,这是允许的。
     else       
     { 
         dst = dst + count - 1;
         src = src + count - 1; 
         while(count--) 
         {
             *dst = *src;
             dst--;
             src--;
         }
    }
    return ret;
}

##区别

  1. strcpy只能复制字符串,memcpy可以复制任何内容
  2. strcpy遇到'\0'就停止,memcpy一直复制到n个字符才停止,不管有没有'\0'
  3. strcpy不支持内存重叠,memcpy支持