社区导航

 
查看: 667|回复: 12

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

[复制链接]

7675

TA的帖子

54

TA的资源

版主

Rank: 6Rank: 6

发表于 2018-6-6 10:33:49 | 显示全部楼层 |阅读模式
本帖最后由 辛昕 于 2018-6-6 11:48 编辑

这件事告诉我们,没有测试就随手写,还以为木有问题,是一定会被打脸的。
而且现世报来的特别快。
这种态度是不对的,一定要改。

骚瑞骚瑞,把这事忘了,我果然是没啥责任心啊,诶~~
好吧,先上代码
  1. char *xx_strcpy(char *s1,char *s2)
  2. {
  3.        char *temp;
  4.        uint32_t s2_len = 0,i;
  5.       
  6.        if( (s1 == NULL) || (s2 == NULL) )
  7.             return NULL;
  8.   
  9.        temp = s2;
  10.       
  11.        while(*temp != 0)
  12.        {
  13.              temp++;
  14.              s2_len++;
  15.        }

  16.        for(i = s2_len;i > 0;i-- )
  17.              *(s1+i) = *(s2+i);

  18.        return s1;
  19. }
复制代码



此帖出自编程基础论坛
没有一件事情是容易的,所以,起念头时,一定要好好琢磨


回复

使用道具 举报

3194

TA的帖子

0

TA的资源

纯净的硅(高级)

Rank: 6Rank: 6

发表于 2018-6-6 10:46:27 来自手机 | 显示全部楼层
看完楼主造的轮子,不由得感叹一句,面向对象真TM好用……

点评

你说的是C++ string吧  详情 回复 发表于 2018-6-6 10:48


回复

使用道具 举报

7675

TA的帖子

54

TA的资源

版主

Rank: 6Rank: 6

 楼主| 发表于 2018-6-6 10:48:46 | 显示全部楼层
ljj3166 发表于 2018-6-6 10:46
看完楼主造的轮子,不由得感叹一句,面向对象真TM好用……

你说的是C++ string吧
没有一件事情是容易的,所以,起念头时,一定要好好琢磨


回复

使用道具 举报

7675

TA的帖子

54

TA的资源

版主

Rank: 6Rank: 6

 楼主| 发表于 2018-6-6 11:08:23 | 显示全部楼层
恕我蠢,不理解什么叫 一个方向的重叠@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. }
复制代码

没有一件事情是容易的,所以,起念头时,一定要好好琢磨


回复

使用道具 举报

7675

TA的帖子

54

TA的资源

版主

Rank: 6Rank: 6

 楼主| 发表于 2018-6-6 11:08:50 | 显示全部楼层
https://c.runoob.com/compile/12
公司电脑加密了,太多毛病,我直接在线跑的。
没有一件事情是容易的,所以,起念头时,一定要好好琢磨


回复

使用道具 举报

1725

TA的帖子

0

TA的资源

五彩晶圆(初级)

Rank: 7Rank: 7Rank: 7

发表于 2018-6-6 11:18:44 | 显示全部楼层
while循环后面的for循环有些多余,我之前回帖写的除了没有判断参数的合法性和返回值不一样,基本思路跟版主的差不多

点评

虾米,你的回复? 不不不,我好像没看到有考虑到地址重叠,然后反过来复制的人。 我反过来复制不是编码习惯,是真的要反过来复制才能防止地址重叠,把0给冲没了。  详情 回复 发表于 2018-6-6 11:37


回复

使用道具 举报

7675

TA的帖子

54

TA的资源

版主

Rank: 6Rank: 6

 楼主| 发表于 2018-6-6 11:30:38 | 显示全部楼层
按照 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. }
复制代码
没有一件事情是容易的,所以,起念头时,一定要好好琢磨


回复

使用道具 举报

7675

TA的帖子

54

TA的资源

版主

Rank: 6Rank: 6

 楼主| 发表于 2018-6-6 11:37:23 | 显示全部楼层
bobde163 发表于 2018-6-6 11:18
while循环后面的for循环有些多余,我之前回帖写的除了没有判断参数的合法性和返回值不一样,基本思路跟版主 ...

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

我反过来复制不是编码习惯,是真的要反过来复制才能防止地址重叠,把0给冲没了。

点评

防止地址重叠,这是什么原理?  详情 回复 发表于 2018-6-6 13:50
没有一件事情是容易的,所以,起念头时,一定要好好琢磨


回复

使用道具 举报

1315

TA的帖子

0

TA的资源

版主

Rank: 6Rank: 6

发表于 2018-6-6 11:39:41 | 显示全部楼层
大牛啊,学习了


回复

使用道具 举报

7675

TA的帖子

54

TA的资源

版主

Rank: 6Rank: 6

 楼主| 发表于 2018-6-6 11:47:25 | 显示全部楼层
@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
复制代码
没有一件事情是容易的,所以,起念头时,一定要好好琢磨


回复

使用道具 举报

1725

TA的帖子

0

TA的资源

五彩晶圆(初级)

Rank: 7Rank: 7Rank: 7

发表于 2018-6-6 13:50:07 | 显示全部楼层
辛昕 发表于 2018-6-6 11:37
虾米,你的回复?
不不不,我好像没看到有考虑到地址重叠,然后反过来复制的人。

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

防止地址重叠,这是什么原理?

点评

你只要画个图就明白了。 比方说 有一个数组 char s[20]; 它里面存的内容是 “0123456789012345” s[16] = 0; 好了,现在你要执行以下操作 strcpy(s + 12,s); 当你在copy的时候,s[16]早早就被填成了非0; 所  详情 回复 发表于 2018-6-6 14:22


回复

使用道具 举报

7675

TA的帖子

54

TA的资源

版主

Rank: 6Rank: 6

 楼主| 发表于 2018-6-6 14:22:00 | 显示全部楼层
本帖最后由 辛昕 于 2018-6-6 14:23 编辑
bobde163 发表于 2018-6-6 13:50
防止地址重叠,这是什么原理?

你只要画个图就明白了。
比方说
有一个数组
char s[20]; 它里面存的内容是 “0123456789012345” s[16] = 0;
好了,现在你要执行以下操作
strcpy(s + 12,s);
当你在copy的时候,s[16]早早就被填成了非0;
所以你永远找不到s结束的地方。

反过来复制,相当于我从一开始,就记录了本来结束的地方。

点评

这种情况下从头开始确实是会出现被填0的情况,但是这种用法本身有潜在的危险,会对原字符串进行破坏,还有可能会出现溢出错误,如果原字符串是字符串常量,你这样就会出问题。如果是相当有把握,保证原字符串之后的  详情 回复 发表于 2018-6-6 15:58
没有一件事情是容易的,所以,起念头时,一定要好好琢磨


回复

使用道具 举报

1725

TA的帖子

0

TA的资源

五彩晶圆(初级)

Rank: 7Rank: 7Rank: 7

发表于 2018-6-6 15:58:24 | 显示全部楼层
辛昕 发表于 2018-6-6 14:22
你只要画个图就明白了。
比方说
有一个数组
char s[20]; 它里面存的内容是 “0123456789012345” s[16 ...

这种情况下从头开始确实是会出现被填0的情况,但是这种用法本身有潜在的危险,会对原字符串进行破坏,还有可能会出现溢出错误,如果原字符串是字符串常量,你这样就会出问题。如果是相当有把握,保证原字符串之后的内存空间可以使用,不溢出,也是可以用。


回复

使用道具 举报

您需要登录后才可以回帖 登录 | 注册

本版积分规则

  • 论坛活动 E手掌握

    扫码关注
    EEWORLD 官方微信

  • EE福利  唾手可得

    扫码关注
    EE福利 唾手可得

小黑屋|手机版|Archiver|电子工程世界 ( 京ICP证 060456

GMT+8, 2018-8-20 20:55 , Processed in 0.342361 second(s), 16 queries , Gzip On, Redis On.

快速回复 返回顶部 返回列表