小弟学习C语言,用的教材是西安电子科技大学出版社马鸣远编著的《程序设计与C语言》,104页中的第22题:22.指出下面程序的执行结果。
#include<stdio.h>
main()
{
int s=0,i=1,j=10;
while(i--&&j--,s+=2,j++<15);
printf("%d\n",i+j+s);
return 0;
}用TurboC2.0编译运行出来的结果是19,实在是不懂!何解???先给100分,不够再加!各位大侠看看!
#include<stdio.h>
main()
{
int s=0,i=1,j=10;
while(i--&&j--,s+=2,j++<15);
printf("%d\n",i+j+s);
return 0;
}用TurboC2.0编译运行出来的结果是19,实在是不懂!何解???先给100分,不够再加!各位大侠看看!
N无聊
while(i--&&j--,s+=2,j++>15);
改为大于吧。否则不出结果啊
我还发现如果while后接上一条语句,比如说改成while(i--&&j--,s+=2,j++<15)printf("");
则是一个无限循环。
我用TC调试过,发现结果的确是19,并且最后 i=-1,j=16,s=4;
我还发现如果while后接上一条语句,比如说改成while(i--&&j--,s+=2,j++<15)printf("");
还是不会变,但如果改成
while(i--&&j--,s+=2,j++<15)printf("%d\n",i);
则是一个无限循环。
所以我觉得这是一个debug,因为同样的程序在VC里编译while(i--&&j--,s+=2,j++<15);
同while(i--&&j--,s+=2,j++<15)printf("%d\n",i);
的执行过程相同。
他们是没有理由不同的。
main()
{
int i=1,s=0,j=10;
while(i--&&j--,s+=2,j++<15)
{
/*我加了这几行,帮助观察程序*/
printf("%d %d %d\n",i,s,j);
}
printf("\n%d\n",i+s+j);
return 0;
}
当程序运行到最后并自动结束时(为了保证能看到程序结束时的运行结果,请首先进入命令行,再启动程序运行),屏幕上留下了一下信息:
....
1 0 15
0 2 1519
好,当0 2 15出现时,说明在while里的printf语句执行时的i,s,j的值分别是0,2,15.大家会发现,只有每次当i值变为0时,j的值才曾1,而i是可以通过不断的溢出循环一再变成1的。关键是当i变成0时j的值是多少。
从0,2,15一行分析,因为j++<15,所以while要想结束,必须j>=15,而while中的printf打出的j值,应该是j自加之后的值,也就是说,当进行j++<15的比较时,j还是14。好,由于当i为0时j会因此加一,所以在0,2,15一行之后的情况应该是,i=0,s=4,j变成了15,比较j++<15,此时15<15不成立,整个逗号表达式的值为0,while结束.此时i再自减,因为i=0,所以&&后的表达式不再参与运算,所以j只自加(j++<15中的自加),不用自减了(i--&&j--中的自减).
所以最后i=-1,s=4,j=16,就i+s+j=-1+4+16=19.
可能有些地方没说明白,抱歉.
所以仅有循环到第二次时,j--才会因为i--表达式已经为零而不做,其它时候都是作了j--,和j++的,这样,j的值就不会变化,而逗号表达式的值,即最后一项的值就始终为真,所以就会一直循环下去。
而TC在循环体中有一定的语句时也是这个结果,但在为空时出现异常,我认为是它的一个debug.我已在这上面花了一下午的时间了,所以大家不要再为这个浪费时间了。
请让程序正常运行5分钟左右(呵呵,我的机子慢)你会发现她能正常结束。
这样改就不用5分钟了,我的确是忽略了溢出。
#include<stdio.h>
main()
{
int i=1,s=0,j=10;
while(i--&&j--,s+=2,j++<15)
{
/*我加了这几行,帮助观察程序*/
if(i==0)
printf("%d %d %d\n",i,s,j);
}
printf("\n%d\n",i+s+j);
return 0;
}
结果如下:
0 2 10
0 2 12
0 2 13
0 2 14
0 2 1519
因为s 总比 i 快一倍,也就是说在i每一次溢出间隔之中,i总是从0,-1,-2,-3...
s总是2,4,6,。。,2,4,6,溢出了两次。
要不然,就是32位的int 虽然结果一样,但就不知会用多少时间了。
当我把代码改成以下这个样子:
001 #include<stdio.h>
002 main()
003 {
004 int s=0,i=1,j=10;
005 int x=0,y=0,z=0;
006 while(i--&&j--,s+=2,j++<15){x=i;y=j;z=s;}
007 printf("%d\n",i+j+s);
008 return 0;
009 }
当代码是上面这个样子的时候,在Turboc2.0中调试时,使用F7单步,在第6行一下就过了,并且可以监测到x,y,z 的值分别是-1、4、16。
当我把代码改成下面这个样子:
001 #include<stdio.h>
002 main()
003 {
004 int s=0,i=1,j=10;
005 int x=0,y=0,z=0;
006 while(i--&&j--,s+=2,j++<15)
007 {
008 x=i;
009 y=j;
010 z=s;
011 }
012 printf("%d\n",i+j+s);
013 return 0;
014 }
当我把代码改成上面这个样子,单步时Turboc2.0的编译器会在第8行到第10行反复运行很长的时间,直到溢出后得到19。
如果说溢出我还想得通,那么这两段的运行差异就让我很奇怪了,怎么会是这样呢?TC的编译器究竟是怎么做的?看到大家说了这么多,我很感谢,其实我把这个题发出来还有一个意思,就是想问问这本书的作者或编者,书出来后你自己调试过这段代码吗?或者是印刷错了,但是为什么没有看到勘误呢?要知道,你们的书是给一群对计算机程序充满向往而刚刚起步学习的年轻学生,他们对于计算机程序的理解和判别都十分有限。教科书对于学生是有相当强的引导作用的,我想问问你们是想引导什么?是要他们以后在编程工作中利用“溢出”来得到正确结果吗?话说到这里,也想奉劝各位,对待年轻学生的教育,对待编书、出书,谨慎!谨慎!
因为while()的原型是while(bool),
所以这个程序主要的问题是在这bool上面,bool为1则运行while,bool为0则跳过。
所以这里只是对(i--&&j--,s+=2,j++<15)这个整体进行判断,对它进行强制(隐式)类型转换后的值是false还是true的问题!
当然有一点必须说清的在VC中对于多个串的判断是以最后一项的结果为准(当然不同编译器可能有问题),所以while(i--&&j--,s+=2,j++<15)就相当于
do
{
i--&&j--;
s+=2;
}while(j++<15)
所以j--之后,又j++,j的值终没变,当然肯定小于15,因此(j++<15)始终为true
因此列循环!!
while(i--&&j--,s+=2,j++<15,0)
while(i--&&j--,s+=2,j++<15,1)
之后,你就会一目了然了!!
实际应用中不允许出现这样的代码,但是这种代码好像有助于了解各个公司编译器的实现差别。
小弟菜鸟,愿倾听各位大侠真知灼见!
条件语句:i--&&j--因为是and,所以当i!=0时,需执行另一个条件,即执行j--;如果i==0则可判断条件语句(i--&&j--为非),不执行j--,此时整个j--和j++执行结果是j=j+1。
{_asm nop
_asm xor eax,eax
_asm mov eax,1
_asm mov eax,2
_asm xor eax,eax int s=0,i=1,j=10;
while(i--&&j--,s+=2,j++<15);
printf("%d\n",i+j+s);
return 0;
}asm 代码:
00401000 fn_00401000:
00401000 56 push esi
00401001 90 nop
00401002 33C0 xor eax,eax
00401004 B801000000 mov eax,1
00401009 B802000000 mov eax,2
0040100E 33C0 xor eax,eax
00401010 33C9 xor ecx,ecx
00401012 BA01000000 mov edx,1
00401017 B80A000000 mov eax,0Ah
0040101C loc_0040101C:
0040101C 8BF2 mov esi,edx
0040101E 4A dec edx
0040101F 85F6 test esi,esi
00401021 7401 jz loc_00401024
00401023 48 dec eax
00401024 loc_00401024:
00401024 83C102 add ecx,2
00401027 8BF0 mov esi,eax
00401029 40 inc eax
0040102A 83FE0F cmp esi,0Fh
0040102D 7CED jl loc_0040101C
0040102F 03C2 add eax,edx
00401031 03C1 add eax,ecx
00401033 50 push eax
00401034 6830604000 push 406030h
00401039 E812000000 call fn_00401050
0040103E 83C408 add esp,8
00401041 33C0 xor eax,eax
00401043 5E pop esi
00401044 C3 ret
在tc 下循环约65536×4次,时间要短的多。
while(i--&&j--,s+=2,j++<15); // 这个语句比较变态
可以翻译成这样的形式:
while(TRUE)
{
if ( (i-- != 0) && (j-- != 0)
&& ( (s += 2) != 0 )
&& (j++ < 15) )
{
break;
}
}不过,这样的形式,还是TMD很难懂。
2.这里,i 不断减 1 ,直到溢出又回到了 0 时,j 增 1
3.当两个条件都为假(j++ < 15 为假,i--&&j-- 为假)时,就跳出来。My god! TC 是 16 位的,还有心情等溢出,等结果,在 32 位 C++ 里就没心情等了,如果要是 64 位,128 位,那...