c君你学校教真快LOL
算术运算符
我们已经接触过诸如+、-、*、/、=
这样的算术运算符。现在我们来更详细地探究它们的特点。
赋值运算符:=
在C语言中,=
不意味着相等,而是一个赋值运算符。例如:num = 123;
这个语句会把值123赋给变量num。我们在阅读程序时,不能视作**“num等于123”**。
C语言使用==
表示相等。我们会在后面再做详细的介绍。
区分赋值和相等的意义是什么?当我们写下这个语句时:
num = num + 1;
显然,这在数学上是错误的,但在程序中,这得以成立。这条语句的意思是:找到变量num的值(即123),把它加上1,再把新值124赋给变量num。
赋值运算符的作用是把右边的值赋给左边的值。由此,我们需要对赋值运算符左右的值做一个区分。我们把运算符右边的值称为右值,把左边的值称为左值。右值只能是字面常量。
显然,根据上面的说法:以下语句是错的:
123 = num;
显然,我们无法把一个变量的值赋到一个常量上(常量本身就是它的值)。
然而,像num2 = num
这样的语句是对的。因为在这条语句之前,num的值已经确定了。所以在这里,它可以被视作一个字面常量。因此,我们在上面要强调,右值必须是字面常量。除此之外,表达式的值也会在赋值之前被确认,所以表达式也可以做右值。
另外要注意的是:使用#define
或const
定义的常量不能做左值。
C语言还支持多重赋值,因此,像num = num1 = num2;
这样的语句不会报错,但不建议使用。
加/减法运算符:+、-
加法运算符用于将两侧的值相加。相加的对象可以是变量,也可以是常量。像这样的语句:
num = num1 + num2;
会将赋值运算符右侧的两个数相加,再把结果赋给左值。
减法运算符用于将左侧的值减去右侧的值。同加法运算符相似,相减的既可以是变量也可以是常量。
加法运算符和减法运算符都是二元运算符。它们必须要两个对象才能完成操作。
符号运算符:-、+
负号运算符可以表示或改变值的符号。如果我们执行以下语句:
num = 123;
num2 = -num;
那么num2
的值就是-123
。也可以使用+来表示符号,但一般不用。
符号运算符是一元运算符。它们只需要一个运算对象。
### 乘/除法运算符:*、/
乘法运算符用于将两侧的值相乘。它的用法与加法运算符类似。
除法运算符用于将左侧的值除以右侧的值。特别要注意的是整数除法和浮点数除法的不同。
我们看下面这个程序:
//divsion.c //演示除法运算符
#include <stdio.h>
int main(void)
{
printf("整数除法:6/3 = %d\n",6/3);
printf("整数除法:7/2 = %d\n",7/2);
printf("浮点数除法:7.0/2.0 = %.2f\n",7.0/2.0);
printf("混合除法:7.0/2 = %.2f\n",7.0/2);
return 0;
}
运行结果如下:
整数除法:6/3 = 2
整数除法:7/2 = 3
浮点数除法:7.0/2.0 = 3.50
混合除法:7.0/2 = 3.50
我们在使用整数除法的时候,计算机会自动截断结果的小数部分(不会四舍五入)。混合除法的结果是浮点数,在进行混合除法时,计算机会自动将两个数转换成浮点数。
其他运算符
C语言有多种多样的运算符。我们在前面已经介绍了sizeof
运算符,现在再介绍求模、递增/减和复合赋值运算符。
求模运算符:%
求模运算符用于求出左侧整数除以右侧整数的余数。它只能用于整数,不能用于浮点数。
例如:13 % 5
的结果是3。
递增/减运算符:++、–
递增/减运算符用于将其运算对象递增/减1。它们既可以出现在运算对象前面做前缀,也可以做后缀。这两种形式分别如下:
++count;//前缀形式
count--;//后缀形式
这两种形式都可以使用。区别在于:前缀形式是先递增/减对象再使用它,而后缀形式是先使用对象再递增/减它。我们通过以下的语句详细解释:
num = 123;
num2 = ++num;//num2 = 123+1
num3 = num2++;//num3 = 124,num2 = 124+1 = 125
使用递增/减运算符使代码更加简明易懂。
复合赋值运算符
通过把算数运算符与赋值运算符结合到一起,我们可以使代码更加简短。例如:+=是加法赋值运算符。它会把左侧对象与右侧对象相加,并把结果赋值给左侧对象。例如:
num = 123;
num2 = 12;
num += num2;//num = num + num2 = 123 + 12 = 135
其他复合赋值运算符的用法与此类似。
C语句的多种写法
显然,我们可以意识到,下列语句是完全等价的:
x++;
x += 1;
x = x + 1;
它们都表示x的值相比原来增加1。但是在具体的编程中用法会有不同。递增/减运算符常用于计数,这可以命令程序执行指定的次数。复合赋值运算符常用于累加。至于第三种则基本不用,这种语句会让程序难以读懂。
运算符的优先级
我们看这几个语句:
int n = 6;
int num2 = 2;
num = 20.0 + 30.0 * n / num2;
计算机会以什么顺序进行计算?C语言对此有明确的规定。
首先,乘除法的优先级高于加减法。因此,计算机会先计算后半部分。
其次,如果乘除法处理同一个对象(在这里是n
),那么就会从左到右计算。在这里,计算机首先计算30.0 * n
,其次计算180 / num2
。
但如果我们使用括号把20.0 + 30.0
括了起来,计算机就会优先计算括号内的内容。
总结如下:运算符的优先级从高到低排列如图:
运算符 | 运算顺序 |
---|---|
() | 从左至右 |
++、– | 视情况而定(前/后缀不同) |
+、-(符号) | 从右至左(符号运算符与其右侧的值结合) |
*、/ | 从左至右 |
+、- | 从左至右 |
= | 从右至左 |
接下来,我们考虑更加复杂的情况:对于这条语句:
num = i = - (3 + 8) * 5 + (4 + 3 * (2 + 1));
我们注意到后半段的括号有两层。所以,计算机优先计算最里面的一层括号:2+1
,得到3。随后计算3*3
,得到9,再计算4+9
,得到13。同时对前面的括号进行计算,得11。然后进行符号运算,得**-11**,再进行乘法计算,得-55。最后进行加法运算,最后得到-42,赋值给i
,又赋值给num
。所以num的值是**-42**。
(附加:不要自作聪明)
我们不建议使用这样的语句:
num2 = num / 2 + 8*(6 + num++);
这个语句看上去是很清晰的:首先,num递增1,然后加上6,再乘上8。此时,它应该加上num / 2
的值。但问题是:程序员能保证他想要加上的是已经递增过的num的值的一半吗?所以,不要在一句语句中加入太多运算符。