论文部分内容阅读
摘要:针对C语言运算符使用规则,分析了在DEV C 环境下自加/自减运算符的使用方法和在复杂表达式中的求值情况分析,并针对问题给出了解决方案。
关键词:C语言;自增运算符;自减运算符
中图分类号:TP311 文献标识码:A 文章编号:1009-3044(2016)27-0248-02
Abstract:For the C language operators use rules, analysis of the add-self /sub-self and evaluation in the analysis of complex expressions with DEV C , and the solutions were given.
Key words: C language;add-self;add-self
C语言是典型的结构化程序设计语言,在国内外得到了广泛的使用,也是各大学普遍开设的程序设计课程。在近年的教学过程中,大多借用C 的编辑环境编辑C程序,使用较多的有Visual C ,DEV C 等。在这些编辑环境下运行C程序,对于某些特定的操作,对不同的编译器可能会得到不同的运行结果。笔者发现,在C语言的运算符中,自加和自减运算符的使用非常灵活,是C语言的特色之一,但在使用过程中也比较容易出错。现就这两种运算符在DEV C 环境中的使用做一个详细的分析。
1 自加/自减运算符的使用方法及运算对象
自加自减运算符是C语言特有的单目运算符,只能和一个变量组成表达式,有前缀和后缀两种形式。前缀形式为: 操作数/- -操作数,后缀形式为操作数 /操作数- -。自加运算符可以使操作数的值增加1个单位,自减运算符可以使操作数的值减少1个单位。操作数只能是变量,不允许使用常量和表达式。比如i和j都是整型变量,使用i ,j 都是合法的,如果对常量3使用自加运算符即3 ,则会使常量3的值增加1,这和常量在程序运行期间值不发生改变的定义相违背;而对表达式(i 2)使用自加运算符(i 2) ,则会使表达式(i 2)的值增加1,但是减少以后的值没有变量可以存储,因此这两种使用方法都不合法。
2 自加/自减运算符单独使用与在复合表达式中使用的区别
2.1 自加/自减运算符单独使用
以自加运算为例,使用整型变量i作为操作数,在运算符单独使用的情况下,有i ;和 i;两种形式,不论是用前缀表示还是后缀表示,都可以使i的值增加1,当然也可以使用赋值语句i=i 1;实现。但是,对于多数C的编译程序,利用自加/自减运算使变量增加/减少1和使用赋值语句相比,生成代码的运行速度会快很多,目标代码的效率更高一些。因此从效率上分析,前两种形式的效率更高。
2.2 自加/自减运算符在复合表达式中使用
同样以自加运算为例,使用整型变量i作为操作数,分析运算符在复合表达式中的使用情况。
(1)i=3;y=i ;printf(“i=%d,y=%d”,i,j);
(2)i=3;y= i;printf(“i=%d,y=%d”,i,j);
在第一个程序段中,运行结果为i=4,y=3。说明在y=i 语句中,i先将增加前的值赋给y,在当前表达式计算完成之后才自己增加1,所以输出结果时,i的值是4,而y的值为3。
在第二个程序段中,运行结果为i=4,y=4。在y= i语句中,i的值先增加1,再把增加后的值参与本表达式的运算,赋给y,所以i,y的值都为4。
通过以上两个程序段的分析,我们发现,当使用后缀表示时,变量i会先将自己的值赋给y,再对自己加1,而使用前缀表示时,变量i先自己增加1,再将增加后的值赋给y。可以将这两种情况总结为“变量在前就先使用,变量在后就先加”。
3 自加/自减运算符的优先级和结合方向
C语言规定,在表达式求值时,先看运算符的优先级,优先级高的先运算,对于同一优先级的运算符,则按照结合方向确定运算次序。自加/自减运算符是单目运算符,优先级仅次于括号等运算符,结合方向为自右向左。也就是说在出现多个同等级的运算符时,需要按照自右向左的方向运算。
比如表达式y=-i ,按照优先级分析,-和 运算符的优先级相同,赋值运算符优先级最低,因此先进行-和 运算,又因为他们的结合方向都是自右向左,因此变量i应该先进行自加运算再进行负号运算。这样该表达式就等价于y=-(i ),如果i的初值为3,则y的值就为-3。注意,这里使用的是后缀表示,所以应该先使用i的值再自加,所以y的值不是-4。
在另外一个表达式y=i j中,如果i的初值为3,j的初值为2,该表达式是按照y=(i ) j计算,还是按照y=i ( j)计算呢?如果单纯从优先级和结合方向考虑,自加运算符的优先级会高于加法运算符,应该先进行自加运算,但是自加的对象就没办法确定了。实际上,DEV C 编译器会从左向右依次扫描表达式,尽可能多地把多个符号组合成一个运算符,因此在扫描三个加号时,会从左到右把前两个加号看做自加运算符,因此该表達式按照y=(i ) j计算,由于自加运算符是后缀形式,所以先取i的值计算再自加,最后计算结果为i=4,j=2,y=5。
4 在一个表达式中出现多个自加/自减运算符的复杂情况
如果在一个表达式中出现了多个自加/自减运算符,则表达式的计算就会变得很复杂,还有可能出现计算结果和编译器相关的情况。本文中的程序段,均在DEV C 编译环境下运行。比如设变量初值为:int i=3;则有如下程序段:
(1) k=( i) i i; printf(“i=%d,k=%d”,i,k); (2) k= i ( i) i; printf(“i=%d,k=%d”,i,k);
(3) k=( i) i ( i); printf(“i=%d,k=%d”,i,k);
(4) k=( i) ( i) ( i); printf(“i=%d,k=%d”,i,k);
在第一个程序段中,由于DEV C 编译器会从左到右扫描表达式,并且合并尽可能多的字符作为一个运算符,所以可以将表达式看做如下形式:k=(( i) ) (i ) i。首先进行 i操作,则得到i的值为4,同时增加后的4值参与本表达式的运算,再进行后缀的自加运算,则得到增加后的值为5,但是因为是后缀形式,所以参与运算的依然是增加前的4,在后面的i 中,依然是使用增加前的值4参与运算,但此时i的值已经增加到了6,表达式中最后一个i的值,因為本表达式还没有计算完成,因此依然取增加前的4值,所以最后k的值应该等于12,而i的值为6。
在第二个程序段中,依照上面的原则,可以将表达式看做如下形式:k= i (( i) ) i首先进行第一个 i操作,得到i的值为4,再进行第二个 i操作,得到i的值为5,继续进行后缀的自加操作,在本表达式中参与运算的值就是5,在表达式计算结束以后,i的值才修改为6。在进行两个结果相加的时候,第一个i的值已经被后面的i修改为5 ,所以得到两个加数的和为10,最后一个i的取值也是前面得到的5。因此,本表达式的计算结果为k=15,i=6。
在第三个程序段中,表达式可以看作为k=(( i) ) i ( i)。首先计算( i),并且用自加后的4参与后缀的自加运算,所以在表达式计算结束时才自加,这样就得到了两个4相加的结果8,最后计算( i),由于上一个后缀的自加运算,加1的结果要在表达式计算结束后才进行,所以这里的i值还是4,用4作为前缀自加的值,则( i)的结果就为5,用前面的中间结果8和5相加,就得到了k=13的结果,而在表达式计算结束以后,进行了最后一次自加操作,i的值变成6。
在第四个表达式中,参照第二个表达式的计算过程,先进行两个,得到两个5相加,再进行第三个( i)操作,此时i的值变为6,参与本表达式运算的值也为6,所以最后的计算结果为k=16,i=6。
从以上四个表达式的计算过程可以发现,在于DEV C 环境下,一个表达式中出现多个自加/自减运算符的时候,同一个表达式,由于括号的位置不同,或者操作数的位置不同,会引起计算结果的变化。
C语言允许用户在一条语句使用含多个赋值和自增/自减运算符,这很大程度上给设计者提供了自由度,但是会给程序的通用性和易读性带来影响。在本文中,以DEV C 作为运行环境,编译器是从左至右扫描表达式的,但是在其他编译器中可能会出现从右至左扫描的情况,那么同一个程序的运行结果就不同了。在这种情况下,我们应该尽可能避免此类情况的出现,在一条语句中至多使用一个自增/自减运算符,并且使用括号将它们和其他运算符分隔,以免使得表达式引起歧义或者由于编译器不同而导致计算结果不同的情况。
参考文献:
[1] 谭浩强.C程序设计(第四版)[M].北京:清华大学出版社,2010.
[2] 苏小红.C语言大学实用教程[M].北京:电子工业出版社,2007.
[3] 朱鸣华.C语言程序设计教程(第三版)[M].北京:机械工业出版社,2014.
[4] 张长海.程序设计基础(第2版).北京:高等教育出版社,2013.
关键词:C语言;自增运算符;自减运算符
中图分类号:TP311 文献标识码:A 文章编号:1009-3044(2016)27-0248-02
Abstract:For the C language operators use rules, analysis of the add-self /sub-self and evaluation in the analysis of complex expressions with DEV C , and the solutions were given.
Key words: C language;add-self;add-self
C语言是典型的结构化程序设计语言,在国内外得到了广泛的使用,也是各大学普遍开设的程序设计课程。在近年的教学过程中,大多借用C 的编辑环境编辑C程序,使用较多的有Visual C ,DEV C 等。在这些编辑环境下运行C程序,对于某些特定的操作,对不同的编译器可能会得到不同的运行结果。笔者发现,在C语言的运算符中,自加和自减运算符的使用非常灵活,是C语言的特色之一,但在使用过程中也比较容易出错。现就这两种运算符在DEV C 环境中的使用做一个详细的分析。
1 自加/自减运算符的使用方法及运算对象
自加自减运算符是C语言特有的单目运算符,只能和一个变量组成表达式,有前缀和后缀两种形式。前缀形式为: 操作数/- -操作数,后缀形式为操作数 /操作数- -。自加运算符可以使操作数的值增加1个单位,自减运算符可以使操作数的值减少1个单位。操作数只能是变量,不允许使用常量和表达式。比如i和j都是整型变量,使用i ,j 都是合法的,如果对常量3使用自加运算符即3 ,则会使常量3的值增加1,这和常量在程序运行期间值不发生改变的定义相违背;而对表达式(i 2)使用自加运算符(i 2) ,则会使表达式(i 2)的值增加1,但是减少以后的值没有变量可以存储,因此这两种使用方法都不合法。
2 自加/自减运算符单独使用与在复合表达式中使用的区别
2.1 自加/自减运算符单独使用
以自加运算为例,使用整型变量i作为操作数,在运算符单独使用的情况下,有i ;和 i;两种形式,不论是用前缀表示还是后缀表示,都可以使i的值增加1,当然也可以使用赋值语句i=i 1;实现。但是,对于多数C的编译程序,利用自加/自减运算使变量增加/减少1和使用赋值语句相比,生成代码的运行速度会快很多,目标代码的效率更高一些。因此从效率上分析,前两种形式的效率更高。
2.2 自加/自减运算符在复合表达式中使用
同样以自加运算为例,使用整型变量i作为操作数,分析运算符在复合表达式中的使用情况。
(1)i=3;y=i ;printf(“i=%d,y=%d”,i,j);
(2)i=3;y= i;printf(“i=%d,y=%d”,i,j);
在第一个程序段中,运行结果为i=4,y=3。说明在y=i 语句中,i先将增加前的值赋给y,在当前表达式计算完成之后才自己增加1,所以输出结果时,i的值是4,而y的值为3。
在第二个程序段中,运行结果为i=4,y=4。在y= i语句中,i的值先增加1,再把增加后的值参与本表达式的运算,赋给y,所以i,y的值都为4。
通过以上两个程序段的分析,我们发现,当使用后缀表示时,变量i会先将自己的值赋给y,再对自己加1,而使用前缀表示时,变量i先自己增加1,再将增加后的值赋给y。可以将这两种情况总结为“变量在前就先使用,变量在后就先加”。
3 自加/自减运算符的优先级和结合方向
C语言规定,在表达式求值时,先看运算符的优先级,优先级高的先运算,对于同一优先级的运算符,则按照结合方向确定运算次序。自加/自减运算符是单目运算符,优先级仅次于括号等运算符,结合方向为自右向左。也就是说在出现多个同等级的运算符时,需要按照自右向左的方向运算。
比如表达式y=-i ,按照优先级分析,-和 运算符的优先级相同,赋值运算符优先级最低,因此先进行-和 运算,又因为他们的结合方向都是自右向左,因此变量i应该先进行自加运算再进行负号运算。这样该表达式就等价于y=-(i ),如果i的初值为3,则y的值就为-3。注意,这里使用的是后缀表示,所以应该先使用i的值再自加,所以y的值不是-4。
在另外一个表达式y=i j中,如果i的初值为3,j的初值为2,该表达式是按照y=(i ) j计算,还是按照y=i ( j)计算呢?如果单纯从优先级和结合方向考虑,自加运算符的优先级会高于加法运算符,应该先进行自加运算,但是自加的对象就没办法确定了。实际上,DEV C 编译器会从左向右依次扫描表达式,尽可能多地把多个符号组合成一个运算符,因此在扫描三个加号时,会从左到右把前两个加号看做自加运算符,因此该表達式按照y=(i ) j计算,由于自加运算符是后缀形式,所以先取i的值计算再自加,最后计算结果为i=4,j=2,y=5。
4 在一个表达式中出现多个自加/自减运算符的复杂情况
如果在一个表达式中出现了多个自加/自减运算符,则表达式的计算就会变得很复杂,还有可能出现计算结果和编译器相关的情况。本文中的程序段,均在DEV C 编译环境下运行。比如设变量初值为:int i=3;则有如下程序段:
(1) k=( i) i i; printf(“i=%d,k=%d”,i,k); (2) k= i ( i) i; printf(“i=%d,k=%d”,i,k);
(3) k=( i) i ( i); printf(“i=%d,k=%d”,i,k);
(4) k=( i) ( i) ( i); printf(“i=%d,k=%d”,i,k);
在第一个程序段中,由于DEV C 编译器会从左到右扫描表达式,并且合并尽可能多的字符作为一个运算符,所以可以将表达式看做如下形式:k=(( i) ) (i ) i。首先进行 i操作,则得到i的值为4,同时增加后的4值参与本表达式的运算,再进行后缀的自加运算,则得到增加后的值为5,但是因为是后缀形式,所以参与运算的依然是增加前的4,在后面的i 中,依然是使用增加前的值4参与运算,但此时i的值已经增加到了6,表达式中最后一个i的值,因為本表达式还没有计算完成,因此依然取增加前的4值,所以最后k的值应该等于12,而i的值为6。
在第二个程序段中,依照上面的原则,可以将表达式看做如下形式:k= i (( i) ) i首先进行第一个 i操作,得到i的值为4,再进行第二个 i操作,得到i的值为5,继续进行后缀的自加操作,在本表达式中参与运算的值就是5,在表达式计算结束以后,i的值才修改为6。在进行两个结果相加的时候,第一个i的值已经被后面的i修改为5 ,所以得到两个加数的和为10,最后一个i的取值也是前面得到的5。因此,本表达式的计算结果为k=15,i=6。
在第三个程序段中,表达式可以看作为k=(( i) ) i ( i)。首先计算( i),并且用自加后的4参与后缀的自加运算,所以在表达式计算结束时才自加,这样就得到了两个4相加的结果8,最后计算( i),由于上一个后缀的自加运算,加1的结果要在表达式计算结束后才进行,所以这里的i值还是4,用4作为前缀自加的值,则( i)的结果就为5,用前面的中间结果8和5相加,就得到了k=13的结果,而在表达式计算结束以后,进行了最后一次自加操作,i的值变成6。
在第四个表达式中,参照第二个表达式的计算过程,先进行两个,得到两个5相加,再进行第三个( i)操作,此时i的值变为6,参与本表达式运算的值也为6,所以最后的计算结果为k=16,i=6。
从以上四个表达式的计算过程可以发现,在于DEV C 环境下,一个表达式中出现多个自加/自减运算符的时候,同一个表达式,由于括号的位置不同,或者操作数的位置不同,会引起计算结果的变化。
C语言允许用户在一条语句使用含多个赋值和自增/自减运算符,这很大程度上给设计者提供了自由度,但是会给程序的通用性和易读性带来影响。在本文中,以DEV C 作为运行环境,编译器是从左至右扫描表达式的,但是在其他编译器中可能会出现从右至左扫描的情况,那么同一个程序的运行结果就不同了。在这种情况下,我们应该尽可能避免此类情况的出现,在一条语句中至多使用一个自增/自减运算符,并且使用括号将它们和其他运算符分隔,以免使得表达式引起歧义或者由于编译器不同而导致计算结果不同的情况。
参考文献:
[1] 谭浩强.C程序设计(第四版)[M].北京:清华大学出版社,2010.
[2] 苏小红.C语言大学实用教程[M].北京:电子工业出版社,2007.
[3] 朱鸣华.C语言程序设计教程(第三版)[M].北京:机械工业出版社,2014.
[4] 张长海.程序设计基础(第2版).北京:高等教育出版社,2013.