strcpy的实现
作者 伊可 | 发布于 2015-02-15
算法 面试 字符串复制

      一直在纠结到底以哪一个例子开头,为了准备面试和学习,我想将我看到的学到的或者想到的一些好的试题或代码记录分享给大家,这些题目包括大家面试的时候会遇到的,考试的时候会遇到的,有疑惑的一些问题,它可能出自ACM竞赛试题,可能是某公司的面试题,可能是《编程之美》、《编程珠玑》题目等等,部分代码和思路是借鉴了网上很多大牛的想法,在此如果找到了原始出处一定附上,由于很多不可考,如果有冒犯原作者的地方还望海涵,我们尊重版权。那么让我们开始吧!

      在使用C或者C++的时候,是不是曾经使用甚至于亲自实现过strcpy这个函数呢?

      是不是曾经面试或者考试过程中遇到过呢?

      曾经在艺龙的一次招聘中,自己当时很水,面试官哥哥当时就说,你实现一下strcpy这个函数吧!自己当时听到后先是一阵信心满满,这不难啊,好,我就写下了如下的代码:

    //有错误的代码 void strcpy(char *a, char *b){ while(*b != '\0'){ *a = *b; a++; b++; } }

      面试官当时应该对我很是失望吧,并没有说出代码中的漏洞,而是问了我一些基础的知识就了了,后来在我系统的学习算法和代码的过程中我发现,在没有经过训练或没具体研究过,要想完完整整的不出错误的写出这个函数还真是不容易的。下面我们来一点点的剖析问题出在哪里...

      首先我们来看看这个函数的原型: 原型声明:extern char *strcpy(const char *dest, const char *src); 功能:把 src 所指由 NULL 结束的字符串复制到 dest 所指的数组中。 说明:src 和 dest 所指内存区域不可以重叠且 dest 必须有足够的空间来容纳 src的字符串。 返回指向 dest 的指针。

      请注意上面说的要点,我们要解决内存重叠、字符串的有效性检查、返回目标字符串等等一系列问题。有人会问为什么还要有返回值:为了增加灵活性如支持链式表达,可以附加返回值。所以,看似很简单的一道题,却有不少的陷阱,必须要注意。 如果把这道题按10分计算的话,下面是不同得分的实现,分别代表不同级别的陷阱:

    //2分的代码 void strcpy(char *sreDest, char *strSrc){ while((*strDest++ = *strSrc++) != '\0'); }
    //4分的代码 void strcpy(const char *sreDest, const char *strSrc){ //将源字符串加const,表明其为输入参数,加2分 while((*strDest++ = *strSrc++) != '\0'); }
    //7分的代码 void strcpy(const char *sreDest, const char *strSrc){ //对源地址和目的地址加非0断言,加分3分 assert((strDest != NULL) && (strSrc != NULL)); while((*strDest++ = *strSrc++) != '\0'); }
    //9分的代码 char* strcpy(const char *sreDest, const char *strSrc){ //为实现链式操作,将目的地址返回,加分2分 assert((strDest != NULL) && (strSrc != NULL)); char *address = strDest; while((*strDest++ = *strSrc++) != '\0'); return address; }
    //10分的代码 char* strcpy(const char *sreDest, const char *strSrc){ //如果有考虑源地址和目的地址区域有重叠的情况,加分1分 if(strDest == strSrc) return strDest; assert((strDest != NULL) && (strSrc != NULL)); char *address = strDest; while((*strDest++ = *strSrc++) != '\0'); return address; }

除了上面说的之外,其实还有很多细节问题,例如关于字符串的命名,strDest之类一定是比ab这些好多了,所以,有很多需要注意的。不知道你是否考虑到这些呢?说实话,第一次在网上看到关于这个问题的讨论后,简直自己弱爆了,带着兴奋和膜拜记下了这些,并一直认真阅读。不知道大家什么赶脚......