探讨strcpy函数的实现(上)

在笔试面试中经常会遇到要求实现strcpy函数的题目,这应该算是一道经典的题目了吧

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

         某内老师还教导我们:其实这个函数的返回值就应该是函数的第一个参数,也就是返回目的字符串地址
好吧,其实在之前的笔试包括刚才在把原来笔试时我的答案再写出来的时候,我都没有想到源字符串地址要加const防止意外修改,感觉自己深深的辜负了某内老师的教导快哭了快哭了

我在之前笔试时的答案大部分是酱紫的。

  1. #include <iostream>  
  2. using namespace std;  
  3.   
  4. char* Mystrcpy(char* dst, char* src)//我在实现的时候源字符串地址没想到要加const……  
  5. {  
  6.     if(dst == NULL || src == NULL)//笔试时有时候忘记检测传过来的参数是否为空……  
  7.         exit(1);//这里有时候脑抽也写成了return NULL;  
  8.     int i = 0;  
  9.     while(src[i] != '\0')  
  10.     {  
  11.         dst[i] = src[i];  
  12.         i++;  
  13.     }  
  14.     dst[i] = '\0';  
  15.     return dst;  
  16. }  
  17. int main()//刚才写的调用实例  
  18. {  
  19.     char* str = "I Love You";  
  20.     char st[15] = {0};  
  21.     char* s = Mystrcpy(st, str);  
  22.   
  23.     cout << "str = " << str << endl;  
  24.     cout << "st = " << st << endl;  
  25.     cout << "s = " << s << endl;  
  26.     cin.get();  
  27.     return 0;  
  28. }  
         以上代码经过在VS2012上的验证是能得到正确的结果的,当然,这样的代码并不是十分健壮,而且更重要的是——自己在电脑前能轻而易举一气呵成来写这段代码,可是笔试的时候达不到这种程度啊,根本不会去判断传入的参数是否为空有木有……

于是决心把这段代码写熟、写透,于是百度了strcpy函数的一般实现方式,于是:

以下内容均来自:http://www.cnblogs.com/chenyg32/点击打开链接

这篇博客给出了此函数的一般实现

  1. char* strcpy(char* dst, const char* src)//[1]  
  2. {  
  3.         assert(dst != NULL && src != NULL);//[2]  
  4.         char* ret = dst;//[3]  
  5.         while((*dst++ = *src++) != '\0');//[4]  
  6.         return ret;  
  7. }  
1.const修饰

        源字符串参数用const修饰,防止修改源字符串(这里我之前在写代码的时候一直都忽略了,以后写代码的时候一定要注意,任何一个参数都要首先考虑要不要传地址要不要使用const修饰)

2.空指针检查

        (A)不检查指针的有效性,说明答题者不注重代码的健壮性(其实倒不能说是不注重,只是经验少,想不到)

        (B)检查指针有效性时使用assert( !dst && !src);

                char*转换为bool是隐式类型转换,这种功能虽然灵活,但更多的是导致出错概率增大和维护成本升高

        (C)检查指针有效性时使用assert(dst != 0 && src != 0);

                直接使用常量会降低程序的可维护性,而使用NULL代替0,如果出现拼写错误,编译器就会检查出来

3.返回目标地址

        保存原来目的字符串的地址,因为后面的循环中dst做了自增运算,最后应该指向的是'\0'之后的字节,所以要把原来的地址记录下来

[4]'\0'

        (A)循环写成while(*dst++ = *src++)明显是错误的

        (B)循环写成while(*src != '\0') *dst++ = *src++;在结尾没有正确的加上'\0'(话说其实我的代码思路是正确的,但是毫无健壮性可言……)

ps.话说刚看这段代码的时候还没有反应过来while((*dst++ = *src++) != '\0');这段代码的逻辑,甚至直到刚才还没反应过来为什么要复制原来目的字符串的地址,而不是直接返回dst,由此可见这基础是多不扎实,要牢记昨天面试学长的话:基础不牢,地动山摇

现在想明白,语句中最内层小括号里的表达式是赋值,表达式的结果就是赋值运算符的左侧,然后再判断复制运算符的左侧,也就是刚刚赋值过去的内容是不是'\0',所以此循环的执行过程应该是这样的:

        1.将src指向的字节的内容赋值给dst指向的字节,然后分别将两个指针向后移动指向各自的下一个字节

        2.判断当前赋值的内容是否为'\0',如果不为'\0',则执行第一步,如果是'\0'则退出循环

        而要保存原来目的字符串的地址的原因在上面[3]的时候已经详细说明了,不再赘述

伴随这个问题,笔试中还会经常问到:这个函数为什么要返回char*

        是为了使函数能够支持链式表达式,例如 int len = strlen(strcpy(str1, str2));

        又如 char* str = strcpy(new char[10], str1);

         在函数中使用了断言assert()来检查指针有效性,assert()实际上是一个宏,使用时在括号中写入一个逻辑表达式,如果表达式的值为真,则程序继续运行;如果表达式的值为假,则终止程序执行

ps.百度百科上说断言只有在Debug模式下使用才有效,那么在Release模式时使用上述函数进行字符串拷贝会不会同样不严密呢?先留个坑,以后深入研究断言的时候再来思考这个问题

        关于strcpy函数的上篇就写这么吧,上篇的实现方式实际上没有考虑内存重叠的情况,有关在内存重叠情况下strcpy的实现方式在下篇再写

难过难过没有一个公司会要一个连strcpy这么简单的函数都实现不全面的人吧……对于我这种基础知识我也是醉了,但又能怎样呢,只能一点一点从头来吧,为了梦想,为了不再错过实现梦想的机会

【本文转至】http://blog.csdn.net/a3789910/article/details/41413281?ref=myread


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值