5.1.概念
明确:计算机程序最终玩内存,内存存的是数字(二进制数字),并且这些数字之间可以
做运算,例如:加减乘除等,最终就是程序将内存中的数据做各种运算操作
运算符:对内存中的数字进行各种运算的符号,例如:+,-等
表达式:运算符和数字结合起来的式子,称之为表达式,例如:1+1
5.2.C语言的运算符
1)算数运算符:加,减,乘,除,取余,对应的符号:+,-,*,/,%
注意:
1.如果参与除法计算的两个数字是整型数则计算结果只保留整数部分
例如:5/2=2
2./和%不能对整数0进行操作,否则程序崩溃
例如:5/0, 5%0
3.%不能对浮点数使用
例如:5%1.1,否则程序崩溃
4.%的结果与其左边的数字符号一致
例如:-7%2=-1 7%-2=1
5./如果除数为浮点数,最后得到inf无穷大
例如:5/0.0
2)赋值运算符:=,就是将右边的值给左边的变量,也就是将变量对应的内存数字进行改变
形式1:
int a;
a = 10;
形式2:
int a, b, c;
a = b = c = 10;
printf("%d %d %\n", a, b, c); //10 10 10
形式3:复合运算符:赋值运算符和其他运算符结合起来使用
例如:
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;
注意实现:不能给常量(不可改变的数字)和表达式赋值
100 = 200; //gcc报错
100 = a; //gcc报错
a+b = c; //gcc报错
3)自增运算符(++)和自减运算符(--)
1.定义
自增运算符就是让变量对应的内存数值加1
自减运算符就是让变量对应的内存数值减1
2.四种形式:
前++:先对变量的值加1,后计算表达式的值
例如:
int a = 1;
int b = 0;
b = ++a;
printf("a = %d, b = %d\n", a, b); //a = 2, b = 2
后++:先计算表达式的值,后对变量的值加1
例如:
int a = 1;
int b = 0;
b = a++;
printf("a = %d, b = %d\n", a, b); //a = 2, b = 1
前--:先对变量的值减1,后计算表达式的值
例如:
int a = 2;
int b = 0;
b = --a;
printf("a = %d, b = %d\n", a, b); //a = 1, b = 1
后--:先计算表达式的值,后对变量的值减1
例如:
int a = 2;
int b = 0;
b = a--;
printf("a = %d, b = %d\n", a, b); //a = 1, b = 2
3.不要对常量进行自增自减运算
100++; //报错
++100; //报错
4)关系运算符:
==等于/!=不等于/>大于/<小于/>=大于等于/<=小于等于
注意:
1.关系运算符的运算结果是整数:1(真)或者0(假)
2.不要进行以下类似的逻辑判断(连续的逻辑判断)
例如:8<7<5,结果总是为1(真)
因为先算8<7,结果为0,而0有小于5,结果为1
问:如何解决类似问题呢?如何实现8,7,5之间的关系呢?
答:必须采用逻辑运算符
5)逻辑(真真假假,假假真真)运算符
a)明确:计算机中的真就是非0(包括1),0就是假
逻辑运算符作用:实现计算机程序中的逻辑判断
例如:当用户名和密码都对了,才能登陆
登陆方式可以是微信或者手机号后者抖音号等
b)逻辑运算符类型:三类
1.逻辑与: &&(并且,与此同时的意思)
2.逻辑或: ||(或者的意思)
3.逻辑非: !(对着干的意思)
c)逻辑与&&运算符特点
使用语法:C=表达式A && 表达式B
语义:只有当A和B的值都为真(非0),整个表达式C的值才为真
只要有一个为假,整个表达式C的值都为假
例如:1 && 1; //整个表示式结果为真
0 && 1; //假
1 && 0; //假
0 && 0; //假
d)逻辑或||运算符特点
使用语法:C=表达式A || 表达式B
语义:只要A和B中有一个为真,整个表达式C的值都为真
只有当A和B都是假,结果才能是假
例如:0 || 0; //假
1 || 0; //真
0 || 1; //真
1 || 1; //真
e)逻辑非运算符特点
使用语法:!表达式A
语义:A假结果为真,A真结果为假
例如:
!0;//结果为假
! 0;//结果为真
f)切记:短路运算(笔试题必考)
形式1.A && B:如果A的值为假,则B不处理,B的代码不执行
例如:
int a = 1;
0 && ++a;
printf("a = %d\n", a); //a=1
int b = 1;
250 && ++b;
printf("b = %d\n", b); //b=2
形式2.A || B: 如果A的值为真,则B不处理,B的代码不执行
例如:
int a = 1;
0 || ++a;
printf("a = %d\n", a); //a=2
int b = 1;
250 || ++b;
printf("b = %d\n", b); //b=1
6)位(bit)运算符
a)计算机中所有的数据(数字)都是内存中,并且都是以二进制的形式存放(1或者0,bit位)
而8,10,16进制仅仅是对二进制数的一种人为的友好表示形式(给人看的)
b)位运算符作用:位运算就是对内存中的二进制数进行运算,并且C语言专门提供对应的
运算符,简称位运算符
c)位运算符四种形式:
位与:&(清0)
位或: |(置1)
位异或: ^(反转)
位反: ~(取反)
d)位与运算符特点:
1.语法:C = A & B;
例如:
A: 01011010 0x5a
B: 11100011 0xe3
&-------------------
C: 01000010 0x42
2.规律:任何数跟0做位与,结果为0,任何数跟1做位与,保持原值
3.切记切记切记应用场合:一般用于将某个数的某个bit位清0,并且保持其他位不变
例如:将0x5a这个数的第3位清0: 0x5a & 0xf7
76543210 二进制编号
A:0x5a 01011010
B : 0xf7 11110111
C: 0x52 01010010
例如:将0x5a这个数的第3位和第4位清0: 0x5a & 0xE7
76543210 二进制编号
A:0x5a 01011010
B : 0xE7 11100111
C: 0x42 01000010
e)位或运算特点
1.语法格式:C = A | B;
例如:
A: 01011010 0x5a
B: 11100011 0xe3
|-------------------
C: 11111011 0xfb
2.规律:任何数跟1做位或,结果为1,任何数跟0做位或,保持原值
3.切记切记切记应用场合:一般用于将某个数的某个bit位置1,并且保持其他位不变
例如:将0x5a这个数的第2位置1: 0x5a | 0x04
76543210 二进制编号
A:0x5a 01011010
B : 0x04 00000100
C: 0x5e 01011110
例如:将0x5a这个数的第1,2位置1: 0x5a | 0x06
76543210 二进制编号
A:0x5a 01011010
B : 0x06 00000110
C: 0x5e 01011110
f)位异或运算特点:^
1.语法:C = A ^ B;
例如:
A: 01011010 0x5a
B: 11100011 0xe3
^-------------------
C: 10111001 0xb9
2.规律:相同为0,不同为1,应用于取反场合
g)位反运算符特点:~
1.语法:C=~A;
例如:
A: 01011010 0x5a
~A:10100101 0xa5
2.规律:0变1,1变0
3.注意:位反(~)运算符一般和位与(&)结合起来实现将某个数的某个bit清0操作
7)移位运算符
a)功能:就是将二进制数统一向左或者向右移动n个位置(简称左移,右移)
b)移位运算符种类:两种
左移:A<<B
语义:将A左移B个位置
右移 : A>>B
语义:将A右移B个位置
例如:
1 << 3:将1左移3位
3 >> 1:将3右移1位
c)移位运算符特点:
1.向左移动后右边空出来的数据用0来填充
例如:A数据前提是char类型
A=0x5A = 01011010
A << 2 = 01011010 << 2 结果为: 01101000 = 0x68
2. 无符号类型数字右移时左边空出来的数据用0来填充
例如:01011010 >> 2 结果为:00010110 = 0x16
3.有符号类型数字右移时左边空出来的数据用符号位填充
例如:10100101(前提是char类型) >> 2 结果为: 11101001 = 0xE9
4.左移n位相当于乘以2的n次方
5.右移n位相当于除以2的n次方
d)切记切记切记:
1.重点掌握左移
2.如果程序中将来涉及乘或者除2的n次方运算,务必用左移或者右移(高薪)
严重鄙视用*或者/,因为后者的执行效率相当低下!
例如:
int a = 1;
int b = a * 4; //垃圾代码
int b = a << 2; //高薪代码
3.不管是位运算符(&,|,^,~)还是左移,右移他们都不会改变变量本身的值!
例如:
int a = 3;
int b = a << 1;
printf("a = %d, b = %d\n", a, b); //a = 3, b = 6
e)切记实际开发常用的位操作公式:
需求就两个:
清0公式:
1.将某个变量的某1个位清0,其他位保持不变
A &= ~(1 << 位编号); //类似:A = A & ~(1 << 位编号)
2.将某个变量的某2个连续的位清0,其他位保持不变
A &= ~(3 << 位编号);
3.将某个变量的某3个连续的位清0,其他位保持不变
A &= ~(7 << 位编号);
4.将某个变量的某4个连续的位清0,其他位保持不变
A &= ~(0xF << 位编号);
置1公式:
1.将某个变量的某1个位置1,其他位保持不变
A |= (1 << 位编号);
2.将某个变量的某2个连续的位置1,其他位保持不变
A |= (3 << 位编号);
3.将某个变量的某3个连续的位置1,其他位保持不变
A |= (7 << 位编号);
4.将某个变量的某4个连续的位置1,其他位保持不变
A |= (0xF << 位编号);
8)取地址运算符&和解引用运算符*
a)明确地址特性:计算机中地址由32位二进制数组成,也就是一个地址32位,4字节
b)取地址运算符&作用:获取一个变量在内存对应的首地址
占位符%p用来显示地址信息
c)取地址运算符&使用语法格式:&变量名;
例如:
int a = 250; //分配4字节内存空间并且放一个250数字
printf("变量a的首地址为%p\n", &a);
d)解引用运算符*作用:根据变量的首地址获取内存中的数据
或者根据变量的首地址向内存写入新数据
e)解引用运算符*语法是:*地址 结果可以操作内存了
例如:
int a = 250;
printf("a的首地址%p\n", &a);
printf("a的值是%d\n", *&a); //通过地址获取变量的值
*&a = 520; //根据变量a的地址找到a的内存,然后向内存写入一个新数520
9)条件运算符(又称三目运算符)
a)语法格式:整个表达式结果D = 条件表达式A ? 表达示B : 表达式C
语义:如果A为真,D=表达式B的运算结果,否则D=表达式C的运算结果
例如:
int a = 1 ? 2 : 3; //a=2
案例:输入一个负数,求它的绝对值
5.3.注意运算符的优先级
例如:
printf("%d\n", 2+3*2); //8
printf("%d\n", (2+3)*2); //10
结论:()它的优先级最高,不嫌多
例如:
int a;
a = 1 > 2 && 2 < 3;
等价于:
a = (1 > 2) && (2 << 3);