二、运算符与表达式

二、运算符与表达式

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个字节。