对了今天看到一个自增问题
今天,有个同学问了我一个题目,就是关于自增量与自增符号的运用的问题。请看下面的问题:
void main()
{int m,j=5;
m=(j++)+(++j)+(j++);
printf("%d %d",m,j);
}
在没有运行的时候,你猜会是什么结果呢?
一般人来说,特别是初学者,一般会认为是m=19,但结果运算起来却是18。
为什么会与认为的不一样呢?难道是自增量与自增符号掌握的不对?
其实,课本上的,还有很多书籍上都会有这样的习题,却没有告诉读者更多的相关信息,让人对自己的答案与运行结果都产生了怀疑。一般产生疑问是正常的,因为课本甚至是老师等等对这个问题不在意,甚至根本不明白什么原理,只告诉学生,这是因编译器不同而造成的(当然,不是这个题目,这个题目不是因为编译器问题),造成很多学生都不想太深究。
所以很多学生不明就理,只知道有这回事,不究根问底。这对于想学好编程的朋友是致命伤。可能有些人会认为,自己只是初学者,就算知道有这个问题,问别人也不一定能懂。没错,确实存在着因为知识角度不到位和知识水平有限,可能理解不了别人的东西,但问题是,对于我们学习编程的人来说,就是进行从不会到会,从不懂到学到懂的反复过程,不能任之听之。当然,如果只想在考试拿个分数就行了,就可以当我没说过这回话。
话说回来,自增量与自减量(其实是一样的,下面都只讲自增)都有自己的运算执行规则,在这些规则下,加上编译原理的不同,就会造成相当大的不确定性,这在编程时尤其注意,因为很多bug也是这样出来的。
但是,如果我们掌握了产生不确定性的原因,在整个过程当中都注意的话,那么这样的不确定性也成为了必然执行结果,变不确性为确定性了。就像上边的题目一样,当我们知道后自增量是在语句或是表达式执行完后再执行增量操作的话,我们就不会容易产生错误的判断。在上课时,老师只告诉我们,后增量是对变量执行后再进行增操作,前增量是在使用前就进行增量操作,这话没错,因为从大范围来说,这话是对的,但还有一个问题,就是这个范围大小如何确定呢??
其实很简单,在C类语言中,后增量的执行范围是在后增量运算的语句或表达式执行完后,下一个语句或表达式执行前执行增量操作的,换句容易理解的话说,后增量是在程序执行到该语句的分号时才进行操作的。
而前增量,是在语句或表达式执行完前就会进行的的操作。举例说明:
用上面的例子,m=(j++)+(++j)+(j++);
在执行这个语句时,第一个或第三个j++,是后增量,程序只要没执行到”;”,那么,增量就不会执行,这样,这个语句就相当于m=(j)+(++j)+(j);
在说明结果前,还要说明一下,无论什么运算,都要通过进栈来运算(如果对栈概念不理解,可以查看数据结构的书籍,在这里说明一下,栈是用来存放数据的,在这里是广义的数据,而栈的结构就是一个盒子,当你向栈放入东西时,最后存放的要最先拿出来,就像叠盘子一样,最拿最下面的,必须先拿掉最上面的。也就是栈具有后进先出的特点。)。
这样,对于上面的语句m=(j)+(++j)+(j);
在语句执行完前,先进行++j运算,假设j=5,那么运算后,j=6,这样,对于语句m=(j)+( j)+(j);无论进栈方式如何,都是一样的了,这样,结果就是18了,知道这个原理后,就不会轻易放错误了。
而根据编译原理的和进栈次序不同,增量操作就有不同的结果。下面述说这情况:
无论哪个编译器,TC,VC,后加都是在语句或表达式执行完后(即遇分号后再进行),而对于前加,在TC中,它是先运算后,再进栈,即将前加都运算后,再将表达式依次进栈。
如:
int j=5;
m=(j)+(++j)+(j)+(++j)+(j);
它是先对两个++j进行运算(这是j=7),后进栈运算,这样得出结果是35。
在VC中,它是先进栈,出栈后(依表达式再运算,这在理解上有点像是递归)再运算,当然这里面还有些要理解:
如:
int j=5;
m=(j)+(++j)+(j)+(++j)+(j);
中,
是先进行前面两个(j)+(++j)运算,而此时,这语句就相当于内部的表达式,所以在进行+运算前(也就是表达式执行完前)先进行++运算,即++j运算,这样就会得到(j)+(j),此时j=6.再进行+运算。如此下去,结果就是32。
对于完整的表达式,如上面的m表达式,在运算过程当中,出栈后运算的结果基本上是数值的了已与变量j无关联了。(结果运算后还要进栈,再依次出栈运算,这时这个过程已经相当简单了)。
这样后,就不难理解了结果的产生了。也不会因为编译器的不同产生不同的结果而迷惘。希望,今天这篇文章会对朋友们有所帮助。下面给出题目,让大家理解一下:
VC++6.0
#include<stdio.h>
void main()
{int m,j=5;
j=5;
m=(++j)+(++j);//14
printf("%d %d\n",m,j);
j=5;
m=(j++)+(j++);//10
printf("%d %d\n",m,j);
j=5;
m=(j++)+(++j)+(++j);//19
printf("%d %d\n",m,j);
j=5;
m=(j++)+(++j)+(j++)+(++j);//25
printf("%d %d\n",m,j);
j=5;
m=(j++)+(++j)+(j++)+(++j)+(j++);//32
printf("%d %d\n",m,j);
j=5;
m=(++j)+(j++)+(++j)+(++j);//27
printf("%d %d\n",m,j);
j=5;
m=(j);
printf("%d %d\n",m,j);//5
j=5;
m=(j++)+(++j);//12
printf("%d %d\n",m,j);
j=5;
m=(j++)+(++j)+(j++);//18
printf("%d %d\n",m,j);
j=5;
m=(j++)+(++j)+(j++)+(++j);//25
printf("%d %d\n",m,j);
j=5;
m=(j++)+(++j)+(j++)+(++j)+(++j);//33
printf("%d %d\n",m,j);
j=5;
m=(++j)+(j++)+(++j);//19
printf("%d %d\n",m,j);
}
WIN TC
#include<stdio.h>
void main()
{int m,j=5;
j=5;
m=(++j)+(++j); /*14*/
printf("%d %d\n",m,j);
j=5;
m=(j++)+(j++); /*10*/
printf("%d %d\n",m,j);
j=5;
m=(j++)+(++j)+(++j); /*21*/
printf("%d %d\n",m,j);
j=5;
m=(j++)+(++j)+(j++)+(++j); /*28*/
printf("%d %d\n",m,j);
j=5;
m=(j++)+(++j)+(j++)+(++j)+(j++);/*35*/
printf("%d %d\n",m,j);
j=5;
m=(++j)+(j++)+(++j)+(++j); /*32*/
printf("%d %d\n",m,j);
j=5;
j=5;
m=(j); /*5*/
printf("%d %d\n",m,j);
j=5;
m=(j++)+(++j); /*12*/
printf("%d %d\n",m,j);
j=5;
m=(j++)+(++j)+(j++); /*18*/
printf("%d %d\n",m,j);
j=5;
m=(j++)+(++j)+(j++)+(++j); /*28*/
printf("%d %d\n",m,j);
j=5;
m=(j++)+(++j)+(j++)+(++j)+(++j);/*40*/
printf("%d %d\n",m,j);
j=5;
m=(++j)+(j++)+(++j); /*21*/
printf("%d %d\n",m,j);
getch();