[源码分析] strcpy实现之 辛昕版

辛昕   2018-6-6 10:33 楼主
这件事告诉我们,没有测试就随手写,还以为木有问题,是一定会被打脸的。 而且现世报来的特别快。 这种态度是不对的,一定要改。 骚瑞骚瑞,把这事忘了,我果然是没啥责任心啊,诶~~ 好吧,先上代码
  1. char *xx_strcpy(char *s1,char *s2)
  2. {
  3. char *temp;
  4. uint32_t s2_len = 0,i;
  5. if( (s1 == NULL) || (s2 == NULL) )
  6. return NULL;
  7. temp = s2;
  8. while(*temp != 0)
  9. {
  10. temp++;
  11. s2_len++;
  12. }
  13. for(i = s2_len;i > 0;i-- )
  14. *(s1+i) = *(s2+i);
  15. return s1;
  16. }
本帖最后由 辛昕 于 2018-6-6 11:48 编辑
强者为尊,弱者,死无葬身之地

回复评论 (12)

看完楼主造的轮子,不由得感叹一句,面向对象真TM好用……
点赞  2018-6-6 10:46
引用: ljj3166 发表于 2018-6-6 10:46
看完楼主造的轮子,不由得感叹一句,面向对象真TM好用……

你说的是C++ string吧
强者为尊,弱者,死无葬身之地
点赞  2018-6-6 10:48
恕我蠢,不理解什么叫 一个方向的重叠@lcofjp
        // 没啥毛病,至于那个  少copy了一个字节 和 加0的毛病,认。

  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <stdint.h>
  4. #include <string.h>

  5. char *xx_strcpy(char *s1,char *s2)
  6. {
  7.        char *temp;
  8.        uint32_t s2_len = 0;
  9.            int i;
  10.       
  11.        if( (s1 == NULL) || (s2 == NULL) )
  12.             return NULL;
  13.   
  14.        temp = s2;
  15.       
  16.        while(*temp != 0)
  17.        {
  18.              temp++;
  19.              s2_len++;
  20.        }

  21.        for(i = s2_len;i >= 0;i-- )
  22.              *(s1+i) = *(s2+i);
  23.                
  24.            *(s1 + s2_len + 1) = 0;

  25.        return s1;
  26. }



  27. #define TEST_STRING "IDOYOULOVE"

  28. int main(void)
  29. {
  30.         char s[12];
  31.        
  32.        
  33.         strcpy(s,TEST_STRING);
  34.        
  35.         printf("strcpy:%s\n",s);
  36.        
  37.         xx_strcpy(s,(char *)(TEST_STRING + 4));
  38.        
  39.         printf("XX:%s\n",s);

  40.         // 我也试过反过来,,先 strcpy(TEST_STRING + 4) 再 xx_strcpy(TEST_STRING)的;
  41.         // 没啥毛病,至于那个  少copy了一个字节 和 加0的毛病,认。
  42.        
  43. }

强者为尊,弱者,死无葬身之地
点赞  2018-6-6 11:08
https://c.runoob.com/compile/12
公司电脑加密了,太多毛病,我直接在线跑的。
强者为尊,弱者,死无葬身之地
点赞  2018-6-6 11:08
while循环后面的for循环有些多余,我之前回帖写的除了没有判断参数的合法性和返回值不一样,基本思路跟版主的差不多
点赞  2018-6-6 11:18
按照 lcoftp 说的,试试非字面量,而是一个 可读可写的 字符串数组
依然没啥发现
  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <stdint.h>
  4. #include <string.h>

  5. char *xx_strcpy(char *s1,char *s2)
  6. {
  7.        char *temp;
  8.        uint32_t s2_len = 0;
  9.            int i;
  10.       
  11.        if( (s1 == NULL) || (s2 == NULL) )
  12.             return NULL;
  13.   
  14.        temp = s2;
  15.       
  16.        while(*temp != 0)
  17.        {
  18.              temp++;
  19.              s2_len++;
  20.        }

  21.        for(i = s2_len;i >= 0;i-- )
  22.              *(s1+i) = *(s2+i);
  23.                
  24.            *(s1 + s2_len + 1) = 0;

  25.        return s1;
  26. }



  27. #define TEST_STRING "IDOYOULOVE"

  28. int main(void)
  29. {
  30.         char s[12];
  31.                 char src[12] = {'0','1','2','3','4','5','6','7','8','9','a'};
  32.         // 但这种写法要注意一个问题,比如一个12元素的数组,你要留最后一个位置,它会自动
  33.                 // 填充0,这是不初始化的默认值,假设没这个0,这个src事实上也不是一个字符串
  34.                 // 因为没有0结尾,所以会出现错误。
  35.                 // 这是我在写这个测试代码的过程中发现的。
  36.         
  37.         strcpy(s,src + 4);
  38.         
  39.         printf("strcpy:%s\n",s);
  40.         
  41.         xx_strcpy(s,src);
  42.         
  43.         printf("XX:%s\n",s);

  44.                 // 还是没啥毛病
  45.         
  46. }
强者为尊,弱者,死无葬身之地
点赞  2018-6-6 11:30
引用: bobde163 发表于 2018-6-6 11:18
while循环后面的for循环有些多余,我之前回帖写的除了没有判断参数的合法性和返回值不一样,基本思路跟版主 ...

虾米,你的回复?
不不不,我好像没看到有考虑到地址重叠,然后反过来复制的人。

我反过来复制不是编码习惯,是真的要反过来复制才能防止地址重叠,把0给冲没了。
强者为尊,弱者,死无葬身之地
点赞  2018-6-6 11:37
大牛啊,学习了
点赞  2018-6-6 11:39
@lcoftp 收到,被打脸了,等等哈
  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <stdint.h>
  4. #include <string.h>

  5. char *xx_strcpy(char *s1,char *s2)
  6. {
  7.        char *temp;
  8.        uint32_t s2_len = 0;
  9.            int i;
  10.       
  11.        if( (s1 == NULL) || (s2 == NULL) )
  12.             return NULL;
  13.   
  14.        temp = s2;
  15.       
  16.        while(*temp != 0)
  17.        {
  18.              temp++;
  19.              s2_len++;
  20.        }

  21.        for(i = s2_len;i >= 0;i-- )
  22.              *(s1+i) = *(s2+i);
  23.                
  24.            *(s1 + s2_len + 1) = 0;

  25.        return s1;
  26. }



  27. int main()
  28. {
  29.         char test1[20] = "hello world!\n";
  30.         char test2[20] = "hello world!\n";

  31.         printf(" --- 1 -----\n");
  32.         puts(xx_strcpy(test1, test1 + 2));
  33.         puts(xx_strcpy(test2 + 2, test2));

  34.         char test3[20] = "hello world!\n";
  35.         char test4[20] = "hello world!\n";

  36.         printf(" --- 2 ----\n");
  37.         puts((char*)memmove(test3, test3 + 2, 10));
  38.         puts((char*)memmove(test4 + 2, test4, 10));
  39.     return 0;
  40. }

  1. // 运行结果
  2. --- 1 -----


  3. hello world!

  4. --- 2 ----
  5. llo world!d!

  6. hello worl
强者为尊,弱者,死无葬身之地
点赞  2018-6-6 11:47
引用: 辛昕 发表于 2018-6-6 11:37
虾米,你的回复?
不不不,我好像没看到有考虑到地址重叠,然后反过来复制的人。

我反过来复制不是编 ...

防止地址重叠,这是什么原理?
点赞  2018-6-6 13:50
引用: bobde163 发表于 2018-6-6 13:50 防止地址重叠,这是什么原理?
你只要画个图就明白了。 比方说 有一个数组 char s[20]; 它里面存的内容是 “0123456789012345” s[16] = 0; 好了,现在你要执行以下操作 strcpy(s + 12,s); 当你在copy的时候,s[16]早早就被填成了非0; 所以你永远找不到s结束的地方。 反过来复制,相当于我从一开始,就记录了本来结束的地方。 本帖最后由 辛昕 于 2018-6-6 14:23 编辑
强者为尊,弱者,死无葬身之地
点赞  2018-6-6 14:22
引用: 辛昕 发表于 2018-6-6 14:22
你只要画个图就明白了。
比方说
有一个数组
char s[20]; 它里面存的内容是 “0123456789012345” s[16 ...

这种情况下从头开始确实是会出现被填0的情况,但是这种用法本身有潜在的危险,会对原字符串进行破坏,还有可能会出现溢出错误,如果原字符串是字符串常量,你这样就会出问题。如果是相当有把握,保证原字符串之后的内存空间可以使用,不溢出,也是可以用。
点赞  2018-6-6 15:58
电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 京公网安备 11010802033920号
    写回复