主页 > IT业界  > 

【C语言】第二期——运算符与表达式

【C语言】第二期——运算符与表达式
目录

1 算术运算符

1.1 加减乘除取余 

1.2 a++ 与 ++a 的区别 

1.3 优先级

2 赋值运算符

2.1 复杂的赋值运算

3 关系运算符

4 逻辑运算符

4.1 逻辑与运算短路

4.2 逻辑或运算符

5 条件运算符(三元运算符)与条件表达式

6 特殊运算符 

6.1 求字节数运算符(sizeof)

6.2 强制类型转换运算符

7 进制(位运算符前言)

7.1 C语言进制介绍

7.2 不同进制的表示

7.2.1 二进制

7.2.2 八进制

7.2.3 十六进制

7.3 不同进制的printf占位符

8 位运算符

8.1 按位与、按位或、按位异或

8.2 按位取反 、反码、补码

8.3 移位符

9 优先级


C语言常用的运算符: 算术运算符 赋值运算符 关系运算符 逻辑运算符 条件运算符 类型转换运算符 求字节数运算符 位运算符 ...

1 算术运算符 运算符描述+把两个操作数相加-从第一个操作数中减去第二个操作数*把两个操作数相乘/分子除以分母%取模运算符,整除后的余数++自增运算符,整数值增加 1--自减运算符,整数值减少 1
1.1 加减乘除取余  //加 #include<stdio.h> int main() { int a = 10; int b = 20; printf("a+b=%d\n", a + b); // 变量相加 printf("a+1=%d\n", a + 1); // 变量与常量相加 printf("1+1=%d\n", 1 + 1); // 常量与常量相加 return 0; }

运行结果: a+b=30

a+1=11

1+1=2 

//减 #include <stdio.h> int main() { int a = 10; int b = 20; printf("b-a=%d\n", b - a); // 变量相减 printf("a-1=%d\n", a - 1); // 变量与常量相减 printf("3-1=%d\n", 3 - 1); // 常量与常量相减 return 0; }

运行结果:

b-a=10

a-1=9

3-1=2

//乘 #include <stdio.h> int main() { int a = 10; int b = 20; printf("b*a=%d\n", b * a); // 变量相乘 printf("a*1=%d\n", a * 1); // 变量与常量相乘 printf("3*1=%d\n", 3 * 1); // 常量与常量相乘 return 0; }

运行结果:

b*a=200

a*1=10

3*1=3

//除 #include<stdio.h> int main() { int a = 10; int b = 20; printf("b/a =%d\n", b / a); printf("a/1 =%d\n", a / 1); printf("20/10=%d\n", 20 / 10); printf("b/6 =%d\n", b / 6); printf("b/6.0 =%lf\n", b / 6.0); printf("20/6 =%d\n", 20 / 6); printf("20/6.0=%lf\n", 20 / 6.0); return 0; }

运行结果:

b/a =2

a/1 =10

20/10=2

b/6 =3

b/6.0 =3.333333

20/6 =3

20/6.0=3.333333

//取余 #include <stdio.h> int main() { int a = 6; int b = 20; printf("%d\n", b % a); printf("%d\n", a % 5); printf("%d\n", 20 % 3); printf("%d\n", 20 % 4); return 0; }

运行结果:

2

1

2

0


1.2 a++ 与 ++a 的区别  #include <stdio.h> int main() { printf("先赋值后运算:\n"); int c; int a = 10; c = a++; printf("Line 1 - c 的值是 %d\n", c ); printf("Line 2 - a 的值是 %d\n", a ); a = 10; c = a--; printf("Line 3 - c 的值是 %d\n", c ); printf("Line 4 - a 的值是 %d\n", a ); //—————————————————————————————————————————————————————————————— printf("先运算后赋值:\n"); a = 10; c = ++a; printf("Line 5 - c 的值是 %d\n", c ); printf("Line 6 - a 的值是 %d\n", a ); a = 10; c = --a; printf("Line 7 - c 的值是 %d\n", c ); printf("Line 8 - a 的值是 %d\n", a ); }

运行结果: 先赋值后运算:

Line 1 - c 的值是 10

Line 2 - a 的值是 11

Line 3 - c 的值是 10

Line 4 - a 的值是 9

先运算后赋值:

Line 5 - c 的值是 11

Line 6 - a 的值是 11

Line 7 - c 的值是 9

Line 8 - a 的值是 9


1.3 优先级

当算术表达式由多个不同的算术运算符组成时,会按照运算符的优先级进行运算:

先乘除后加减、先括号里再括号外,

优先级相同,按照自左向右的顺序进行运算

分析:a*10+(100%3)-b/10 的值

#include <stdio.h> int main() { int a = 12; int b = 100; printf("%d", a * 10 + (100 % 3) - b / 10); }
2 赋值运算符 运算符描述实例=简单的赋值运算符,把右边操作数的值赋给左边操作数C = A + B 将把 A + B 的值赋给 C+=加且赋值运算符,把右边操作数加上左边操作数的结果赋值给左边操作数C += A 相当于 C = C + A-=减且赋值运算符,把左边操作数减去右边操作数的结果赋值给左边操作数C -= A 相当于 C = C - A*=乘且赋值运算符,把右边操作数乘以左边操作数的结果赋值给左边操作数C *= A 相当于 C = C * A/=除且赋值运算符,把左边操作数除以右边操作数的结果赋值给左边操作数C /= A 相当于 C = C / A%=求模且赋值运算符,求两个操作数的模赋值给左边操作数C %= A 相当于 C = C % A

可以运行一下以下代码: 

#include<stdio.h> int main() { int a; int b; int c; a = 20; // 将数值 20 赋值给变量 a b = a - 10; // 先计算 a-10,然后将计算结果赋值给变量 b c = a + b; // 先计算 a+b,然后将计算结果赋值给变量 c printf("a=%d\n", a); printf("b=%d\n", b); printf("c=%d\n", c); return 0; } #include <stdio.h> int main() { int a = 21; int c; c = a; printf("Line 1 - = 运算符实例,c 的值 = %d\n", c); c += a; printf("Line 2 - += 运算符实例,c 的值 = %d\n", c); c -= a; printf("Line 3 - -= 运算符实例,c 的值 = %d\n", c); c *= a; printf("Line 4 - *= 运算符实例,c 的值 = %d\n", c); c /= a; printf("Line 5 - /= 运算符实例,c 的值 = %d\n", c); c = 200; c %= a; printf("Line 6 - %%= 运算符实例,c 的值 = %d\n", c); }
2.1 复杂的赋值运算 #include<stdio.h> int main() { int a = 1; int b = 2; a += b * 20; b %= a + 10; printf("a=%d\n", a); printf("b=%d\n", b); return 0; }

运行结果: a=41

b=2


3 关系运算符

关系运行符中输出1表示真,输出0表示假。

运算符描述实例==检查两个操作数的值是否相等,如果相等则条件为真。(A == B) 为假!=检查两个操作数的值是否相等,如果不相等则条件为真。(A != B) 为真>检查左操作数的值是否大于右操作数的值,如果是则条件为真。(A> B) 为假<检查左操作数的值是否小于右操作数的值,如果是则条件为真。(A < B) 为真>=检查左操作数的值是否大于或等于右操作数的值,如果是则条件为真。(A>= B) 为假<=检查左操作数的值是否小于或等于右操作数的值,如果是则条件为真。(A <= B) 为真 #include <stdio.h> int main() { int a = 10; int b = 20; int c = 30; printf("%d\n", 1 > 2); printf("%d\n", 5 >= 2); printf("%d\n", a < 2); printf("%d\n", a <= b); printf("%d\n", a + b == c); printf("%d\n", c != a + b); return 0; }

运行结果: 0

1

0

1

1

0


4 逻辑运算符 运算符描述实例&&称为逻辑与运算符。如果两个操作数都非零,则条件为真。(A && B) 为假||称为逻辑或运算符。如果两个操作数中有任意一个非零,则条件为真。(A || B) 为真!称为逻辑非运算符。用来逆转操作数的逻辑状态。如果条件为真则逻辑非运算符将使其为假。!(A && B) 为真 #include<stdio.h> int main() { int gender = 1; // gender 性别: 1 表示男, 0 表示女 int adult = 1; // adult 是否成年: 1 表示成年, 0 表示未成年 printf("%d\n", gender && adult); printf("%d\n", gender || adult); printf("%d\n", !gender); printf("%d\n", !adult); getchar(); return 0; } #include <stdio.h> int main() { int a = 5; int b = 20; printf("%d\n", a && b); printf("%d\n", a || b); printf("%d\n", !a); }
4.1 逻辑与运算短路

当“&&”左侧为“假”时,逻辑与运算表达式结果直接为“假”,“&&”右侧将不再进行判断

#include <stdio.h> int main() { int a = 8; int b = (a > 5) && ((a = a + 5) < 10); printf("b=%d\n", b); printf("a=%d", a); return 0; }

运行结果:

b=0

a=13

#include <stdio.h> int main() { int a = 8; int b = (a < 5) && ((a = a + 5) < 10); printf("b=%d\n", b); printf("a=%d", a); return 0; }

运行结果:

b=0

a=8


4.2 逻辑或运算符

当“||”左侧为“真”时,逻辑或运算表达式结果直接为“真”,“||”右侧将不再进行判断

#include <stdio.h> int main() { int a = 8; int b = (a < 5) || ((a = a + 5) < 10); printf("b=%d\n", b); printf("a=%d", a); return 0; }

运行结果:

b=0

a=13

#include <stdio.h> int main() { int a = 8; int b = (a > 5) || ((a = a + 5) < 10); printf("b=%d\n", b); printf("a=%d", a); return 0; }

运行结果:

b=1

a=8


5 条件运算符(三元运算符)与条件表达式

条件运算符又被称为三元运算符,是C语言中唯一的一个三元运算符,基本格式如下:

表达式1 ? 表达式2 : 表达式3 max = a>b ? a : b

其求值规则为:如果表达式1的值为真,则以表达式2 的值作为整个条件表达式的值,否则以表达式3的 值作为整个条件表达式的值。条件表达式通常用于赋值语句之中。 

#include <stdio.h> int main() { int a = 9; nt b = 0; b = (a > 10 ? 888 : 666); printf("b=%d\n", b); b = (a > 5 ? 888 : 666); printf("b=%d\n", b); return 0; }
6 特殊运算符  6.1 求字节数运算符(sizeof)

c语言中,使用sizeof运算符可以获取一个数据类型或者一组数据类型的字节数。

例如,sizeof(int)会返回4,因为int类型通常占据4个字节。

#include<stdio.h> int main() { printf("sizeof(char) =%d\n", sizeof(char)); printf("sizeof(int) =%d\n", sizeof(int)); printf("sizeof(float) =%d\n", sizeof(float)); printf("sizeof(double)=%d\n", sizeof(double)); return 0; }

运行结果:

sizeof(char) =1

sizeof(int) =4

sizeof(float) =4

sizeof(double)=8


6.2 强制类型转换运算符

强制类型转换运算符由括号“( )“和数据类型两部分构成,形为:(数据类型)

其一般使用形式为:

(数据类型)常量; (数据类型)变量; (数据类型)(表达式);

其作用是将常量、变量、表达式运算结果等,转换为括号中的指定数据类型

#include <stdio.h> int main() { int a; float f; a = (int)3.14; f = (float)(10 + 20); printf("a=%d\n", a); printf("f=%f\n", f); return 0; }

运行结果:

a=3 f=30.000000


7 进制(位运算符前言)

位运算符通常用于进行二进制操作

在了解位运算符前我们首先需要知道什么是10进制、2进制 、16进制

7.1 C语言进制介绍

对于计算机来说,本质上只能识别和执行0和1组成的二进制指令,例如:

0101 1111 0000 0000

在嵌入式系统开发中,16进制和二进制通常用于将数据转换为易于处理的形式。

例如,在嵌入式系统中使用16进制可以更容易地处理数据和变量,因为大多数硬件都支持16进制。

同样,二进制是嵌入式系统中最常用的编码方式之一,因为它可以轻松地与CPU指令集配合使用,并且可以更好地控制内存访问等操作 。

十进制二进制十六进制十进制二进制十六进制000000810008100011910019200102101010A300113111011B401004121100C501015131101D601106141110E701117151111F

我们都知道10进制逢10进1

同理:

二进制是逢2进1,一般我们用四位为一组表示一个二进制数

16进制是逢16进1,一般嵌入式中我们用一个16进制数表示一组二进制数


7.2 不同进制的表示 7.2.1 二进制

二进制由 0 和 1 两个数字组成,使用时必须以0b或0B(不区分大小写)开头

例如:

//合法的二进制 int a = 0b101; //换算成十进制为 5 int b = -0b110010; //换算成十进制为 -50 int c = 0B100001; //换算成十进制为 33 //非法的二进制 int m = 101010; //无前缀 0B,相当于十进制 int n = 0B410; //4不是有效的二进制数字

注意:标准的C语言并不支持上面的二进制写法,只是有些编译器自己进行了扩展,才支持二进制数字。换句话说,并不是所有的编译器都支持二进制数字,只有一部分编译器支持,并且跟编译器的版本有关系。


7.2.2 八进制

八进制由 0~7 八个数字组成,使用时必须以0开头

//合法的八进制数 int a = 015; //换算成十进制为 13 int b = -0101; //换算成十进制为 -65 int c = 0177777; //换算成十进制为 65535 //非法的八进制 int m = 256; //无前缀 0,相当于十进制 int n = 03A2; //A不是有效的八进制数字
7.2.3 十六进制

十六进制由数字 0~9、字母 A~F 或 a~f(不区分大小写)组成,使用时必须以 0x 或 0X(不区分大小写)开头

例如:

//合法的十六进 int a = 0X2A;  //换算成十进制为 42 int b = -0XA0;  //换算成十进制为 -160 int c = 0xffff;  //换算成十进制为 65535 //非法的十六进制 int m = 5A;  //没有前缀 0X,是一个无效数字 int n = 0X3H;  //H不是有效的十六进制数字
7.3 不同进制的printf占位符

%d 可以以十进制输出整数、%o可以以八进制输出整数、%X可以以16进制输出整数

%x和%X这两个占位符中x的大小写会决定输出十六进制数时字母部分的大小写

#include <stdio.h> #include <stdlib.h> int main() { int a = 12; printf("八进制 --> %o\n", a); printf("十六进制 --> %X\n", a); printf("十进制 --> %d\n", a); char s[16]; itoa(a, s, 2); printf("二进制 --> %s\n", s); return 0; }
8 位运算符 运算符描述&按位与:对两个操作数的每一位执行逻辑与操作,如果两个相应的位都为 1,则结果为 1,否则为 0。按位与操作,按二进制位进行 “与” 运算。运算规则:0 & 0 = 0; 0 & 1 = 0; 1 & 0 = 0; 1 & 1 = 1;|按位或:对两个操作数的每一位执行逻辑或操作,如果两个相应的位都为 0,则结果为 0,否则为 1。按位或运算符,按二进制位进行 “或” 运算。运算规则:0 | 0 = 0; 0 | 1 = 1; 1 | 0 = 1;1 | 1 = 1;^按位异或:对两个操作数的每一位执行逻辑异或操作,如果两个相应的位值相同,则结果为 0,否则为 1。异或运算符,按二进制位进行 “异或” 运算。运算规则:0^0=0; 0^1=1; 1^0=1; 1^1=0;~按位取反:对操作数的每一位执行逻辑取反操作,即将每一位的 0 变为 1,1 变为 0。取反运算符,按二进制位进行 “取反” 运算。运算规则:~1=-2; ~0=-1;(详看补码系统)<<按位左移:将操作数的所有位向左移动指定的位数。左移 n 位相当于乘以 2 的 n 次方。二进制左移运算符。将一个运算对象的各二进制位全部左移若干位(左边的二进制位丢弃,右边补 0)。>>按位右移:将操作数的所有位向右移动指定的位数。右移 n 位相当于除以 2 的 n 次方。二进制右移运算符。将一个数的各二进制位全部右移若干位,正数左补 0,负数左补 1,右边丢弃。
8.1 按位与、按位或、按位异或 #include <stdio.h> #include <stdlib.h> int main() { char a = 0b00000001; // 相当于10进制1 char b = 0b00001001; // 相当于10进制9 printf("a对应的10进制%d\n", a); printf("b对应的10进制%d\n", b); // 00000001 & 00001001=00000001 如果两个相应的位都为 1,则结果为 1 printf("a&b 按位与值%d\n", a & b); // 00000001 & 00001001=00001001 如果两个相应的位都为 0,则结果为 0 printf("a|b 按位或的值%d\n", a | b); // 00000001 ^ 00001001=00001000 如果两个相应的位值相同,则结果为 0 printf("a^b 按位异或的值%d\n", a ^ b); }
8.2 按位取反 、反码、补码

对操作数的每一位执行逻辑取反操作,即将每一位的 0 变为 1,1 变为 0

如 0 000 0001 按照位取反后得到的二进制位 1111 1110

如 0 000 1001 按照位取反后得到的二进制位 1111 0110

#include <stdio.h> #include <stdlib.h> int main() { char a = 0b00000001; // 相当于10进制1 printf("a按位取反的十进制值是%d\n", ~a); char b = 0b00001001; // 相当于10进制9 printf("b按位取反的十进制值是%d", ~b); }

输出结果为: a按位取反的十进制值是-2

b按位取反的十进制值是-10

问题: 这个结果和我们上面想要的结果出入很大,为什么呢?

原因:在计算机中数据是以其补码形式存储和运算的 。

首先补充几个概念:

机器数:数值在计算机中的二进制表示形式,机器数通常使用最高位作为符号位,一般规定 0 表示正数,1 表示负数

真值:一个数在数学中的实际数值

原码:一种最简单的机器数表示法。最高位为符号位,其余位表示数值的绝对值。符号位用 0 表示正数,用 1 表示负数。(可进行无符号计算)

反码:反码的符号位与原码相同,正数的反码和原码相同;负数的反码是在原码的基础上,符号位不变,其余各位按位取反。(可参与符号计算,但会出现-0的情况,即11111111)

补码:正数的补码和原码、反码相同;负数的补码是在其反码的基础上加 1。补码解决了原码在加减法运算中的问题,使得计算机可以使用加法器统一进行加法和减法运算。

(可参与符号计算,排除了-0的情况)

在上文代码中,a变量存储的值0000 0001首位为0,为正数,所以其反码补码都是0000 0001

我们提到,在计算机中数据是以补码形式参与计算的,所以在其参与计算(取反计算)后,得到的数还是补码 1111 1110 ,

最终我们是让其以十进制打印出结果,即打印真值,而此时还是补码,因此我们要将补码转成原码(因为原码可以直观转化为真值)

操作为原码转补码的逆运算:

第一步:1111 1110先减一,得到1111 1101(此时为反码)

第二步:再将其除了符号位都取反,即 1000 0010(此时为原码)

第三步:原码即可转化为真值

1000 0010,首位为1,为负数,剩下七位转成十进制为2,所以最终显示-2

注意:补码先加一再取反效果与上述一样,但不便于理解,不推荐

视频教程:

【一听就懂】C语言必会之原码/反码/补码!分析+实例,十分钟带你彻底掌握,这可比学校讲的细致多了!_哔哩哔哩_bilibili


8.3 移位符

<< 按位左移:

将一个运算对象的各二进制位全部左移若干位(左边的二进制位丢弃,右边补0)

>> 按位右移:

将一个数的各二进制位全部右移若干位

注意所移动的值最高位是否表示符号,以及移动过后正负性的改变

#include <stdio.h> int main() { char a = 0b00001000; // 0000 1000 左移2位0010 0000 printf("a按位左移2位后的的十进制值是%d\n", a << 2); // 0000 1000 右移动2位 0000 0010 }
9 优先级

下表将按运算符优先级从高到低列出各个运算符

(具有较高优先级的运算符出现在表格的上面,具有较低优先级的运算符出现在表格的下面)

在表达式中,较高优先级的运算符会优先被计算

表格里的 “结合性” 指的是当一个表达式中有多个相同的运算符时,运算执行的方向

类别运算符结合性后缀() [] ->. ++ --从左到右一元+ -! ~ ++ -- (type)* & sizeof从右到左乘除* / %从左到右加减+ -从左到右移位<< >>从左到右关系< <= > >=从左到右相等== !=从左到右位与 AND&无位异或 XOR^无位或 OR**无逻辑与 AND&&无逻辑或 OR||无条件?:从右到左赋值=  +=  -=  *=  /=  %=  >>=  <<=  &=  ^=  |=从右到左逗号,无
标签:

【C语言】第二期——运算符与表达式由讯客互联IT业界栏目发布,感谢您对讯客互联的认可,以及对我们原创作品以及文章的青睐,非常欢迎各位朋友分享到个人网站或者朋友圈,但转载请说明文章出处“【C语言】第二期——运算符与表达式