好了,在我们继续之前,我们先来做一道数学题
1+1*2=?
一道小学数学题,在你小学数学合格的情况下,你应该回答为2而不是4
为什么?
因为我们都知道的运算法则:先乘除后加减
在我们初中学习了乘方后,对于下面的题目
3*2^2 (这里的^代表数学中的乘方)
我们也能很快的得出正确的答案:12,而不是36
因为应该先计算乘方。
但是,对于下面的这个式子
(3*2)^2
它的值便是36,因为括号中的内容应该最先计算
从上面不难发现,对于一个式子中出现的各种计算,人们规定了他们运算的先后顺序
这种顺序便是优先级。只有按照正确的顺序进行计算,得出的结果才是合理且正确的
在编程中,同样有着优先级的规定
下面这个简单的表中给出了我们已经学习过的运算的优先级
优先级(不完整) | 符号 | 名称或含义 | 用法 |
---|---|---|---|
1 | () | 圆括号 | (表达式) |
2 | + | 一元正号 | +表达式 |
- | 一元负号 | -表达式 | |
(type) | 强制类型转换 | (double)123 | |
++ | 自增 | ++变量 变量++ |
|
-- | 自减 | --变量 变量-- |
|
sizeof | 长度运算符 | sizeof var | |
3 | * | 算数乘号 | 表达式1*表达式2 |
/ | 算术除号 | 表达式1/表达式2 | |
% | 求余 | 表达式1%表达式2 | |
4 | + | 算术+ | 表达式1+表达式2 |
- | 算术减号 | 表达式1-表达式2 | |
5 | > | 大于 | 表达式1>表达式2 |
< | 小于 | 表达式1<表达式2 | |
>= | 大于等于 | 表达式1>=表达式2 | |
<= | 小于等于 | 表达式1<=表达式2 | |
6 | == | 等于 | 表达式1==表达式2 |
!= | 不等于 | 表达式1!=表达式2 | |
7 | = | 赋值运算符 | 左值=表达式 |
注意,上表中出现的符号只是C语言中的一部分,因此表格中给出的优先级的数字只能做一个参考
在这个表中
优先级越小的符号优先级越高
因此我们可以看到,括号的优先级最高
这意味着我们几乎可以在任何时候使用括号强行改变运算执行的顺序
从上表我们还可以得出
赋值符号的优先级(在此表中)最低
这就是说,像下面的语句
a=1+3
相当于a=(1+3)
同理,比较大小时使用的>等符号,优先级也比四则运算的优先级低
这就是说像a>5+1
相当于a>(5+1) 即a>6
而且不是拿a与5进行比较
对于完整的优先级表,你可以在这里得到 http://yangwang.hk/?p=489
你可能会问,这么多运算符的优先级需要记忆吗?
答案是,基本不需要
我们只需要对于加减乘除等符号的优先级有一个大致的了解
对于较为复杂的式子,更方便而且更好的方法是使用神奇的括号
如下面的代码
if(a=getchar()+1!=0)
if中的表达式涉及了3个符号
根据上表,我们可以分析运算的过程
因为赋值符号优先级很低,因此一定会在赋值前先执行getchar()+1!=0
而不等号的优先级比算术加号的优先级低
因此表达式执行的过程为
- 通过getchar()读取一个字符
- 将读取到的字符和1相加
- 使相加的结果和0比较
- 将比较的结果赋值给a
但是通过这种方法判断执行的顺序不仅麻烦,而且容易出错
在这种情况下,我们可以使用括号,来“确保”执行的顺序为我们所期望的
if(a = ( (getchar() + 1) != 0) )
这样,不仅执行的顺序一目了然,甚至在我们不记得以上符号的优先级的情况下
也能使程序按照我们所希望的方法执行
值得一说的是,对于同样优先级的运算,运算的先后则由结合性决定。
而且某些操作可能会产生不可确定的结果(未定义行为),关于这些内容,我们将在稍后的文章中详细介绍
然后,我们将继续学习一些运算符
自增与自减
在上面的表中,我们已经给出了自增和自减这两个符号
实际上,对于自增和自减来说,他们分别又有两种写法
例如对于int型变量var来说
自增可以写为
++var和var++
自减也类似
像第一种自增(减)符号写在变量前面的情况,叫做“前缀自增”,依此类推,第二种则为“后缀自增”
自增和自减的作用为,将变量内的值加上(或减去)1,(因此此操作符只对非浮点数的类型有效,浮点数即使小数点后全部为0,也是浮点数)
例如var原来的值为10
在执行完
++var;
后,var的值将变为11
同理,如果是–var,那么得到的值就为9
你可以编写一个简单的程序进行尝试
因为自增和自减对于变量的加减1非常方便
因此在需要重复进行加、减1操作的地方非常常用,如循环
对于3.3中的如下程序
#include <stdio.h> #include <stdlib.h> int main() { int i = 0; while (i <= 100) { printf("%d\n", i); i = i + 1; } return 0; }
我们可以使用自增运算符改写,如下
#include <stdio.h> #include <stdlib.h> int main() { int i = 0; while (i <= 100) { printf("%d\n", i); ++i; } return 0; }
换句话说,++i在功能上等同于i = i+1(但也只是在功能上)
–i的结果,等同于i = i – 1
对于后缀写法的自增自减运算
和前缀有些许差别(但是却会对程序的结果产生很大的影响)
在这种简单的增(减)1的情况下,推荐使用前缀写法
我们将于稍后的岔路口详细讨论这个问题
加后赋值与减后赋值
还是对于上面的程序
i=i+1可以使用自增操作符代替
但是对于增加的数不为1,而是2,甚至是0.5的情况呢?
对于此,c语言还提供另外一种运算符,叫做加后赋值
加后赋值:+=
减后赋值:-=
注意两个字符连在一起,它是一个完整的运算符,而不是由其它符号和赋值符号组合成的!
对于i = i + 1
我们可以写作i += 1
对于i=i+5,可以写作i+=5,对于int来说,这两个式子是等价的(对于其他类型则略有差异,我们将在稍后的文章详细叙述)
运算过程为,先取出i的值,然后将其加上右边表达式的值,再将其赋值给i(加后赋值这个名字也好理解了)
对于减后赋值,同理
这些符号对浮点数同样有效
类似的
还有“乘后赋值”(*=)
“除后赋值”(/=)
“取余后赋值”(%=)
用法和含义和上面类似