求解答,关于 C 使用 strcpy 问题 - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
NoahNye
V2EX    C

求解答,关于 C 使用 strcpy 问题

  •  
  •   NoahNye 2021 年 1 月 27 日 2603 次点击
    这是一个创建于 1826 天前的主题,其中的信息可能已经有所发展或是发生改变。

    着实无法理解,为什么已经赋值的 c 和 d 会在 strcpy 之后改变原值(这里故意设置错误下标导致复制越界)

    #include <stdio.h> #include <string.h> int main(){ char a[6]={"hello"},b[7]={"world1"}; // a[]="hello"; // b[]="world"; int c,d; int *c_,*d_; c=(int)sizeof(a)/sizeof(*a); d=(int)sizeof(b)/sizeof(*b); // c_=&c; // d_=&d; // printf("c_=%p\td_=%p\n",c_,d_); // printf("c=%p\td=%p\n",&c,&d); printf("c=%d,d=%d\n",c,d); strcpy(a,b); printf("%s-%s\n",a,b); printf("c=%d,d=%d",c,d); } 

    运行结果: !run1 [root@iZwz94s0djlh8ob47gwodcZ Ctest]# ./test
    c=6,d=7
    world1-world1
    c=6,d=0
    run1.png

    并且,在用新的指针赋值之后,这个 c 和 d 又不会因为 strcpy 而改变原值了。

    #include <stdio.h> #include <string.h> int main(){ char a[6]={"hello"},b[7]={"world1"}; // a[]="hello"; // b[]="world"; int c,d; int *c_,*d_; c=(int)sizeof(a)/sizeof(*a); d=(int)sizeof(b)/sizeof(*b); c_=&c; d_=&d; // printf("c_=%p\td_=%p\n",c_,d_); // printf("c=%p\td=%p\n",&c,&d); printf("c=%d,d=%d\n",c,d); strcpy(a,b); printf("%s-%s\n",a,b); printf("c=%d,d=%d",c,d); } 

    运行结果:
    [root@iZwz94s0djlh8ob47gwodcZ Ctest]# ./test
    c=6,d=7
    world1-world1
    c=6,d=7
    run2.png

    测试了 gcc 和 clang,只有 gcc 出现这个问题。

    第 1 条附言    2021 年 1 月 27 日

    p.png
    gdb里很明显了,因为越界导致顶栈被设为0。
    想到一个曲线救国的方法,就是再另外设置一个变量 'e',只要数组复制相差的位数小于e,就可以假装显示正常结果,相当于设置一个变量当作溢出缓存,避免顶端想要的结果被修改,不过也只是可用在研究或调试上。
    很低端的错误,让大家见笑了。

    和strcpy一样,strncpy把源字符串的字符复制到目标数组。然而,它总是正好向dst写入len个字符。如果strlen( src )的值小于len,dst数组就用额外的NUL字节填充到len长度。如果strlen( src )的值大于或等于len,那么只有len个字符被复制到dst中。注意!它的结果将不会以NUL字节结尾。 《C和指针》

    14 条回复    2021-01-27 15:24:06 +08:00
    hello2060
        1
    hello2060  
       2021 年 1 月 27 日 via iPhone   1
    已经忘了 C 了,但是既然 stripy 越界了,变量值改变也是有可能的啊,你看看数组 a 和 d 的地址,看看 d 是不是跟在 a 数组元素后面
    momo1999
        2
    momo1999  
       2021 年 1 月 27 日
    你不懂什么叫越界吗
    hello2060
        3
    hello2060  
       2021 年 1 月 27 日 via iPhone   1
    最简单的,IDE 里单步 debug 看 memory 变化
    hello2060
        4
    hello2060  
       2021 年 1 月 27 日 via iPhone   1
    最后你定义了 c_ d_那可能就改变了栈内各个变量地址的关系,本身正常的程序就不预设栈内变量地址之间的关系。一旦越界了,啥都有可能发生。

    不过最简单的还是 debug 一下
    hello2060
        5
    hello2060  
       2021 年 1 月 27 日 via iPhone   2
    你说你无法理解,这个不需要理解啊,因为这个 code 出错了,所以啥错误都是有可能的。
    NoahNye
        6
    NoahNye  
    OP
       2021 年 1 月 27 日
    @hello2060 谢谢回复,之前有发过在 stackoverflow,好像也差不多得到这种回答,大概是错误的代码导致不可预期的行为,但我还是觉得这个赋值的这两个变量不应该因为 strcpy 而改变,因为它们并没有在 strcpy 之后被重新赋值。既然是程序错误,我也不在这个错误代码里钻牛角尖了。最后再次感谢您的回复。
    LANB0
        7
    LANB0  
       2021 年 1 月 27 日   1
    如一楼所说,你 strcpy 越界了。越界的字节覆盖了变量 d 低字节的内存,后一种写法,d_的值也是有误的。
    Linux 下局部变量内存地址分布顺序:
    按字节大小,大的先入栈;
    字节大小相同的,后定义的先入栈;

    按定义顺序,依次入栈的是 c,d,a,b ; intel 小端,d 的低字节和 a 的末尾是连着的;进而溢出的'\0'把 d 的低字节覆盖了
    hello2060
        8
    hello2060  
       2021 年 1 月 27 日
    strcpy(a, b) 的时候 a + 6 和 a + 7 那个位置的值都被错误的覆盖了(我已经忘了最后的\0 是怎么处理的了,反正至少有一个 byte 被 strcpy 这个动作错误的改写了,

    d 的内存地址可能刚好包括这个 byte, '这个赋值的这两个变量不应该因为 strcpy 而改变,因为它们并没有在 strcpy 之后被重新赋值' -- 变量 d 并不是只有被重新赋值了才会有新值,任何操作他内存地址的操作都有可能改变他的值啊


    比如说你定义

    char a, char b, 假设他们在内存里是 [a,b]
    你再定义 int* p = &a, (我不确定这个是否是正确的语法)
    *p = 0, 这里对 p 的内存改写,因为 p 指向 4 个 byte 的 int, 从 a 地址开始的 4 个 byte 都变成 0 了,b 也变 0 了
    nightwitch
        9
    nightwitch  
       2021 年 1 月 27 日
    继续往下学吧,如果你只停留在 C 语法上的话,大家跟你解释你也不大听得懂。
    这个问题你学到 C 语言的基本类型在机器上的内存排布就自然明白了
    changcui
        10
    changcui  
       2021 年 1 月 27 日
    和 strcpy 无关吧,sizeof 是编译的时候就计算好的
    ipwx
        11
    ipwx  
       2021 年 1 月 27 日   2
    怎么又讨论起未定义行为了?讨论这种的行为没有意义,因为 -O3 可以把指令都乱序,内存读取跳过(用寄存器),诸如此类的。。。
    huangmingyou
        12
    huangmingyou  
       2021 年 1 月 27 日
    gdb 解君愁
    ghostcir
        13
    ghostcir  
       2021 年 1 月 27 日
    因为 a 内存越界了,结尾的\0 填到了 d 的内存
    aneostart173
        14
    aneostart173  
       2021 年 1 月 27 日
    第一个 c_和 d_都没用,编译器给优化掉了, 第二个 c_和 d_都用上了,栈布局就变了。越界了什么事都会发生,讨论这个没任何意义。
    关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     5791 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 30ms UTC 02:04 PVG 10:04 LAX 18:04 JFK 21:04
    Do have faith in what you're doing.
    ubao msn snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86