#include "stdafx.h"
#include
#include
#include
using namespace std;
int main(int argc, _TCHAR* argv[])
{
int i = 5;
int j = 5;
int p = (i++)+(i++)+(i++);//理解为先3个i相加为15,所以p=15;然后i的值自增3次等于8
cout<
cout<
int q = (++j)+(++j)+(++j);//理解为j的值先自增3次等于8,然后3个j值相加,所以q的值为24
cout<
cout<
int x = 20 , y = 35;
x = y++ + x++;//理解为先x+y赋值给x,x=x+y=55,然后x和y都自增1,x=56,y=36
y = ++y + ++x;//理解为x和y先自增1,x=57,y=37,然后x和y相加y=y+x=94
cout<
}
摘要: 从自增自减运算符的概念出发, 分析了C++与 C 语言中自增自减运算符在循环结构和指针运算中的应用方法,详细归纳了 + + / - - 运算符在解题过程中应注意的多个方面的事项 , 并分析C++与C在处理自增自减运算构成的复杂算术表达式的区别。是对教材的一个非常有益的补充 ,可用于语言教学的参考 ,也有助于初学者的自学。
关键词:C,C++,自增运算符,自减运算符
一、自增自减运算符的概念
C 语言程序设计 过 程中 , 我 们 经 常 用 到 x=x+1 ,x=x-1这 样 的赋值表达式, 用更简洁的方式表示x=x+1 可表示为: x + + 或 + + x,x=x- 1 可表示为: x - - 或 - - x,“++” - - ”称为自增、自减运算符。它们是单目运算符, 只能应用于变量, 而不能用于常量或表达式。结合性与简单赋值运算符相同,但优先级高于任何双目运算符。
自增自减运算符有两种使用形式: 前缀形式, 即它们在操作数前,如 ++x、 - x; 后缀形式, 即它们在操作数后, 如 x++、- 。++-x-表达式与 - - 表达式独立使用时,前缀形式与后缀形式无区别, 但它们在表达式中被引用时, 结果是不同的。前缀形式是先增 减)(1, 后被引用; 后缀形式是先被引用, 后增 减) 1。例如, 如果变量 x的原值等于 3, 则执行下面的赋值语句:
①y=++x; ( x 的值先变成 4, 再将 x 的值赋给 y, y 的值为 4)
②y=x++; ( 先 将 x 的 值 3 赋 给 y, y 的 值 为 3, 然 后 x 的 值 变为 4)
二、学习和应用这两个运算符应注意以下几点 :
1 注意表达式的值和变量值的区别
以自增运算符为例 ,当自增运算符 + + 作用于一个变量时 ,例如 :当 i = 3 时 + + i 这个算术表达式的值为 4 ,同时变量 i 的值也由原来的 3 改变为 4 。一般情况下 ,计算表达式后不改变之量的值 ,而 + + 运算符和运算符组成的表达式计算后 ,则改变之量的值 ,这称为运算符的副作用 ,这种运算符在计算表达式时 ,一定要注意区分表达式的值和变量的值。
2 注意前缀运算和后缀运算的区别
仍以自增运算符为例 ,该运算符可作用在变量之前 ,例如 ,前面所讲的 + + i ,称为前缀运算 ;也可作用在变量之后 ,例如 ,i + + 称为后缀运算 ,在这两种运算中 ,表达式的值不同 ;前缀运算后 ,表达式的值为原变量的值加 I ;后缀运算后 ,表达式的值仍为原变量值 ;而变量不论前缀运算还是后缀运算都加 1 。自减运算符与自增运算符类似 ,即前缀运算是“先变后用”,而后缀运算是“先用后变”。
3 注意运算符的运算对象
自增、自减运算符能作用于变量 , 而不能作用于常量或表达式。因为自增、自减运算符具有对运算量重新赋值的功能 , 而常量、表达式无存储单元可言。当然不能做自增、自减运算 , 只要是标准类型的变更 , 不管是整型、实型 , 还是字符型、枚举型都可以作为这两个运算符的运算对象。如 i + + +j + + 、+ + i + ( + + j ) 、 + + a + b ++ 、+ + array [ - j ] 合法 ; 而 + + 5、 ( i + j ) + + 、’A’+ + 、+ + i + + +j 都是不合法的。为什么 i + + +j + +合法 , 而 + + i + + +j 却不合法呢 ? 这是因为 C 语言的编译器对程序编译时 , 从左到右尽可能多地将字符组成一个运算符或标识符 , 因此 i + + +j + + 等效于 (i + + ) + (j+ + ) , 两个 “+ + ”作用的对象都是变量 , 这是合法的 ;而 + + i + + +j 等效于 + + ( i + + ) + j , 第 1 个 “ + + ”作用的对象是表达式 “i + + ” 这是不允许的。,
4、 注意运算符的结合方向
表达式 k = - i + +等效于 k = ( - i) + + 不是 K = - ( i+ + ) ? 因为负号运算符和自增运算符的优先级相同 ,哪一个正确就得看结合方向。自增、自减运算符的结合方向都是从右向左 ,因此 ,上式等效于 k = - ( i + + ) 若 i = 4 则表达式 k = - i + +运算后 k 的值为 - 4 ,i 为 5 。
5 注意运算符的副作用
C 语言允许在一个表达式中使用一个以上的赋值类运算 ,包括赋值运算符 、自增运算符、自减运算符等 ,这种灵活性使程序简洁 ,但同时也会引起副作用 。这种副作用主要表现在 :使程序费解 ,并易于发生误解或错误 。例如 ,当 i =3 时 ,表达式 (i + + ) + ( i + + ) + ( i + + ) 的值为多少 ,各种教材说法不统一 :有的认为是 9 ;也有人认为是 12 。到底哪一种说法正确呢 ? 请看下面这个程序的运行情况 :
main ()
{
int i , j ;
i = 3 ,j = (i + + ) + (i + + ) ;
printf ( \ nj = %d” ) ;“,j
i=3
printf ( j = %d” (i + + ) + i ( + + ) + (i + + ) ) ;“,
}
以上运行 ,其结果则是 :j = 9 ,j = 12 ,究其原因“先用后变 ,先变后用” “先” “后”中的和是一个模糊的概念 ,很难给出顺序或时间上的准确定论 “先”,到什么时候 “后”,到什么程度 ,没有此方面的详细资料可查询 。克服这类副作用的方法是 ,尽量把程序写得易懂一些 ,将费解处分解成若干个语句 ,如 : k = i + + +j ,可写成 k = i+ j ,i + +而类似 (i + + ) + i ( + + ) + (i + + ) 这类连续自增、自减的运算最好不要使用 ,以减少程序出错的可能性 。在程序设计中 ,效率和易读性是一对主要矛盾 。
三、在实例应用中的分析
在赋值语句中的应用
在使用自增自减运算时常会出现一些人们想不到的副作用,在不同的例子中应用有所不同,下面我们就结合不同的例子对其加以分析。
例:main()
{ int a=-1,b=1,k;
If((++a)<0)&&(--b<=0))
printf(“%d,%d\n”,b,a);
else printf(“%d,%d\n”,b,a);
}
运行结果为:1,0
++,--运算符出现在条件表达式中,对于条件表达式(++a<0)&&!(b--<=0)进行运算,因为a=a+1=-1+1=0,所以(++a<0)为假,而且C语言规定:在一个“&&”表达式中,若“&&”的一端为0,则不必再计算另一端,该表达式的值为0,所以此时不再执行语句—b,即b的值为1.
例:有以下程序段
J=-i++;printf(“%d,%d\n”,I,j);
运行结果为:3,-2
在C语言中,“++,--”运算符与“-”的优先级相同,结合方向从右至左,所以表达式-i++ 相当于-(i++),计算顺序是先计算表达式i++,表达式取i的为2,然后变量i增1;2再做取负值运算,表达式-i++的值为-2;再将-2赋给变量j。
自增自减运算符在循环结构中的应用
为了充分发挥计算机在程序控制下进行自动计算的功能和运算速度快的特点, 在程序设计过程中力求把复杂问题的求解转化为简单过程的重复。为此,在多数计算机程序设计语言中, 都提供有循环结构。C++与C 语 言 提 供 有 3 种循环结构 : for 结 构 、while 结 构 和 do…while 结构。
在 while 结构和 do… while 结构中, 其循环 体 中 应 有 使 循 环趋向于结束的语句。而这样的语句一般用赋值语句。
例如:用表达式“i++” “i- - ”或。其中 i 称 为 循环 变 量 , 在 循 环 结 构 中 只 有 改 变循环变量的值, 这样在循环体执行若干次之后, 才能使循环条件不满足, 结束循环。如果无此语句, 则 i 的值始终不 变 , 程 序 陷入死循环。
在 for 结构中, for 语句最简单的应用形式也可 理 解 为 如 下 形式:(for 循环变量赋初值; 循环条件; 循环变量增值)语句其中循环变量增值语句一般应用包含自增自减)运算符的表达式来实现。使用原理同 while 结构和 do… while 结构。
例如: for (i=1; i<=100; i++) sum+=i;该语句能完成 1+2+3+……+100 的功能。(当然在循环结构中使用自增 自减) 运算符 ,只有在长增或1的情况下使用,在其它情况下,还应使用赋值表达式来完成改变循环变量值的功能。
自增自减运算符在指针中的应用
在 C 程序 中 , 定 义 一个 变 量 , 就 意 味 着 在 计 算 机 内 存中 给 这个变量分配一定的存储空间。使用 Turbo C 系统时计算机内存为整型变量分配 1 个字节, 对单精度型变量分配 4 个字节, 为双精度变量分配 8 上字节, 为字符型变量分配 1 个字节。内存区的每一个存储单元 1 字节) 都有一个固定的编号, 这 个 编 号 就 称 为 地(址。如图 1 所示, 假设定义变量 p 和 a, 则在内存中分别为两个变量分配存储单元,其存储单元的首地址分别是 3420 和 2000。为了方便对存储单元进行控制, 我们可以设置某些变量专门存放指针, 这样的变量称 为 指 针 变 量 。 图 1 中 的 变 量 p 存 放 了变 量 a 的 地 址 2000, 因此, p 就是指向 a 的指针变量。
在 C 语言 中 , 指针使用非常灵活 , 指 针 既 可 指 向 各 种 类 型 的函数和文件。指针指向一定的数据对象时 ,变量, 也可指向数组、即可下移指向下一对象, 又可上移指向上一对象, 这就用到自增自减运算符来实 现 。 在 C语言中 , 指针变量引用时 ,同样要先定义, 后使用。如果定义指针变量 p 指向一定的数据类型, 则 p++ 指向内存中下一个元素 ( 而不是将值简单加 1) ,p- - 指向内 存 中 上一个元素 而不是将值简单减 1) 。 ( p-- ) 所代表的地址实际上(p++是 p+ 1×d (p- 1×d), d 是一个数据对象所占的 字 节 数 , 在C++与C 中, 对整数 d=2, 对单精度实数 d=4, 对字符型数 d=1。
下面来看一个程序段:int a[6]={1,2,3,4,5,6},*p;p=a;
“%d”printf(,*p++);
“%d”printf(,(*p)++);
此程序段中 , 定义了一 个整型数组a, 包含有6个数组元素,并且该数组已初始化。同时定义指针变量 p, 将 a 数组的起始地址赋予指针变量 p, 也可认为指 针 p 指 向 a 数 组 。第一次调用 printf 函 数 输 出 *p++ 表 达 式 的 值 , 在 此 表 达 式 中 , *和 ++ 运算符的优先级相同,结合性为自右向左, 即可表示为 *(p++), 括号内为自增运算符的后缀形式, 即先引用 p, 然后 p 自身即先求 *p 的值, 然后求 p+1。第一次输出结果为 p 所指向的加 1。存储单元 a[0]的值 1, 然 后 指 针 变 量 p 指 向 下 一 个 数 组 元 素 a[1]。第二次调用 printf 函数输出表达式(*p)++ 的值, 在此表达式中, 括号的优先级高, 首先计算 *p 的值, 然后将 *p 表达式的值加 1。第二 次 输 出 结 果 为 p 所 指 向 的 存 储 单 元 a[1]的 值 再 加 1, 即 结 果为
在程序设计中 ,经常遇到 = i + 1” “i = i - 1”“i和这两种极为常用的操作 ,变量 i 被称为“计数器”,用来记录完成某一操作的次数。C 语言为这种计数器操作提供了两个更为简洁的运算符 ,即 + + 和 - - ,分别叫做自增运算符和自减运算符 ,它们是从右向左结合的一元算术运算符 ,优先级为2 。
四、在C和C++语言中,操作符存在着优先级与结合性,通过操作符的连接,可以构造出据用不同复杂程度的表达式。一当表达式中有多个操作符时,优先级高的操作符先执行。二 操作符的结合性分为由左向右或由右向左两种,一元操作符,赋值及复合赋值操作符具有从右向左的结合性,其余操作符具有从左向右的结合性。若表达式中相邻的两个操作符优先级相同,先执行哪个操作符,即与前一个操作符的结合性有关。三在处理含有前增1,前减1操作符的算术表达式时,前增1的过程在C++与C例处理方法略有不同,C是一开始进行的,而C++是分布进行的。
综上所述,当“++”,“--”运算符所在的表达式或语句中只含右一种操作时(如++n;或n++;仅含有加1一种操作),则其前缀和后缀功能对程序的作用时一样的;而当含有两个或两个以上操作时,在考虑各个运算符的优先级别和结合性的基础上,则其前缀和后缀的功能对程序的作用时不一样的。为了提高程序的效率 ,需要用技巧把程序写得尽可能简洁一些 ,但这样有可能降低和谐的可能性和可理解性。可读性差的程序容易隐藏错误且难于纠正 ,不易维护 ,降低了程序的可靠性。人们在程序设计时遵守的基本规范是 :可靠性第一 ,效率第二。为了保证可靠性 ,程序必须清晰易读 ,而表达式的清晰易读是十分重要的 ,因此 ,在 C++与C 程序设计中 ,要慎重