2 zuoside  lord zuoside__lord 于 2017.11.10 20:31 提问

为什么这个变量不能控制循环,变量作用域

#include
int main()
{
int N;
int i = 0;
scanf("%d",&N);
while(i<N)
{
unsigned short a,g,d;
printf("请输入a\n");
scanf("%u",&a);
printf("我是a=%u\n",a);
i++;
printf("我是i=%d\n",i);
printf("我是N=%d",N);
}

return 0;

}//如题,N不能控制循环,我怀疑是因为变量作用域问题,可是为什么呢,我把N改成static int N,把i改成static int i就又可以了,有没有办法可以不改,求解答,

6个回答

jinhangdev
jinhangdev   2017.11.10 23:07
已采纳

楼上说的可能没在点子上,本程序真正出问题的原因应该是:读入a的值的时候由于格式化字符串中的%u溢出将N的值破坏了,因为N和a均在栈中管理,N的首地址比a的首地址高2个字节,当向a的首地址放入4个字节的数据时,N的低2字节将被覆盖
改成static int N以后,N将不再在栈中管理,因此就不会和栈中的a冲突,因此改为static后就正常了。
下面看一下N和a均在栈中时的汇编代码:
跟踪到scanf("%d",&N);时:

   0x00401566 <+70>:    lea    0x58(%esp),%eax
   0x0040156a <+74>:    mov    %eax,0x4(%esp)
   0x0040156e <+78>:    movl   $0x41b000,(%esp)
   0x00401575 <+85>:    movl   $0x1,0x20(%esp)
   0x0040157d <+93>:    call   0x40b558 <scanf>

可见,N的地址为0x58(%esp)
跟踪到scanf("%u",&a);时:

   0x00401598 <+120>:   lea    0x56(%esp),%eax
   0x0040159c <+124>:   mov    %eax,0x4(%esp)
   0x004015a0 <+128>:   movl   $0x41b00b,(%esp)
   0x004015a7 <+135>:   call   0x40b558 <scanf>

可见,a的地址为0x56(%esp)
在执行本次scanf之前,我先扫一下0x56(%esp)的地址(此时ESP的值为0x28fe50):

(gdb) x/10bx ($esp+0x56)
0x28fea6:   0x00    0x00    0x0a    0x00    0x00    0x00    0x00    0x00

可见N位于$esp+0x58处,确实是10(0x0000000a)
下面我们给a读入一个127(0x007f),看看0x56(%esp)的地址变化的情况:

(gdb) x/10bx ($esp+0x56)
0x28fea6:   0x7f    0x00    0x00    0x00    0x00    0x00    0x00    0x00

看到了吗?之前的0x0a被覆盖掉了,因为%u使得scanf函数&a处写入了**4**个字节,假如我们输入一个对于unsigned short会溢出的数,比如4294967295(0xffffffff),你将在屏幕上看到以下输出:

10
请输入a
4294967295
我是a=65535
我是i=1
我是N=65535请输入a
(后面的输出省略)

看吧!N怎么会等于65535(0xffff)!原来就是因为写入的0xffffffff覆盖掉了N的低16位!此时去扫一下内存,一定会发现N所在的0x58(%esp)变为了0xff 0xff

改成static int N以后,N将不再在栈中管理,因此就不会和栈中的a冲突,因此改为static后就正常了。

个人的一点探讨,如尚未解决您的问题,可追问;若解决了您的问题,请采纳。

jinhangdev
jinhangdev   2017.11.10 23:11

补充一点,造成上述问题的关键点在于%uunsigned short的不匹配,若将unsigned short改为unsigned int,程序也将正常运行!

zuoside__lord
zuoside__lord 谢谢,看了半天,好像就你回复比较正常,,,像是那么回事。虽然上面一堆不是很明白,看来汇编很有用很高大上,也就是说是那个人定义和输入时的数据类型不匹配造成的咯,然后造成数据溢出,
11 天之前 回复
chenxiansheng888
chenxiansheng888   2017.11.11 09:41

short 错了吧 改成int 试试

liangshilin
liangshilin   2017.11.10 22:38

不想加static,也可将定义 N 和 i 放到main()外面,似乎要用scanf()输入的话会重新跑一遍main(),所以之前的N会变回0

gameuu
gameuu   2017.11.11 06:50

简单说就是n开始没有赋值,

zuoside__lord
zuoside__lord 我把N赋值试过,赋值为0也没有什么用
11 天之前 回复
qq_24276421
qq_24276421   2017.11.11 13:44

"N改成static int N,把i改成static int i就可以了" 这种现象是典型的变量使用前没有初始化的缘故,你的局部变量在栈里,是不会默认初始化为0的,而定义成static 的时候,变量在数据段,程序在运行时,会先将数据段初始化为0,

Csdn user default icon
上传中...
上传图片
插入图片