小弟学习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分,不够再加!各位大侠看看!

解决方案 »

  1.   

    奇怪了,我怎么从来都没有写过这样的while语句
      

  2.   

    NND,见到这种题,就想扁那个出题人。
    N无聊
      

  3.   

    VC , TC下都没结果
      

  4.   

    int s=0,i=1,j=10;
      while(i--&&j--,s+=2,j++>15);
     改为大于吧。否则不出结果啊
      

  5.   

    while语句有这么写的吗?建议先学c编码规范!
      

  6.   

    朋友们请息怒,我用TC调试过,发现结果的确是19,并且最后 i=-1,j=16,s=4;
    我还发现如果while后接上一条语句,比如说改成while(i--&&j--,s+=2,j++<15)printf("");
    则是一个无限循环。
      

  7.   

    循环条件是个逗号表达式,建议楼主好好看一下书,其实这个题目不是很难,还有j++>15才对!
      

  8.   

    更正:
    我用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);
    的执行过程相同。
    他们是没有理由不同的。
      

  9.   

    搂主,这道题不错,很能考查大家对逗号表达式和int型溢出的理解。众位楼上的大哥,恕我拙见,其实编程并不一定要实用,我相信大家最初步入这一行,应该不是仅仅为了实现一两个别人已经实现过了的功能,或是,挣一两个money吧?大家难道不是因为喜欢编程才开始自己的计算机生涯的吗?就是因为喜欢才去喜欢,仿佛初恋一样。在这个物欲的世界里,对于我们来说,也就是create程序才能帮我们找回那份珍贵的感觉了吧。经过艰苦卓绝的努力,终于获得了成功,那时的兴奋,也是众位大哥们迷恋这一行的原因吧。所以程序本无好坏之分,我们尊重的是,那份深藏于我们内心深处的感觉。如果这个程序能诱出那份感觉,我想,它就应该算是一个好程序了吧。#include<stdio.h>
    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.
    可能有些地方没说明白,抱歉.
      

  10.   

    因为非零即为真,
    所以仅有循环到第二次时,j--才会因为i--表达式已经为零而不做,其它时候都是作了j--,和j++的,这样,j的值就不会变化,而逗号表达式的值,即最后一项的值就始终为真,所以就会一直循环下去。
    而TC在循环体中有一定的语句时也是这个结果,但在为空时出现异常,我认为是它的一个debug.我已在这上面花了一下午的时间了,所以大家不要再为这个浪费时间了。
      

  11.   

    :vollin(林尚义) 
    请让程序正常运行5分钟左右(呵呵,我的机子慢)你会发现她能正常结束。
      

  12.   


    这样改就不用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
      

  13.   

    hehe是啊,因为我原本也以为这是一个死循环程序呢,
      

  14.   

    为什么不i=0时,s=2呢?
    因为s 总比 i 快一倍,也就是说在i每一次溢出间隔之中,i总是从0,-1,-2,-3...
    s总是2,4,6,。。,2,4,6,溢出了两次。
      

  15.   

    因为s的值对j没有影响啊,对于i--&&j--逻辑表达式,只有i--不为0时,此表达式才会运算j--的值,看是否为0.所以当i=0了,整个表达式就为0了,不需要计算j--
      

  16.   

    还有在VC中编译也是一样的结果,不过为了速度快一点最好将int 改为_int16.
    要不然,就是32位的int 虽然结果一样,但就不知会用多少时间了。
      

  17.   

    呵呵!感谢各位大侠,其实这道题真的是我的小弟在教材上看到的,要我帮他解释,我想到的原因跟各位说的差不多。但是我在调试的时候还发现了这样一个现象。
    当我把代码改成以下这个样子:
    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的编译器究竟是怎么做的?看到大家说了这么多,我很感谢,其实我把这个题发出来还有一个意思,就是想问问这本书的作者或编者,书出来后你自己调试过这段代码吗?或者是印刷错了,但是为什么没有看到勘误呢?要知道,你们的书是给一群对计算机程序充满向往而刚刚起步学习的年轻学生,他们对于计算机程序的理解和判别都十分有限。教科书对于学生是有相当强的引导作用的,我想问问你们是想引导什么?是要他们以后在编程工作中利用“溢出”来得到正确结果吗?话说到这里,也想奉劝各位,对待年轻学生的教育,对待编书、出书,谨慎!谨慎!
      

  18.   

    其实这个问题很简单!!
    因为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
    因此列循环!!
      

  19.   

    关键是要看(j++<15)是真还是假,当然你试试
    while(i--&&j--,s+=2,j++<15,0)
    while(i--&&j--,s+=2,j++<15,1)
    之后,你就会一目了然了!!
      

  20.   

    关于时间差异的问题,我们要知道调试时与实际运行时是不同的,所谓单步,实际上是运行一行的程序,而且每次运行完了之后除了程序用的时候外,还要在代码中定位,这是显示刷新的速度与CPU速度是无法匹配的。所以才会有差异,而你直接运行所用的时间你可以测一下,绝对是一样的。
      

  21.   

    这个程序在VC下死循环,在TC下算出是19,但是在TC下如果while循环体内有代码的话就会陷入死循环。我是这样理解的,在TC下,如果循环体内没有代码,while()只取逗号表达式最右边表达式的值,左边及中间的表达式不去计算,而如果循环体内有代码,那么整个逗号表达式里边的表达式都要进行运算,刚进行完j++又进行j--,当然死循环了。而在VC下,不管循环体内有没有代码,都要计算逗号表达式里的所有表达式,j++刚进行完就进行j--,所以就死循环了。
        实际应用中不允许出现这样的代码,但是这种代码好像有助于了解各个公司编译器的实现差别。
        小弟菜鸟,愿倾听各位大侠真知灼见!
      

  22.   

    题目很好,但真的比较难,建议将int 改为char
    条件语句:i--&&j--因为是and,所以当i!=0时,需执行另一个条件,即执行j--;如果i==0则可判断条件语句(i--&&j--为非),不执行j--,此时整个j--和j++执行结果是j=j+1。
      

  23.   

    int main(int argc, char* argv[])
    {_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
      

  24.   

    这个程序在VC下不是死循环,只是时间很长。试想一下,循环约4294967296×4次需要多少时间。
    在tc 下循环约65536×4次,时间要短的多。
      

  25.   

    32位VC编译器,结果是一个超级长循环,你可以花一个晚上来执行:)
    while(i--&&j--,s+=2,j++<15); // 这个语句比较变态
    可以翻译成这样的形式:
    while(TRUE)
    {
    if ( (i-- != 0) && (j-- != 0)
        && ( (s += 2) != 0 )
        && (j++ < 15) )
    {
    break;
    }
    }不过,这样的形式,还是TMD很难懂。
      

  26.   

    有点无聊,这样的程序的确不好理解。1.当 i 为 0 时,下一个 j 才会增 1
    2.这里,i 不断减 1 ,直到溢出又回到了 0 时,j 增 1
    3.当两个条件都为假(j++ < 15 为假,i--&&j-- 为假)时,就跳出来。My god! TC 是 16 位的,还有心情等溢出,等结果,在 32 位 C++ 里就没心情等了,如果要是 64 位,128 位,那...