06. 运算符与表达式

一、运算符与表达式

  运算符 就是对字面量或者变量进行操作的符号;表达式 是指用运算符把字面量或者变量连接起来,符合 C 语言语法的式子。不同运算符连接的表达式体现的是不同类型的表达式;每个表达式都有一个值。要想获取这个值,必须根据运算符优先级的顺序来执行操作。

二、算数运算符

  数字类型进行运算时,数据类型不一样是不能进行运算的,需要转换成一样的类型,才能运算;当容量小的数据类型的变量与容量大的数据类型的变量做运算时,结果自动提升为容量大的数据类型(此时的容量大小指的是,表示数的范围的大和小)。

算数运算符运算范例结果
+5 + 2
‘a’ + 5
7
‘f’
-5 - 23
*5 * 210
/5 / 2
5.0 / 2
2
2.5
%取模(取余)5  % 21
#include <stdio.h>

int main(void)
{
    int a = 5;
    int b = 2;
    char ch = 'a';
    double c = 5;

    printf("%d + %d =  %d\n",a,b,a+b);      // 5 + 2 = 7
    printf("%d - %d =  %d\n",a,b,a-b);      // 5 - 2 = 3
    printf("%d * %d =  %d\n",a,b,a*b);      // 5 * 2 = 10
    printf("%d / %d =  %d\n",a,b,a/b);      // 5 / 2 = 2
    printf("%d %% %d =  %d\n",a,b,a%b);     // 5 % 2 = 1

    printf("%c + %d = %c\n",ch,a,ch+a);     // a + 5 = f
    printf("%lf / %d = %lf\n",c,b,c/b);     // 5.000000 / 2 = 2.500000

    return 0;
}

在代码中,如果有小数参与运算,其结果可能是不精确的;

当参与 / 运算的两个操作数都是整数时,表示整数除法;否则,表示浮点除法;

float 与 double 不能进行取余运算;

C99 规定 “趋零截断”,即,% 取模运算结果的正负与被模数一致,即:a % b 等价于 a - a/ b * b,取模结果的正负与 a 的正负一致;

字符 + 字符 或者 字符 + 数字 的时候,会把字符通过 ASCII 码表 查询到对应的数字再进行计算;

三、自增自减运算符

  ++ 和 – 即可以放在变量的前面,也可以放在变量的后面;++ 和 – 无论是放在变量的前面还是后面,单独写一行的结果是一样;如果 前 ++前 – 参与运算的话,那 先用后加(减);如果 后 ++后 – 参与运算的话,那 先加(减)后用

自增自减运算符运算范例结果
++变量的值加 1a = 2; b = ++a;
a = 2;b = a++;
a = 3; b = 3;
a = 3; b = 2;
变量的值减 1a = 2; b = --a;
a = 2; b = a–;
a = 1; b = 1;
a = 1; b = 2;
#include <stdio.h>

int main(void)
{
    int a = 2;
    int b;
  
    // 运算规则等价于 a=a+1; int b=a;
    b = ++a;
    printf("前++\n");
    printf("a = %d\n",a);   // 3
    printf("b = %d\n",b);   // 3
    putchar('\n');

    // 运算规则等价于 int b=a; a=a+1;
    a = 2;
    b = a++;
    printf("后++\n");
    printf("a = %d\n",a);   // 3
    printf("b = %d\n",b);   // 2
    putchar('\n');

    // 运算规则等价于 a=a-1; int b=a;
    a = 2;
    b = --a;
    printf("前--\n");
    printf("a = %d\n",a);   // 1
    printf("b = %d\n",b);   // 1
    putchar('\n');

    // 运算规则等价于 int b=a; a=a-1;
    a = 2;
    b = a--;
    printf("后--\n");
    printf("a = %d\n",a);   // 1
    printf("b = %d\n",b);   // 2
    putchar('\n');

    return 0;
}

自增和自减运算符只能影响一个变量,或者说,只能影响一个可修改的左值;

四、赋值运算符

  赋值运算符 用于将表达式的值赋值给变量。

赋值运算符运算示例
=赋值a = 10
+=加后赋值a += b 等价于 a = a + b
-=减后赋值a -= b 等价于 a = a - b
*=乘后赋值a *= b 等价于 a = a * b
/=除后赋值a /= b 等价于 a = a / b
%=取余后赋值a %= b 等价于 a = a % b
<<=左移后赋值a <<= b 等价于 a = a << b
>>=右移后赋值a >>= 3 等价于 a = a >> b
&=按位与后赋值a &= b 等价于 a = a & b
|=按位或后赋值a| b 等价于 a = a | b
^=按位异或后赋值a ^ b 等价于 a = a ^ b
#include <stdio.h>

int main(void)
{
    int a = 10;
    int b = 5;

    a += b;
    printf("a =  %d\n",a);      // 15
    printf("b = %d\n",b);       // 5
    putchar('\n');

    a = 10;
    b = 5;

    a -= b;
    printf("a =  %d\n",a);      // 5
    printf("b = %d\n",b);       // 5
    putchar('\n');

    a = 10;
    b = 5;

    a *= b;
    printf("a =  %d\n",a);      // 50
    printf("b = %d\n",b);       // 5
    putchar('\n');

    a = 10;
    b = 5;

    a /= b;
    printf("a =  %d\n",a);      // 2
    printf("b = %d\n",b);       // 5
    putchar('\n');

    a = 10;
    b = 5;

    a %= b;
    printf("a =  %d\n",a);      // 0
    printf("b = %d\n",b);       // 5
    putchar('\n');

    return 0;
}

五、关系运算符

  关系运算符 也被称为 比较运算符;关系运算符 用于表达式的比较,并返回一个真值或假值。在 C 语言中,0 为假,非 0 为真

关系运算符运算范例结果
==相等4 == 30
!=不等于4 != 31
<小于4 < 30
>大于4 > 31
<=小于等于4 <= 30
>=大于等于4 >= 31
#include <stdio.h>

int main(void)
{
    int a = 4;
    int b = 3;

    printf("%d == %d: %d\n",a,b,(a==b));    // 4 == 3: 0
    printf("%d != %d: %d\n",a,b,(a!=b));    // 4 != 3: 1
    printf("%d < %d: %d\n",a,b,(a<b));      // 4 < 3: 0
    printf("%d <= %d: %d\n",a,b,(a<=b));    // 4 <= 3: 0
    printf("%d > %d: %d\n",a,b,(a>b));      // 4 > 3: 1
    printf("%d >= %d: %d\n",a,b,(a>=b));    // 4 >= 3: 1

    return 0;
}

六、逻辑运算符

  逻辑运算符 用于根据表达式的值返回真值或假值。在 C 语言中,0 为假,非 0 为真

逻辑运算符功能
&&逻辑与,全真为真,有假为假
||逻辑或,有真为真,全假为假
!逻辑非,非假为真,非真为假

  运算结果:

aba && ba|| b!a
11110
10000
01001
00001
#include <stdio.h>

int main(void)
{
    int a = 1;
    int b = 1;
    int c = 0;
    int d = 0;

    // 逻辑与,两边都为真,结果才为真
    printf("%d && %d: %d\n",a,b,(a&&b));    // 1 && 1: 1
    printf("%d && %d: %d\n",a,c,(a&&c));    // 1 && 0: 0
    printf("%d && %d: %d\n",c,d,(c&&d));    // 0 && 0: 0
    printf("\n");

    // 逻辑或,两边都为假,结果才为假
    printf("%d || %d: %d\n",a,b,(a||b));    // 1 || 1: 1
    printf("%d || %d: %d\n",a,c,(a||c));    // 1 || 0: 1
    printf("%d || %d: %d\n",c,d,(c||d));    // 0 || 0: 0
    printf("\n");

    // 逻辑非
    printf("!%d: %d\n",a,!a);               // !1 = 0
    printf("!%d: %d\n",c,!c);               // !0 = 1
    printf("\n");

    return 0;
}

  短路与逻辑运算符 和 逻辑或运算符 具有短路效果,即当左边的表达式能确定最终结果时,那么右边就不会参与运算了;

  • 逻辑与运算符;当符号左边是 true 时,&& 会执行右边的运算;当符号左边是 false 时,&& 不再执行符号右边的运算;
  • 逻辑或运算符:当符号左边是 false 时,|| 会执行右边的运算;当符号左边是 true 时,|| 不再执行右边的运算;
#include <stdio.h>

int main(void)
{
    // 短路逻辑运算符具有短路效果
    // 当左边的表达式能确定最终结果时,那么右边就不会参与运算了
    int a = 10;
    int b = 10;
    int c;
  
    c = (++a < 5) && (++b < 5);
    printf("(++a < 5) && (++b <5): %d\n",c);    // 0
    printf("a = %d\n",a);                       // 11
    printf("b = %d\n",b);                       // 10
    printf("\n");

    a = 10;
    b = 10;

    c = (++a > 5) || (++b > 5);
    printf("(++a > 5) || (++b >5): %d\n",c);    // 1
    printf("a = %d\n",a);                       // 11
    printf("b = %d\n",b);                       // 10
    printf("\n");

    return 0;
}

七、位运算符

  位运算符是直接对整数的二进制进行的运算; 所有数字在计算机底层都以二进制形式执行;所有的整数值底层都以补码的方式存储;

  • 正数:三码合一,符号位为 0;
  • 负数:符号位为 1
    • 原码:直接将数值转成二进制数,最高位是符号位;
    • 反码:对原码按位取反,符号位不变;
    • 补码:其反码加 1;
位运算符运算范例
<<左移,空位补 0,被移除的高位舍弃3 << 2 = 12
>>右移,空位使用符号位填充,被移除的低位舍弃3 >> 1 = 1
&与运算,二进制位进行与运算,全1为1,有0为06 & 3 = 2
|或运算,二进制位进行或运算,有1为1,全0为06| 3 = 7
^异或运算,二进制位进行异或运算,相同为0,不同为16 ^ 3 = 5
~按位取反,二进制位进行取反运算,非0为1,非1为0~6 = -7
#include <stdio.h>

int main(void)
{
    printf("3 << 2: %d\n",(3 << 2));        // 12
    printf("3 >> 1: %d\n",(3 >> 1));        // 1
    printf("-3 >> 1: %d\n",(-3 >> 1));      // -2
    printf("6 & 3: %d\n",(6 & 3));          // 2
    printf("6 | 3: %d\n",(6 | 3));          // 7
    printf("6 ^ 3: %d\n",(6 ^ 3));          // 5
    printf("~6: %d\n",(~6));                // -7

    return 0;
}

<<:在一定范围内,每向左移一位,相当于乘以 2;

>>:在一定范围内,每向右移一位,相当于除以 2;

我们可以通过 x | (1 << (y - 1)) 的方式将第 y 位 置1

我们可以通过 x & (~(1 << (y-1))) 的方式将第 y 位 清零

八、三元运算符

  三元运算符的格式如下:

(条件表达式) ? 表达式1 : 表达式2;

  它的执行流程如下:

  • 三元运算符在执行时,会先对条件表达式进行求值判断
    • 如果条件表达式结果为 1,运算后的结果是 表达式1
    • 如果条件表达式结果为 0,运算后的结果是 表达式2
#include <stdio.h>

int main(void)
{
    int a = 10;
    int b = 20;

    // 使用三元运算符获取两个整数的较大值
    printf("%d",((a > b) ? a : b));     // 20

    return 0;
}

三元运算符结果一定要使用,不能单独写在一行;

三元运算符的表达式 1 和表达式 2 为同种类型

三元运算符一定可以改成 if-else 语句,反之不成立;

如果程序既可以使用三元运算符又可以使用 if-else 语句,优先使用三元运算符;

九、逗号运算符

  逗号表达式就是用逗号隔开的一串表达式,逗号表达式的特点是是从左向有依次计算的,整个表达式的结果是最后一个表达式的结果。

#include <stdio.h>

int main(void)
{
    int a = 0;
    int b = 3;
    int c = 5;
    int d = (a=b+2, c=a-4 , b=c+2);	// a=5,c=1,b=3

    printf("%d\n",d);

    return 0;
}

十、sizeof运算符

  sizeof 运算符以字节位单位带返回运算对象的大小。运算对象可以是具体的数据对象(如,变量名)或类型(如,int)如果运算对象是类型,则必须用圆括号将其括起来。

  C 语言规定,sizeof 返回 size_t 类型的值。这时候一个无符号整数类型,但它不是新类型。在 C 头文件中,使用 typedef 把 size_t 作为 unsigned int 或 unsigned long 的别名。这样,在使用 size_t 类型时,编译器会根据不同的系统替换标准类型。

  C99 做了进一步调整,新增了 %zd 和 %zu 转换说明用于 printf() 显示 size_t 类型的值。如果系统不支持 %zd 和 %zu,可使用 %u 或 %lu 代替。

#include <stdio.h>

int main(void)
{
    char str[] = "hello world!";

    printf("char: %zu\n",sizeof(char));                         // 1
    printf("short: %zu\n",sizeof(short));                       // 2
    printf("int: %zu\n",sizeof(int));                           // 4
    printf("long: %zu\n",sizeof(long));                         // 4
    printf("long long: %zu\n",sizeof(long long));               // 8
    printf("float: %zu\n",sizeof(float));                       // 4
    printf("double: %zu\n",sizeof(double));                     // 8
    printf("long double: %zu\n",sizeof(long double));           // 16

    printf("str: %zu\n",sizeof str);                            // 13
    printf("integer: %zu\n",sizeof 10);                         // 4
    printf("decimals: %zu\n",sizeof 3.14);                      // 8
  
    return 0;
}

不同的操作系统环境下,使用 sizeof 运算符得到的结果可能不同;

sizeof 何时使用圆括号取决于运算对象是类型还是特定量;运算对象是类型时,圆括号必不可少,但是对于特定量,可有可无;

十一、运算符的优先级

  我们可以使用小括号来提升运算符的优先级

优先级运算符名称或含义使用形式结合方向说明
1[]数组下标数组名[常量表达式]左到右
()圆括号(表达式)/函数名(形参表)
.成员选择(对象)对象.成员名
->成员选择(指针)对象指针->成员名
2+正号运算符+表达式右到左单目运算符
-负号运算符-表达式单目运算符
(类型)强制类型转换(数据类型)表达式
++前置自增运算符++变量名单目运算符
++后置自增运算符变量名++单目运算符
--前置自减运算符--变量名单目运算符
--后置自减运算符变量名--单目运算符
*取值运算符*指针变量单目运算符
&取地址运算符&变量名单目运算符
!逻辑非运算符!表达式单目运算符
~按位取反运算符~表达式单目运算符
sizeof长度运算符sizeof(表达式)
3/表达式/表达式左到右双目运算符
*表达式*表达式双目运算符
%余数(取模)整型表达式/整型表达式双目运算符
4+表达式+表达式左到右双目运算符
-表达式-表达式双目运算符
5<<左移变量<<表达式左到右双目运算符
>>右移变量>>表达式双目运算符
6>大于表达式>表达式左到右双目运算符
>=大于等于表达式>=表达式双目运算符
<小于表达式<表达式双目运算符
<=小于等于表达式<=表达式双目运算符
7==等于表达式==表达式左到右双目运算符
!=不等于表达式!=表达式双目运算符
8&按位与表达式&表达式左到右双目运算符
9^按位异或表达式^表达式左到右双目运算符
10|按位或表达式|表达式左到右双目运算符
11&&逻辑与表达式&&表达式左到右双目运算符
12||逻辑或表达式||表达式左到右双目运算符
13?:条件运算符表达式1?表达式2:表达式3右到左三目运算符
14=赋值运算符变量=表达式右到左
/=除后赋值变量/=表达式
*=乘后赋值变量*=表达式
%=取模后赋值变量%=表达式
+=加后赋值变量+=表达式
-=减后赋值变量-=表达式
<<=左移后赋值变量<<=表达式
>>=右移后赋值变量>>=表达式
&=按位与后赋值变量&=表达式
^=按位异或后赋值变量^=表达式
|=按位或后赋值变量|=表达式
15,逗号运算符表达式,表达式,…左到右从左向右顺序运算
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值