二、运算符与表达式
二、运算符与表达式
1.算数运算符
C语言提供了 13 种类型的运算符, 如下所示。
(1) 算术运算符 (+-*/ %) .
(2) 关系运算符 (> < == >= <= !=) .
(3) 逻辑运算符(!&&‖) .
(4) 位运算符(<<>>~|^&) 。
(5) 赋值运算符(=及其扩展赋值运算符) 。
(6) 条件运算符(?:) 。
(7) 逗号运算符(,) 。
(8) 指针运算符(*和&) 。—讲指针时讲解
(9) 求字节数运算符(sizeof) .
(10) 强制类型转换运算符 ((类型)) .
(11) 分量运算符(.->) 。—讲结构体时讲解
(12) 下标运算符 ([]) 。 —-讲数组时讲解
(13) 其他(如函数调用运算符()) 。—讲函数时讲解
2 .算术运算符及算术表达式
算术运算符包含+、-、*、/和%,乘、除、取余运算符的优先级高于加、减运算符。除%运算符外, 其余几种运算符既适用于浮点型数又适用于整型数。当操作符/的两个操作数都是整型数时, 它执行整除运算, 在其他情况下执行浮点型数除法。**%为取模运算符, 它接收两个整型操作数,** 将左操作数除以右操作数, 但它的返回值是余数而不是商。由算术运算符组成的式子称为算术表达式, 表达式一定有一个值。
#include <stdio.h>
//练习算术运算符
int main() {
int result=4+5*2-6/3+11%4; //15
printf("result=%d\n",result);
return 0;
}
3.关系运算符与关系表达式
关系运算符>、<、==、>=、<=、!=依次为大于、小于、是否等于、大于等于、小于等于和不等于, 由关系运算符组成的表达式称为关系表达式。**关系表达式的值只有真和假**, 对应的值为1和0. 由于 C语言中没有布尔类型, 所以在C语言中O值代表假,非0值即为真.例如, 关系表达式3>4为假, 因此整体值为0, 而关系表达式5>2为真, 因此整体值为1. 关系运算符的优先级低于算术运算符,
当判断整型变量 i是否等于3时, 我们可以写为3==i, 即把常量写在前面而把变量写在后面.这是因为当不小心将两个等号写为一个等号时, 变量在前面就会导致编译不通, 从而快速发现错误
同时,在编写程序时,如果我们需要判断三个数是否相等,那么绝对不可以写为 if(5==5==5),这种写法的值无论何时都为假, 为什么? 因为首先 5==5 得到的结果为1, 然后1==5得到的结果为0. 如果要判断三个变量a、b、c是否相等, 那么不能写为a==b==c, 而应写为 a==b&&b==c. 下面来看一个例子.
#include <stdio.h>
//关系运算符,优先级小于算术运算符
int main() {
int a;
while(scanf("%d",&a))
{
if(3<a && a<10)//a大于3同时a小于10要这样写
{
printf("a is between 3 and 10\n");
}else{
printf("a is not between 3 and 10\n");
}
}
return 0;
}
如果要判断变量 a 是否大于3且同时小于 10, 那么不能写为3<a<10, 首先, 无论a是大于3还是小于3, 对于3<a这个表达式只有1或0两种结果。 由于1和0都是小于10的, 所以无论a的值为多少, 这个表达式的值始终为真, 因此在判断变量a是否大于3且同时小于 10时, 要写成:a>388a<10,, 这才是正确的写法.
4.运算符优先级表
优先级 | 运算符 | 名称或含义 | 使用形式 | 结合方向 | 说明 |
---|---|---|---|---|---|
1 | [] | 数组下标 | 数组名[常量表达式] | 左到右 | |
1 | () | 圆括号 | (表达式)函数名(形参表) | 左到右 | |
1 | . | 成员选择(对象) | 对象.成员名 | 左到右 | |
1 | -> | 成员选择(指针) | 对象指针->成员名 | 左到右 | |
2 | - | 负号运算符 | -表达式 | 右到左 | 单目运算符 |
2 | (类型) | 强制类型转换 | (数据类型)表达式 | 右到左 | |
2 | ++ | 自增运算符 | ++变量名/变量名++ | 右到左 | 单目运算符 |
2 | -- | 自减运算符 | --变量名/变量名-- | 右到左 | 单目运算符 |
2 | * | 取值运算符 | *指针变量 | 右到左 | 单目运算符 |
2 | & | 取地址运算符 | &变量名 | 右到左 | 单目运算符 |
2 | ! | 逻辑非运算符 | !表达式 | 右到左 | 单目运算符 |
2 | ~ | 按位取反运算符 | ~表达式 | 右到左 | 单目运算符 |
2 | sizeof | 长度运算符 | sizeof(表达式) | 右到左 | |
3 | / | 除 | 表达式 / 表达式 | 左到右 | 双目运算符 |
3 | * | 乘 | 表达式*表达式 | 左到右 | 双目运算符 |
3 | % | 余数(取模) | 整型表达式%整型表达式 | 左到右 | 双目运算符 |
4 | + | 加 | 表达式+表达式 | 左到右 | 双目运算符 |
4 | - | 减 | 表达式-表达式 | 左到右 | 双目运算符 |
5 | << | 左移 | 变量<<表达式 | 左到右 | 双目运算符 |
5 | >> | 右移 | 变量>>表达式 | 左到右 | 双目运算符 |
6 | > | 大于 | 表达式>表达式 | 左到右 | 双目运算符 |
6 | >= | 大于等于 | 表达式>=表达式 | 左到右 | 双目运算符 |
6 | < | 小于 | 表达式<表达式 | 左到右 | 双目运算符 |
6 | <= | 小于等于 | 表达式<=表达式 | 左到右 | 双目运算符 |
7 | == | 等于 | 表达式==表达式 | 左到右 | 双目运算符 |
7 | != | 不等于 | 表达式!= 表达式 | 左到右 | 双目运算符 |
8 | & | 按位与 | 表达式&表达式 | 左到右 | 双目运算符 |
9 | ^ | 按位异或 | 表达式^表达式 | 左到右 | 双目运算符 |
10 | | | 按位或 | 表达式|表达式 | 左到右 | 双目运算符 |
11 | && | 逻辑与 | 表达式&&表达式 | 左到右 | 双目运算符 |
12 | || | 逻辑或 | 表达式||表达式 | 左到右 | 双目运算符 |
13 | ?: | 条件运算符 | 表达式1? 表达式2: 表达式3 | 右到左 | 三目运算符 |
14 | = | 赋值运算符 | 变量=表达式 | 右到左 | |
14 | /= | 除后赋值 | 变量/=表达式 | 右到左 | |
14 | *= | 乘后赋值 | 变量*=表达式 | 右到左 | |
14 | %= | 取模后赋值 | 变量%=表达式 | 右到左 | |
14 | += | 加后赋值 | 变量+=表达式 | 右到左 | |
14 | -= | 减后赋值 | 变量-=表达式 | 右到左 | |
14 | <<= | 左移后赋值 | 变量<<=表达式 | 右到左 | |
14 | >>= | 右移后赋值 | 变量>>=表达式 | 右到左 | |
14 | &= | 按位与后赋值 | 变量&=表达式 | 右到左 | |
14 | ^= | 按位异或后赋值 | 变量^=表达式 | 右到左 | |
14 | |= | 按位或后赋值 | 变量|=表达式 | 右到左 | |
15 | , | 逗号运算符 | 表达式,表达式,… | 左到右 |
同一优先级的运算符,运算次序由结合方向所决定。
简单记就是: ! >算术运算符>关系运算符>&&> || >赋值运算符
5.逻辑运算符与逻辑表达式
逻辑运算符!、&&、‖依次为逻辑非、逻辑与、逻辑或,这和数学上的与、或、非是一致的。逻辑非的优先级高于算术运算符, 逻辑与和逻辑或的优先级低于关系运算符,逻辑表达式的值只有真和假,
#include <stdio.h>
//记住优先级目的,不能够加多余的括号
int main() {
int year,i,j=6;
while(scanf("%d",&year))
{
if(year%4==0&&year%100!=0 || year%400==0)
{
printf("%d is leap year\n",year);
}else{
printf("%d is not leap year\n",year);
}
}
i=!!j;
printf("i value=%d\n",i);
return 0;
}
针对代码中的逻辑非, 首先给变量j赋值 6, 因为j 的值非0, 所以!j 的值为0; 然后, 由于逻辑非是单目运算符, 结合顺序为从右至左, 得到!!j的值为1。也就是说, 对0取非, 得到的值为 1; 对非0值取非, 得到的值为0.
短路运算
#include <stdio.h>
//逻辑与和逻辑或 短路运算
int main() {
int i=0;
i&&printf("you can't see me !\n");//当i为假时,不会执行逻辑与后的表达式,称为短路运算
i=1;
i||printf("you can't see me !\n");
return 0;
}
逻辑与短路运算是当前面一个表达式为假时, 后面的表达式不会得到执行, 逻辑或短路运算是当前面一个表达式为真时, 后面的表达式不会得到执行
6.赋值运算符
为了理解有些操作符存在的限制, 必须理解左值 (L-value) 和右值(R-value) 之间的区别。这两个术语多年前由编译器设计者创造并沿用至今, 尽管它们的定义与C语言并不严格吻合。
左值是那些能够出现在赋值符号左边的东西, 右值是那些可以出现在赋值符号右边的东西。例如,a = b+25;其中, a 是一个左值, 因为它标识了一个可以存储结果值的地点; b + 25是一个右值, 因为它指定了一个值.
它们可以互换吗? 比如:b + 25 = a;因为每个位置都包含一个值, 所以原先用作左值的a 此时也可以作为右值; 然而, b+25不能作为左值, 因为它并未标识一个特定的位置(并不对应特定的内存空间) . 因此, 上面这条赋值语句是非法的。
复合赋值运算符:
复合赋值运算符操作是一种缩写形式, 使用复合赋值运算符能使对变量的赋值操作变得更加简洁, 例如,
iNum = iNum + 5;
对变量 iNum的赋值进行操作, 值为这个变量本身与一个整型常量5 相加的结果.使用复合语句可以实现同样的操作。例如, 上面的语句可以修改为
iNum+=5;
赋值运算符与复合赋值运算符的区别如下:
(1) 复合赋值运算符简化了程序, 可使程序精炼, 提升阅读速度。
(2) 复合赋值运算符提高了编译效率。
下例说明了加后赋值与乘后赋值的用法。
#include <stdio.h>
//赋值的练习
int main() {
int a=1,b=2;
a+=3;
b*=5;
printf("a=%d\n",a);
printf("b=%d\n",b);
return 0;
}
上面的程序代码可以看到,a+=3代表a加3 后再赋值给a, 因此a的最终值为4, 而 b的值等于5乘以b的值, 所以最终结果为10。
7.求字节运算符
很多同学会认为 sizeof是一个函数, 这种理解是错误的, 实际sizeof是一个运算符, 不像其他运算符是一个符号, sizeof是字母组成的, 用于求常量或变量所占用的空间大小,例:
#include <stdio.h>
//sizeof运算符
int main() {
int i=0;
printf("i size is %d\n",sizeof(i));
return 0;
}
运行结果为 i size is 4, 可以求得整型变量占用的空间大小是 4个字节。