c语中的自增自减1Word格式文档下载.docx

上传人:b****5 文档编号:20299421 上传时间:2023-01-21 格式:DOCX 页数:13 大小:358.23KB
下载 相关 举报
c语中的自增自减1Word格式文档下载.docx_第1页
第1页 / 共13页
c语中的自增自减1Word格式文档下载.docx_第2页
第2页 / 共13页
c语中的自增自减1Word格式文档下载.docx_第3页
第3页 / 共13页
c语中的自增自减1Word格式文档下载.docx_第4页
第4页 / 共13页
c语中的自增自减1Word格式文档下载.docx_第5页
第5页 / 共13页
点击查看更多>>
下载资源
资源描述

c语中的自增自减1Word格式文档下载.docx

《c语中的自增自减1Word格式文档下载.docx》由会员分享,可在线阅读,更多相关《c语中的自增自减1Word格式文档下载.docx(13页珍藏版)》请在冰豆网上搜索。

c语中的自增自减1Word格式文档下载.docx

只要是标准类型的变量,不管是整型、实型,还是字符型、枚举型都可以作为这两个运算符的运算对象。

如以下四个表达式都是合法的:

i+++j++、++i+(++j)、++a+b++、++array[--j];

而++6、(i+j)++、‘A’++、++i+++j、(&

p)++这五个表达式却是不合法的。

为什么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=5,则表达式k=-i++运算之后k的值为-5,i的值为6。

此赋值表达式的值即为所赋的值-5。

不要因为k=-i++等效于k=-(i++)就先做“++”运算!

这里采用的是“先用后变”,即先拿出i的值做负号“-”运算,把这个值赋给变量k之后变量i才自增。

5 注意运算符的副作用

  C语言允许在一个表达式中使用一个以上的赋值类运算,包括赋值运算符、自增运算符、自减运算符等。

这种灵活性使程序简洁,但同时也会引起副作用。

这种副作用主要表现在:

使程序费解,并易于发生误解或错误。

例如,当i=3时,表达式(i++)+(i++)+(i++)的值为多少,各种教材说法不统一:

有的认为是9(3+3+3,如谭浩强的《C程序设计》,清华大学出版社,1991);

也有的认为是12(3+4+5,如王森的《C语言程序设计》,电子工业出版社,1995)。

到底哪一个说法正确呢不妨看看下面这个程序的运行情况:

  main()

  {inti,j;

  i=3;

j=(i++)+(i++)+(i++);

printf(“\nj=%d,”j);

printf(“j=%d”,(i++)+(i++)+(i++));

  }

  在上运行,其结果则是:

j=9,j=12,究其原因,“先用后变,先变后用“中的“先”和“后”是一个模糊的概念,很难给出顺序或时间上的准确定论。

“先”到什么时候,“后”到什么程度没有此方面的详细资料可供查询。

  为此,笔者用各种表达式上机测试,结果发现当表达式的值作为printf函数的直接输出对象时,“先变后用”和“先用后变”中的“后”就是指++i和i++这一小项运算完之后,如上面程序中最后一个语句中的输出对象:

第一个(i++)取出i的值3以后i立即变为4,第二个(i++)取出i的值4以后i立即变为5,第三个(i++)取出i的值5以后i立即变为6,这样输出的结果便是3+4+5这个表达式的值,即12。

而在其它一些表达式或语句中,“变”或“用”的时机却很难掌握。

下列各式中变量j的值都是在i=3,k=1的前提下求出的:

  后缀运算:

  

(1)j=(5,6,(i++)+(i++)+(i++)):

j=9(3+3+3)

  

(2)j=(k++,6,(i++)+(i++)+(i++)):

  (3)j=1(i++)+(i++)+(i++):

0:

  (4)j=i(i++)+(i++)+(i++):

j=12(3+4+5)

  (5)j=k++(i++)+(i++)+(i++):

  前缀运算:

  (6)j=(5,i,(++i)+(++i)+(++i)):

j=18(6+6+6)

  (7)j=(5,k++,(++i)+(++i)+(++i)):

j=15(4+5+6)

  (8)j=1(++i)+(++i)+(++i):

  (9)j=1(k++,(+i)+(++i)+++i)):

  (10)j=k++(++i)+(++i)+(++i):

  其中(3)和(4)、(6)和(7)、(8)和(10)等这几对类型相同的表达式却得到完全不同的运算结果,令人费解!

由此可见,在一般表达式中,就i++来说,“先用后变”中何时“变”很难说得清楚;

对++i来说,“先变后用”中何时“用”也不易道白(自减运算符与此类似)。

因此,读者在使用这类运算符时一定要特别注意。

  克服这类副作用的方法是,尽量把程序写得易懂一些,即将费解处分解成若干个语句。

如:

k=i+++j:

可写成k=i+j:

i++:

而类似(i++)+(i++)+(i++)这类连续自增、自减的运算最好不要使用,以避免疑团的出现,同时也可减少程序出错的可性能。

  在程序设计中,效率和易读性是一对主要矛盾。

为了提高程序的效率,需要用技巧把程序写得尽可能简洁一些,但这样有可能降低程序的可读性和可理解性。

可读性差的程序容易隐藏错误且难于纠正,不易维护,降低了程序的可靠性。

鉴于“软件危机”的教训,人们在程序设计时遵守的基本规范是:

可靠性第一,效率第二。

为了保证可靠性,程序必须清晰易读,而表达式的清晰易读是十分重要的方面。

因此,在C程序设计中,要慎重使用自增、自减运算符,特别是在一个表达式中不要多处出现变量的自增、自减等运算。

 

安装教科书上说明:

“函数参数的求值顺序是自右向左”更是大错特错。

楼主,C语言跟大多数语言一样,没有规定表达式的求值顺序,除了以下几个顺序点:

;

(分号,标志一条语句结束)

(逗号操作符,函数参数列表里面的逗号只起分隔作用,不是逗号操作符)

&

和||(逻辑与,逻辑或)

:

(条件运算符)

()(if,while,for,do..while,以及函数调用)

这些统称为顺序点,它们的求值顺序有规定。

我这里只给你说明逗号操作符,其他的不一一作介绍(不然能写一大篇呢),你自己参考相关资料。

逗号表达式最简单的情形如下:

exp1,exp2;

C语言保证exp1在exp2之前求值,并且exp1求值的副作用保证在逗号之前生成。

所以象下面这个逗号表达式:

inti=1;

i++,(i==2);

最后的值就是1,因为逗号表达式的前半部分i++的副作用(i自增1)在逗号之前已经生成,所以当执行到(i==2)的时候,i的值已经是2了,所以i==2成立,(i==2)的值便作为整个逗号表达式的值。

但是,对函数原型,函数定义,函数调用,C语言里面明确说明,参数列表里面的逗号不是逗号操作符,只起到分隔作用,所以这里的逗号不再是一个顺序点,那它前后的表达式的求值顺序就是任意的,并且所有带副作用的表达式的副作用都要等到下一个顺序点之后才是确定的,也就是说你只有等到下一个顺序点之后,你才能准确得依赖这些表达式产生的副作用。

所以,像这样的函数调用

foo(i++,++i);

是得不到准确的结果的。

因为这里逗号不是逗号操作符,所以就算编译器选择的是从左到右的求值顺序,由于C语言不再保证i++的副作用在逗号之前生成,算到++i的时候,都不确定i到底有没有自增1,不确定性就在这里产生了。

再者,如果编译器选择的是从右到左求值,同样产生不确定性,这样一来,传进函数foo的两个参数的值就可能不同,那么最后的结果当然也就不同了。

你这里一样,printf是一个函数,

printf("

%d,%d,%d\n"

++i,--i,-i++);

是函数调用,括号内的所有逗号都不是逗号操作符,而只起到分隔参数的作用。

所以++i,--i,-i++这三个表达式的求值顺序是任意的,编译器想怎么算就怎么算,不同的编译器的“想法”可能相同可能不同,结果就可能一样可能不一样。

这才是楼上的各位得到不同结果的真正原因!

楼主要好好参考顺序点的定义和作用,并且牢记下面这条规则:

C语言里面明确指出:

在两个顺序点之间两次改变同一个变量的任何尝试得到的结果都是不确定的!

你这里

inti=10;

的两个顺序点分别是inti=10;

的分号,和包围printf的参数的括号,C语言只保证位于两个顺序点之间的表达式求值产生副作用在第二个顺序点之前生成,但不保证两个顺序点之间所有表达式的求值顺序。

你这里++i,--i,-i++三个表达式企图在两个顺序点前一个分号和()之间三次改变同一个变量i的值,所以结果注定是不确定的。

至于为什么C语言要规定相邻顺序点之间的表达式以任意顺序求值,是为了给编译器更多的自由空间,让底层运算操作能由编译器调度安排从而使运算更有效地执行。

1.自加运算符(++)

使用自加运算符时应注意以下5个事项:

①自加运算符“++”的运算结果是使运算对象增1。

例如,i++相当于i=i+1。

②运算符“++”是单目运算符,运算对象可以是整型变量也可以是实整型变量,不能是常量或表达式。

所以像++3、(i+j)++是不合法的。

③用自加运算符构成表达式时,既可以是前缀形式,也可以是后缀形式。

这两种形式对于变量来说,其结果都是加1,但对表达式来说其值是不同的。

④运算符“++”的结合方向是“自右向左”。

⑤不要在一个表达式中对同一个变量进行多次诸如i++或++i等运算。

2.自减运算符(--)

使用自减运算符时应注意以下5个事项:

①自减运算符“--”的运算结果是使运算对象减1。

例如,i--相当于i=i-1。

②运算符“--”是单目运算符,运算对象可以是整型变量也可以是实整型变量,不能是常量或表达式。

③用自减运算符构成表达式时,既可以是前缀形式,也可以是后缀形式。

这两种形式对于变量来说,其结果都是减1,但对表达式来说其值是不同的。

④运算符“--”的结合方向是“自右向左”。

⑤不要在一个表达式中对同一个变量进行多次诸如i--或--i等运算。

对于代码 

inti=3;

i=i++;

不同编译器给出不同的结果,有的为3,有的为4,哪个是正确的?

 

没有正确答案;

这个表达式无定义。

参见问题,和 

同时注意,i++和++i都不同于i+1。

如果你要使i自增1,使用i=i+1,i+=1,i++或++i,而不是任何组合,参见问题。

b*\Xs2mQ0N~

有人说i=i++的行为是未定义的,但是我刚在一个兼容ANSI 

的编译器上测试,得到了我希望的结果。

_'

J^\V 

面对未定义行为的时候,包括范围内的实现定义行为和未确定行为,编译器可以做任何实现,其中也包括你所有期望的结果。

但是依靠这个实现却不明智。

参加问题,,和。

]'

aH{@使用我的编译器,下面的代码 

inti=7;

printf("

%d\n"

i++*i++);

返回49不管按什么顺序计算,难道不该打印出56吗?

$`!

t|_*m 

尽管后缀自加和后缀自减操作符++和--在输出其旧值之后才会执行运算,但这里的``之后"

常常被误解。

没有任何保证确保自增或自减会在输出变量原值之后和对表达式的其它部分进行计算之前立即进行。

也不能保证变量的更新会在表达式``完成"

(按照ANSIC的术语,在下一个``序列点"

之前,参见问题之前的某个时刻进行。

本例中,编译器选择使用变量的旧值相乘以后再对二者进行自增运算。

BSD爱好者乐园c5D

u8~~(w2a

包含多个不确定的副作用的代码的行为总是被认为未定义。

(简单而言,``多个不确定副作用"

是指在同一个表达式中使用导致同一对象修改两次或修改以后又被引用的自增,自减和赋值操作符的任何组合。

这是一个粗略的定义;

严格的定义参见问题,``未定义"

的含义参见问题。

)甚至都不要试图探究这些东西在你的编译器中是如何实现的(这与许多C教科书上的弱智练习正好相反);

正如 

K&

R明智地指出,``如果你不知道它们在不同的机器上如何实现,这样的无知可能恰恰会有助于保护你。

以(i为例作为自增自减的变量)

一、 

在C语言中,是以整条语句为基础的。

1、先计算完所有的(++i)和(--i),得出这个时候的i值。

2、再根据现在的i值计算整条语句的值。

3、最后再根据(i++)和(i--)计算出i的值。

(1):

inti=5,k;

k=(++i)*(--i)*(--i);

k=%d 

i=%d"

k,i);

以上程序的输出结果为:

k=64 

i=4。

先计算(++i)、(--i)、(--i)的值,得出i=4,在算k=i*i*i,得出k=64。

(2):

inti=3,k;

k=(++i)*(i--)*(--i);

i=%d 

"

k=27 

i=2。

先计算(++i)、(--i)的值,得出i=3,在算k=i*i*i,得出k=27。

最后算(i--)

C程序中自增(自减)运算的研究与分析

李茂秋1助理研究员,泰山学院计算机科学系(271021),

摘要:

自增(自减)运算是C语言教学中的难点和重点,大多C语言教材回避了这个繁琐的问题,给C语言的学习增加了难度,本文作者在引用大量例程和上机实验的基础上,详细分析和讨论了C语言自增(自减)运算符的运算规则,提出了自己的见解,对C语言学习者具有一定的启发和借鉴作用。

关键词:

C语言自增运算(符)自减运算(符)自增(自减)因式

引言C语言具有丰富的运算符,用以实现丰富的运算功能,同时,其丰富的运算符又具有繁杂的运算规则,比如:

优先级、结合方向等。

正确的理解和使用这些运算符,能给程序设计带来效率高、代码简单等好处,自增(自减)运算符是C语言中语法繁杂、运用灵活的一个运算符,在C语言的学习中,一直是一个难点和重点,在历年的等级考试中,占有较大的比重,但在各种C语言教材中,很少对此进行详细细致的介绍。

此外,在实际编程实践中,a++尽管和a=a+1都具有对a赋值的作用,但a++具有一个显著的优点就是,它比a=a+1要快,占用的RAM更少,原因是它们的指令执行周期不同,产生的目标代码(机器码)不同。

因此,对++运算符的详细介绍十分必要,笔者结合多年的C语言教学和开发实践,引用例程,拟对此进行分析、讨论与总结。

自增(自减)运算符的基本理论

在自反赋值运算符中,有两种特殊的情况,也是两种极为常用的操作,即k=k+1写作k+=1,k=k-1写作k-=1。

这两种运算符对k所进行的操作是增1(或减1)的操作,通常,我们把k当作计数器,这两个运算符通常用来对计数器进行控制,用来记录完成某项任务的次数,C语言为这两种操作提供了更为简洁的运算符:

k++或++k(k--或--k);

++k/--k称为前缀形式;

k++/k--称为后缀形式。

无论前缀还是后缀的形式,都是使运算对象自身增1(减1)。

因此,称++(--)自增(自减)运算符。

自增(自减)运算符的优先级是14,级别较高,仅次于括号、方括号等,其结合方向是“自右至左”。

关于结合方向,将在后面说明。

自增(自减)运算符的前缀和后缀形式,在表达式中,有着不同的值,这将是我们在本文讨论的主要方面。

尽管自增(自减)运算与自反赋值运算具有相同的赋值效果,但应当知道,他们是不同的运算符,因为它们的优先级不一样,究其原因是,其编译后的目标代码不同,指令的执行周期不同,自增(自减)的执行周期小,速度快,效率高。

因为自增(自减)运算是一种赋值运算,因此不能对常量或表达式进行自增(自减)运算。

二、 

自增(自减)运算符的几种使用环境及其运算规律研究

为了研究的方便,我们把出现在表达式中,或独立构成语句的一个自增(自减)运算式,称作是一个自增(自减)因式。

对于自增或自减运算,我们除了关心自增(自减)的效率外,更重要的,我们关心的是自增(自减)因式的前缀和后缀两种形式,所产生的因式的值,及运算对象(变量)的值。

这是C语言学习和教学中的难点,也是C语言水平考试中常见的考点。

大体说来,应当考虑以下几种使用情况:

1.一个自增(自减)因式构成一个独立语句。

形如:

k++;

或++k;

这样一个因式构成一个独立语句时,其前缀形式和后缀形式得到的结果是一样的,即得到的因式的值一样,参与运算的变量k的值一样。

例程1:

/**/

main()

{intk;

k=1;

/*前缀形式*/

printf(“\nk=%d”,k);

/*验证前缀形式得到的k值*/

k=1;

++k;

/*后缀形式*/

/*验证后缀形式得到的k值*/

}

程序中,初值为1的变量k,分别出现在前缀和后缀两种形式的自增运算独立语句中,语句执行的结果,使k值都增加为1。

实际上,两个因式的值都是2。

因此可以说,在自增(自减)运算构成独立语句的时候,对自增(自减)运算的前缀和后缀的区分是毫无意义的。

2.在表达式中引用同一个变量的一个或多个自增(自减)因式。

(1) 

在表达式中只含有一个自增(自减)因式,但表达式不仅仅包含此因式,还有其他运算对象或运算符。

这种情况,按照各种教材所讲授的规律:

表达式引用此因式时,如是后缀形式,则先引用变量的值(未变化的值)当作此因式的值,参与表达式的运算,然后再变化(自增或自减)变量的值,变化了的变量的值不参与表达式的运算。

如果是前缀形式,则先进行变量的自增(自减)运算,然后引用变化了的变量值,参与表达式的运算。

例程2:

{intk,j;

k=5;

j=k++;

/*前缀形式的自增运算出现在赋值运算中*/

printf(“

(1)k=%d,j=%d\n”,k,j);

j=++k;

printf(“

(2)k=%d,++k=%d\n”,k,j);

/*验证前缀形式的运算对象和因式的值*/

程序的运行结果是:

(1)k=6,j=5;

/*先把k的初值5拿来用,即赋给变量j.再改变k的初值*/

(2)k=6,j=6;

/*先完成对k的自增为6,再拿来用,即赋给变量j.*/

因此,这种情况下,应该描述为;

当一个自增或自减运算出现在表达式中整体参与运算时,应遵循‘后缀形式;

先用后变’,‘前缀形式;

先变后用’的原则。

(2) 

表达式中含有两个或两个以上的自增(自减)运算因式。

实际上,当多个自加(自减)运算出现在同一个表达式中,系统所进行的运算远没有一个自增(自减)运算因式时简单。

请看如下例程:

例程3/**/

{inta,k=4,k1,k2,k3,k4;

a=(k1=k++)+(k2=k++)+(k3=++k)+(k4=k++);

a=%d,k=%d\n"

a,k);

k1=%d,k2=%d,k3=%d,k4=%d\n"

k1,k2,k3,k4);

}

运行结果:

a=20,k=8

k1=5,k2=5,k3=5,k4=5

程序的运行结果说明;

参与表达式运算的同一个变量的自增(自减)运算因式,在表达式中具有相同的结果,而参与自增(自减)的变量k的最终结果与这些因式的结果并不完全一致。

通过大量例程我们可以得到如下的结论:

对于参与表达式运算的各个自增(自减)因式来说,最终的值是一样的,我们可以这样解释其过程:

C系统对参与表达式运算的多个自增(自减)因式,按照运算的优先级,逐一进行运算扫描,扫描的过程遵循前缀和后缀的规律,并将最后运算的自增(自减)运算因式的结果带回到各个自增(自减)因式,使得各个自增(自减)因式以相同的值参与表达式的运算。

在上述例程中,k1=k++,按照后缀的规律,先引用k的值,再增加1,使得k1=k++的值暂时为4,计算k2=k++时,没有使k的值增1,而是继续引用k=4,k2=k++的值仍然暂时为4,计算k3=++k时,引用k的当前值k=4,因是前缀形式,所以,先增后引,使得k3=k++的值暂时为5,在计算k4=k++时,同理,引用k的当前值k=5,因是后缀形式,k4=k++的仍为5。

C系统把这最后一个自增(自减)运算因式的值,重新带回到其他自增(自减)运算因式,参与表达式的运算,因此使得k1=5,k2=5,k3=5,k4=5。

为验证一下这个结论,我们可以随意将程序中的各自增(自减)因式修改,改变前后缀形式,改变增或减,均可以分析得出正确的执行结果。

对于这种结论,我们可以概括总结为一句话:

对于表达式中同一变量的多个自增(自减)因式的值,遵循“逐一扫描,共同引

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 工程科技 > 电子电路

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1