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

2021-01-27 11:15:19 +08:00
 NoahNye

着实无法理解,为什么已经赋值的 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

并且,在用新的指针赋值之后,这个 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

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

1905 次点击
所在节点    C
14 条回复
hello2060
2021-01-27 11:23:23 +08:00
已经忘了 C 了,但是既然 stripy 越界了,变量值改变也是有可能的啊,你看看数组 a 和 d 的地址,看看 d 是不是跟在 a 数组元素后面
shuax
2021-01-27 11:24:51 +08:00
你不懂什么叫越界吗
hello2060
2021-01-27 11:25:01 +08:00
最简单的,IDE 里单步 debug 看 memory 变化
hello2060
2021-01-27 11:28:50 +08:00
最后你定义了 c_ d_那可能就改变了栈内各个变量地址的关系,本身正常的程序就不预设栈内变量地址之间的关系。一旦越界了,啥都有可能发生。

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

按定义顺序,依次入栈的是 c,d,a,b ; intel 小端,d 的低字节和 a 的末尾是连着的;进而溢出的'\0'把 d 的低字节覆盖了
hello2060
2021-01-27 11:55:56 +08:00
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
2021-01-27 11:57:25 +08:00
继续往下学吧,如果你只停留在 C 语法上的话,大家跟你解释你也不大听得懂。
这个问题你学到 C 语言的基本类型在机器上的内存排布就自然明白了
changcui
2021-01-27 13:13:51 +08:00
和 strcpy 无关吧,sizeof 是编译的时候就计算好的
ipwx
2021-01-27 13:16:35 +08:00
怎么又讨论起未定义行为了?讨论这种的行为没有意义,因为 -O3 可以把指令都乱序,内存读取跳过(用寄存器),诸如此类的。。。
huangmingyou
2021-01-27 13:22:35 +08:00
gdb 解君愁
ghostcir
2021-01-27 14:21:12 +08:00
因为 a 内存越界了,结尾的\0 填到了 d 的内存
aneostart173
2021-01-27 15:24:06 +08:00
第一个 c_和 d_都没用,编译器给优化掉了, 第二个 c_和 d_都用上了,栈布局就变了。越界了什么事都会发生,讨论这个没任何意义。

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/748830

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX