您的位置:首页 > 其它

strcpy函数的实现

2016-06-26 16:25 351 查看
strcpy函数的实现

大家一般认为名不见经传strcpy函数实现不是很难,流行的strcpy函数写法是:

[cpp] view
plain copy

char *my_strcpy(char *dst,const char *src)  

{  

    assert(dst != NULL);  

    assert(src != NULL);  

    char *ret = dst;  

    while((* dst++ = * src++) != '\0')   

        ;  

    return ret;  

}  

如果注意到:

1,检查指针有效性;

2,返回目的指针des;

3,源字符串的末尾 '\0' 需要拷贝。

写出上面实现函数就不在话下。

然而这样的实现没有考虑拷贝时内存重叠的情况,下面的测试用例就能使调用my_strcp函数的程序崩溃:

[cpp] view
plain copy

char str[10]="abc";  

my_strcpy(str+1,str);  

然而调用系统的strcpy函数程序正常运行,打印str结果为“aabc”!可见系统strcpy函数的实现不是这样的。

strcpy的正确实现应为:

[cpp] view
plain copy

char *my_strcpy(char *dst,const char *src)  

{  

    assert(dst != NULL);  

    assert(src != NULL);  

    char *ret = dst;  

    memcpy(dst,src,strlen(src)+1);  

    return ret;  

}  

memcpy函数实现时考虑到了内存重叠的情况,可以完成指定大小的内存拷贝,它的实现方式建议查看文章“卓越的教练是如何训练高手的?”,会获益良多,这里仅粘帖函数memcpy函数的实现:

[cpp] view
plain copy

void * my_memcpy(void *dst,const void *src,unsigned int count)  

{  

     assert(dst);  

     assert(src);  

     void * ret = dst;  

     if (dst <= src || (char *)dst >= ((char *)src + count))//源地址和目的地址不重叠,低字节向高字节拷贝  

     {  

         while(count--)  

         {  

             *(char *)dst = *(char *)src;  

             dst = (char *)dst + 1;  

             src = (char *)src + 1;  

         }  

     }  

     else                       //源地址和目的地址重叠,高字节向低字节拷贝  

     {   

         dst = (char *)dst + count - 1;  

         src = (char *)src + count - 1;   

         while(count--)   

         {  

             *(char *)dst = *(char *)src;  

             dst = (char *)dst - 1;  

             src = (char *)src - 1;  

         }  

    }  

    return ret;  

}  

两者结合才是strcpy函数的真正实现吧。

流行的写法中传入的是str+1,所以实际打印的也是从str+1所指向的位置开始打印,结果为abc。楼主缺少一种情况:当目的地址和源地址相同时,就不需要复制了

char *strcpy(char *strDest, const char *strSrc)
{
if ( strDest == NULL || strSrc == NULL)
return NULL ;
if ( strDest == strSrc)
return strDest ;
char *tempptr = strDest ;
while( (*strDest++ = *strSrc++) != ‘\0’);
return tempptr ;
}



strcpy函数的实现

已知strcpy函数的原型是:
char *strcpy(char *dst, const char *src);
实现strcpy函数
解释为什么要返回char *
假如考虑dst和src内存重叠的情况,strcpy该怎么实现
 

1.strcpy的实现代码

char * strcpy(char *dst,const char *src)   //[1]
{
assert(dst != NULL && src != NULL);    //[2]

char *ret = dst;  //[3]

while ((*dst++=*src++)!='\0'); //[4]

return ret;
}


[1]const修饰
源字符串参数用const修饰,防止修改源字符串。
[2]空指针检查
(A)不检查指针的有效性,说明答题者不注重代码的健壮性。
(B)检查指针的有效性时使用assert(!dst && !src);
char *转换为bool即是类型隐式转换,这种功能虽然灵活,但更多的是导致出错概率增大和维护成本升高。
(C)检查指针的有效性时使用assert(dst != 0 && src != 0);
直接使用常量(如本例中的0)会减少程序的可维护性。而使用NULL代替0,如果出现拼写错误,编译器就会检查出来。
[3]返回目标地址
(A)忘记保存原始的strdst值。
[4]'\0'
(A)循环写成while (*dst++=*src++);明显是错误的。
(B)循环写成while (*src!='\0') *dst++=*src++;
循环体结束后,dst字符串的末尾没有正确地加上'\0'。
 

2.为什么要返回char *?

返回dst的原始值使函数能够支持链式表达式。
链式表达式的形式如:
int l=strlen(strcpy(strA,strB));
又如:
char * strA=strcpy(new char[10],strB);
返回strSrc的原始值是错误的。
其一,源字符串肯定是已知的,返回它没有意义。
其二,不能支持形如第二例的表达式。
其三,把const char *作为char *返回,类型不符,编译报错。
 

3.假如考虑dst和src内存重叠的情况,strcpy该怎么实现

char s[10]="hello";
strcpy(s, s+1); //应返回ello,
//strcpy(s+1, s); //应返回hhello,但实际会报错,因为dst与src重叠了,把'\0'覆盖了
所谓重叠,就是src未处理的部分已经被dst给覆盖了,只有一种情况:src<=dst<=src+strlen(src)
C函数memcpy自带内存重叠检测功能,下面给出memcpy的实现my_memcpy。

char * strcpy(char *dst,const char *src)
{
assert(dst != NULL && src != NULL);

char *ret = dst;

my_memcpy(dst, src, strlen(src)+1);

return ret;
}


my_memcpy的实现如下

char *my_memcpy(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;
}


 

转载请注明出处http://www.cnblogs.com/chenyg32/

分类: C++

标签: 面试strcpy

好文要顶 关注我 收藏该文 

 






Norcy
关注 - 1
粉丝 - 33

+加关注

10

0

(请您对文章做出评价)

« 上一篇:《C++程序设计》朝花夕拾
» 下一篇:预处理指令

posted @ 2014-05-20 19:47 Norcy 阅读(25934)
评论(5) 编辑 收藏
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: