着实无法理解,为什么已经赋值的 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
#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 出现这个问题。
gdb里很明显了,因为越界导致顶栈被设为0。
想到一个曲线救国的方法,就是再另外设置一个变量 'e',只要数组复制相差的位数小于e,就可以假装显示正常结果,相当于设置一个变量当作溢出缓存,避免顶端想要的结果被修改,不过也只是可用在研究或调试上。
很低端的错误,让大家见笑了。
1
hello2060 2021-01-27 11:23:23 +08:00 via iPhone 1
已经忘了 C 了,但是既然 stripy 越界了,变量值改变也是有可能的啊,你看看数组 a 和 d 的地址,看看 d 是不是跟在 a 数组元素后面
|
2
shuax 2021-01-27 11:24:51 +08:00
你不懂什么叫越界吗
|
3
hello2060 2021-01-27 11:25:01 +08:00 via iPhone 1
最简单的,IDE 里单步 debug 看 memory 变化
|
4
hello2060 2021-01-27 11:28:50 +08:00 via iPhone 1
最后你定义了 c_ d_那可能就改变了栈内各个变量地址的关系,本身正常的程序就不预设栈内变量地址之间的关系。一旦越界了,啥都有可能发生。
不过最简单的还是 debug 一下 |
5
hello2060 2021-01-27 11:30:13 +08:00 via iPhone 2
你说你无法理解,这个不需要理解啊,因为这个 code 出错了,所以啥错误都是有可能的。
|
6
NoahNye OP @hello2060 谢谢回复,之前有发过在 stackoverflow,好像也差不多得到这种回答,大概是错误的代码导致不可预期的行为,但我还是觉得这个赋值的这两个变量不应该因为 strcpy 而改变,因为它们并没有在 strcpy 之后被重新赋值。既然是程序错误,我也不在这个错误代码里钻牛角尖了。最后再次感谢您的回复。
|
7
LANB0 2021-01-27 11:44:31 +08:00 1
如一楼所说,你 strcpy 越界了。越界的字节覆盖了变量 d 低字节的内存,后一种写法,d_的值也是有误的。
Linux 下局部变量内存地址分布顺序: 按字节大小,大的先入栈; 字节大小相同的,后定义的先入栈; 按定义顺序,依次入栈的是 c,d,a,b ; intel 小端,d 的低字节和 a 的末尾是连着的;进而溢出的'\0'把 d 的低字节覆盖了 |
8
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 了 |
9
nightwitch 2021-01-27 11:57:25 +08:00
继续往下学吧,如果你只停留在 C 语法上的话,大家跟你解释你也不大听得懂。
这个问题你学到 C 语言的基本类型在机器上的内存排布就自然明白了 |
10
changcui 2021-01-27 13:13:51 +08:00
和 strcpy 无关吧,sizeof 是编译的时候就计算好的
|
11
ipwx 2021-01-27 13:16:35 +08:00 2
怎么又讨论起未定义行为了?讨论这种的行为没有意义,因为 -O3 可以把指令都乱序,内存读取跳过(用寄存器),诸如此类的。。。
|
12
huangmingyou 2021-01-27 13:22:35 +08:00
gdb 解君愁
|
13
ghostcir 2021-01-27 14:21:12 +08:00
因为 a 内存越界了,结尾的\0 填到了 d 的内存
|
14
aneostart173 2021-01-27 15:24:06 +08:00
第一个 c_和 d_都没用,编译器给优化掉了, 第二个 c_和 d_都用上了,栈布局就变了。越界了什么事都会发生,讨论这个没任何意义。
|