浅析C语言中的自增自减运算

来源 :计算机光盘软件与应用 | 被引量 : 0次 | 上传用户:kellyfly
下载到本地 , 更方便阅读
声明 : 本文档内容版权归属内容提供方 , 如果您对本文有版权争议 , 可与客服联系进行内容授权或下架
论文部分内容阅读
  摘 要:C语言应用中,自增自减运算符运用灵活、广泛且具有一定的使用技巧和难度,在编程过程中,往往是初学者最难理解和最容易出错的运算符。本文根据自增自减运算符的特点和两种使用形式,剖析自增自减运算符的功能和在不同编译环境下的运算规则,以便更好地为初学者学习和使用提供帮助。
  关键词:C语言;自增运算符;运算规则;自减运算符
  中图分类号:TP312.1
  C语言中自增自减运算符使用过于灵活多变、不易掌握,在编程时会出现一些令人意料不到的结果。于是对C语言初学者而言正确而又灵活地掌握好自增自减运算符的应用,是非常必要的。
  1 自增自减运算符的运算规则
  1.1 功能
  自增运算符即“++”,其功能使变量的值自增1。
  自减运算符即“--”,其功能使变量的值自减1。
  1.2 运算对象
  自增自减运算符都是单目运算符,只能对单个变量进行操作,而不能操作常量或表达式。自增自减运算符实质是在原来变量的基础上自增(减)1,最后的值还要重新赋给原变量。由于常量和表达式自身没有存储单元,自增(减)后的值无法保存,故都不能做自增自减运算。如:3++、(m+n)--等都是非法的。
  1.3 使用形式
  使用形式分为前缀形式和后缀形式两种。
  前缀形式:运算符在变量前,例如:++i,--i(在使用i之前,先使i的值加(减)1)。
  后缀形式:运算符在变量后,例如:i++,i--(在使用i之后,使i的值加(减)1)。
  在这两种形式运算中,表达式的值不同:前缀形式运算后,表达式的值为运算变量值加(减)1。
  例如:
  int m,n=1;
  m=++n;(先把变量n的值加1使n=2,再把n的值赋给变量m,m=2,++n表达式的值为2)
  printf(“%d,%d”,n,m);输出结果为:2,2。
  后缀形式运算后,表达式的值仍为运算变量原值。
  例如:
  int m,n=1;
  m=n++;(先把变量n的值赋给变量m,m=1,再把变量n加1使n=2,n++表达式的值为1)
  printf(“%d,%d”,n,m);输出结果为:2,1。
  1.4 优先级与结合性
  属于单目运算符的自增自减运算符优先级为2级,运算时结合性为“自右至左”。
  例如:若要计算j=-i++;的值,则必须先计算出-i++表达式的值然后赋给变量j。那么在运算-i++表达式时,由于自增运算符“++”和负号运算符“-”的类型、优先级和结合方向都相同,所以按照C语言的规定,优先级相同的运算先后次序由结合方向来决定,故表达式执行-(i++)操作。若变量i=1,则运算时先用i的原值1加上负号赋给变量j,j=-1,然后i增值为2,最终结果为:j=-1,i=2。
  1.5 自增自减运算符连续多次出现在一个表达式中
  C语言的表达式中允许使用一个以上的赋值运算符、自增运算符和自减运算符。这种灵活性使程序简洁,但同时可读性变差且易于发生错误,而且不同的编译系统对这样的程序运行所得结果也各不相同,以下主要以Turbo C和Visual C++ 6.0编译环境为例进行分析。
  例如:
  main()
  {int i,p;
  i=3;p=(i++)+(i++)+(i++);printf(“p=%d,i=%d\n”,p,i);
  i=3;p=(++i)+(++i)+(++i);printf(“p=%d,i=%d\n”,p,i);
  }
  分析:在Turbo C和Visual C++ 6.0两种编译环境中表达式p=(i++)+(i++)+(i++)中的自增运算作为后缀式,其运算优先级低于求和运算。故先使用自增运算符中变量i的值参与求和运算,即p=3+3+3=9,然后再对变量i进行3次自增运算,即i++;i++;i++;最后i的值为6。
  在Visual C++ 6.0环境下,表达式p=(++i)+(++i)+(++i)中的自增运算作为前缀式,其运算优先级高于求和运算。故先按照“自右至左”的结合性进行两次自增运算即i++;i++;,i的值变为5,获得满足第一个求和运算符两侧的操作数要求进行5+5求和运算,然后将和值(10)与变量i的第三次自增值(i=6)进行第二次求和运算(10+6)即p=((++i)+(++i))+(++i)=(5+5)+6=16,最后i的值为6。
  在Turbo C环境下,虽然表达式p=(++i)+(++i)+(++i)中自增运算也作为前缀式,但是其运算优先级高于全部求和运算,故按照“自右至左”的结合性先进行3次自增运算,即i++;i++;i++;,之后i的值变为6,最后再进行加法运算,即p=6+6+6=18。
  2 自增自减运算符的应用
  2.1 在关系表达式中的应用
  當自增自减运算符用于关系表达式,如果为前缀形式时,需要运算变量先加(减)1,然后才能进行比较;如果为后缀形式时,则需要运算变量的表达式先参与比较,然后运算变量才加(减)1。
  例如:
  int x,m=10,n=5;
  x=(--m==n++)?--m:++n;
  语句执行之后,x,m,n的值分别为:7,9,7。
  语句x=(--m==n++)?--m:++n;在运算时是把条件表达式(--m==n++)?--m:++n的值赋给变量x,而要计算条件表达式(--m==n++)?--m:++n的值,应先判断条件表达式中--m==n++真假,而--m==n++是带有自增自减运算符的关系表达式,自增自减运算符的优先级高于关系运算符,因此计算--m==n++的值其实是求--m的值(变量m自减1(m=9)后的值)与n++的值(变量n的原值5)进行是否相等的比较(9==5的比较),之后n加1(n=6),最后比较结果为假值,将条件表达式(--m==n++)?--m:++n中的最后一个表达式++n的值(n自加1(6+1)为7)赋给x,x值为7。   2.2 自增自减运算符在逻辑表达式中的应用
  当自增自减运算符在逻辑表达式中应用时,先根据逻辑运算符特点确定它们的优先级关系之后再运算。如果为前缀形式时,需要运算变量先加(减)1,然后才能进行逻辑值判断;如果为后缀形式时,则需要运算变量的表达式先参与逻辑值判断,然后运算变量才加(减)1。
  例如:
  int a=1,b=2,c=3,d;
  d=++a||++b&&--c;
  语句执行之后,a,b,c,d的值分别为:2,2,3,1。
  程序运行时要得到变量d的值就要对表达式++a||++b&&--c先进行运算,而按照运算原则,自增自减运算符的优先级高于逻辑运算符,那么就要先对表达式中的++a、++b和--c进行结果计算,最后再进行||、&&的运算。但在Turbo C和Visual C++ 6.0环境中运行时实际只有++a参与了运算,而++b和--c并没有被执行。这是因为在C语言中对于有多个||和&&参与组成的表达式在运算时有一个规定:在一个以上逻辑运算符组成的逻辑表达式中,如果通过前面子表达式的值就能够决定整个表达式的值,那么就没有必要再计算后面的子表达式了,即短路特性。在++a||++b&&--c表达式中,++a的值为2,它与后面的子表达式++b&&--c进行||运算,它自身值为2结果为真已经能够决定整个表达式的值,后面--b,++c就不会被执行了,变量b和c的值也不会发生改变。所以自增自减运算符用于逻辑表达式中时,它们的优先级关系受到逻辑运算符特点的制约。
  2.3 自增自减运算符在if语句中的应用
  自增自减运算符用于if表达式,如果为前缀形式时,需要运算变量先加(减)1,然后才进行条件判断;如果为后缀形式时,则需要运算变量的表达式先参与条件判断,然后运算变量才加(减)1。
  例如:
  main()
  {
  int m=5;
  if(m++>5)
  printf(“%d\n”,m++);
  else
  printf(“%d\n”,m--);
  }
  程序执行之后结果为:6。
  自增自减运算符出现在if(m++>5)条件表达式中,关系表达式m++>5先进行运算,因为自加运算符的优先级高于关系运算符,所以先计算m++表达式的值5,然后判断关系表达式(5>5)为假,同时变量m增1(m=6),程序执行printf(“%d\n”,m--);语句,输出m--表达式的值6,最后变量m减1(m=5)。
  2.4 自增自減运算符在printf()输出函数和函数实参中的应用
  在Turbo C和Visual C++ 6.0编译系统中规定函数参数的求值顺序是“从右至左”,而且各个参数可被看成表达式独立的参与运算过程。因此, 在满足运算优先级前提下,在printf()输出函数参数中出现自增自减运算符时,要对每一个表达式求解。
  例如:
  int i=3;printf(“%d,%d,%d\n”,++i,++i,++i);
  int i=3;printf(“%d,%d,%d\n”,i++,i++,i++);
  对例题printf(“%d,%d,%d\n”,++i,++i,++i);输出语句中自增运算符为前缀式,虽然在Turbo C和Visual C++ 6.0编译系统中规定函数参数的求值顺序是“从右至左”,而且各个参数可被看成表达式独立的参与运算过程,但是自增、自减运算优先级高于每一个表达式的求解。即在从右至左对每个表达式依次求解时,变量i的值先自增1,然后得到++i的值。最后再从左到右输出每个表达式++i的值:6,5,4。
  对于例题printf(“%d,%d,%d\n”,i++,i++,i++);输出语句中自增运算符为后缀式,虽然运算顺序和前缀式相同,但在Turbo C和Visual C++ 6.0不同编译环境中每一个表达式的求解优先级不同。即在Turbo C编译环境中在从右至左依次对每个表达式求解时,先得到i++的值,然后变量i的值才加1(即依次每运算一个i++表达式时,变量i自加一次),最后再从左到右输出每个表达式i++的值:5,4,3;而在Visual C++ 6.0编译环境中先参考运算优先级,然后再从右至左依次对每个表达式求解。即依次得到表达式i++的值,然后再从左到右输出每个表达式i++的值:3,3,3,最后变量i的值再累加3次。
  例如:
  int i=3;
  printf(“%d,%d\n”,(++i,i++),i);
  Turbo C中输出结果为:4,3。
  Visual C++ 6.0中输出结果为:4,4。
  函数实参进行值传递的顺序也是按照自右而左依次进行赋值的。如果在函数的实参中包含自增自减运算符,那么其求解方法和printf()输出函数中参数的自增自减运算的求解方法一样,实参和对应形参传递同样按照自右而左的顺序依次进行。
  例如:
  #include
  int add(int m,int n)
  { int sum;
  sum=m+n;
  return(sum);
  }
  main()
  { int i=2,s;
  s=add(i,i++);
  printf(“s=%d\n”,s);
  }
  Turbo C中执行结果为:s=5。
  Visual C++ 6.0中执行结果为:s=4。   2.5 自增自减运算符在循环语句中的应用
  C语言中提供了两类循环:第一类是条件循环由while语句和do-while语句实现;第二类是计数循环由for语句实现。在由while 结构、do…while结构和for(循环变量赋初值;循环条件;循环变量增值)语句构成的循环中,都有类似表达式“i++”或“i--”这样由变量和自增自减运算符构成的赋值语句充当使循环趋于结束的语句,目的是为了避免程序出现死循环。由于循环结构中使用的自增(减)运算符只能实现步长增1或减1的情况,如果不是此种情况,就应选择其他的赋值表达式来实现改变循环变量值的功能。
  2.6 自增自减运算符在指针中的应用
  在C程序中,由于数组是多个同类有序数据的集合,并且在使用时不能一次引用整个数组,而只能逐个地使用下标变量。这就直接影响存有大批量数据元素的数组的处理效率,大大降低程序的运行速率,所以在C语言中,选择灵活、高效的指针。因为通过指针变量直接访问数组元素时,不必每次都重新定位地址,只要通过指针变量自增自减运算就可以实现指针变量自动向前或向后移动,指向上一个或下一个数组元素。这种有规律地改变地址值能大大提高执行效率。但是在使用自增自减运算符时,特别要注意数组不得越界。
  例如:
  #include
  void main()
  { int *point;
  int n,array[10];
  point=array;
  for(n=0;n<=9;n++)
  scanf(“%d”,point++);
  printf(“\n”);
  for(n=0;n<=9;n++,point++)
  printf(“%d”,*point);
  printf(“\n”);
  }
  本例用指針变量point来指向数组array的元素,用point++使point的值不断改变从而指向不同的数组元素,指针变量point的初值为array数组首元素(即array[0])的地址,但经过第一个for循环为array数组10个元素读入数据后,point已指向array数组的末尾。因此,在执行第二个for循环时,point指针变量的起始值不是&array[0]了,而是array+10。由于执行第二个for循环时,每次都要执行point++,因此point指向的是array数组下面的10个元素,而这些存储单元已经超出了数组array[10]的定义范围,它们的值是不可预料的,由于C语言编译时不会对数组array[10]访问越界发出错误提示,程序运行时会得不到预期的结果,所以使用指针变量指向数组元素时,应切实保证指向有效的数组元素。除此之外还应该注意指针变量的自增自减运算的不同形式。例如有定义int *p,a[10];p=a;了解p++;*p++;*(p++);*(++p);与++(*p);的不同含义。
  自增自减运算符是C程序设计语言中常用的运算符,灵活运用可以编写出简洁、高效的程序代码,大大提高编程的效率。但对于初学者而言首要的任务是正确理解自增自减运算符的作用和意义以及它在不同语句中的运算规则,能够编写出清晰易读的程序,其次才是追求程序的简洁性和高效性。本文从常用的两种编辑器Turbo C和Visual C++ 6.0出发,结合自增自减运算符自身的特点,针对自增自减运算符在各种不同表达式中的功能及不同的编译环境下同一段代码的运行结果进行分析及规律的总结。
  参考文献:
  [1]谭浩强.C程序设计[M].3版.北京:清华大学出版社,2005.
  [2]曲万里.C程序设计教程[M].1版.北京:清华大学出版社,2009,1.
  [3]熊锡义.C语言程序设计案例教程[M].大连:大连理工大学出版社,2009,5.
  作者单位:运城职业技术学院电信系,山西运城 044000
其他文献
建筑施工现场防灭火技术主要包括现场防火、灭火及人员安全疏散等消防技术措施,施工现场防火工作的重点就是总平面布局和建筑防火。本文主要阐述了建筑工程施工现场的总平面布
对不确定度进行测量已经成为了一项重要的数据衡量指标,很多国家都认为,测量的结果如没有带不确定度的话,是没有任何实际意义的测量数据。现在大多数国家都存有自己的不确定
热激蛋白在植物干旱和正常生长发育过程中具有重要的调控作用,近年来,研究者利用水稻、大豆、玉米等不同类群植物分析了植物干旱胁迫应答蛋白,尤其是热激蛋白的表达调控策略