英文:
clear:清0
set:置1
change:反转
shift:移位
abs:absolute:绝对值
回顾:
1.数据类型
1.1.功能:预算变量占内存大小
1.2.12大数据类型:char…double
1.3.字符类型:本质就是单字节整数(ASCII码)
1.4.整型类型:六种形式
1.5.浮点类型
1.6.数据类型和占位符
%c,%hhd,%hd,%hu,%d,%u,%ld,%lu,%f,%lf,%g,%lg
注意回滚rollback现象
1.7.常量
100,100L,100LL,100u,100UL
2.scanf函数
scanf("%c%d",&a,&b); //A 100
3.进制转换
bit(位)
符号位:前提是基于某种数据类型
数字表现形式四种:2,8(0%o),10,16(%#x,%#X)
2->8,8->2或者2->10,10->2:计算器完事
基本能力:心算:2->16,16->2
0101 1100 1101 1000 -> 0x5cd8
0xb487->1011 0100 1000 0111
4.运算符和表达式
运算符:实现计算机对内存中的数据进行数据运算
表达式:运算符和数字结合起来的式子
4.1.算数运算符:+ - * / %,注意事项
4.2.赋值运算符: = ,注意事项
4.3.复合运算符:赋值运算符和其他运算符结合使用,+= -=,*= /= %=
4.4.自增++,自减–运算符,四种形式
4.5.关系运算符:== != > < >= <=,运算结果:1(真)和0(假),注意事项
4.6.逻辑(真真假假,假假真真)运算符
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真结果为假
例如:
!1;//结果为假
!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
4.7.位(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操作
4.8.移位运算符
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 << 位编号);
提示:公式推导流程
31 15 7 0
1 << 0
0000 0000 0000 0000 0000 0000 0000 0001 //0x1
1 << 1
0000 0000 0000 0000 0000 0000 0000 0010 //0x2
1 << 2
0000 0000 0000 0000 0000 0000 0000 0100 //0x4
1 << 3
0000 0000 0000 0000 0000 0000 0000 1000 //0x8
1 << 4
0000 0000 0000 0000 0000 0000 0001 0000 //0x10
…
变形:
31 15 7 0
~(1 << 0)
1111 1111 1111 1111 1111 1111 1111 1110
~(1 << 1)
1111 1111 1111 1111 1111 1111 1111 1101
~(1 << 2)
1111 1111 1111 1111 1111 1111 1111 1011
~(1 << 3)
1111 1111 1111 1111 1111 1111 1111 0111
~(1 << 4)
1111 1111 1111 1111 1111 1111 1110 1111
…
现在有一个数据为0x5A:
0000 0000 0000 0000 0000 0000 0101 1010
要求将0x5A的第0位(bit0)清0,其余位保持不变:
0000 0000 0000 0000 0000 0000 0101 1010
&1111 1111 1111 1111 1111 1111 1111 1110 = ~(1 << 0)
结果:0x5A & 0xFFFFFFFE //垃圾,可读性很差
0x5A & ~(1 << 0) //可读性很好
要求将0x5A的第1位(bit1)清0,其余位保持不变:
0000 0000 0000 0000 0000 0000 0101 1010
&1111 1111 1111 1111 1111 1111 1111 1101 = ~(1 << 1)
结果:0x5A & 0xFFFFFFFD //垃圾,可读性很差
0x5A & ~(1 << 1) //可读性很好
要求将0x5A的第0位(bit1)置1,其余位保持不变:
0000 0000 0000 0000 0000 0000 0101 1010
| 0000 0000 0000 0000 0000 0000 0000 0001 = (1 << 0)
结果:0x5A | 0x1 //垃圾,可读性很差
0x5A | (1 << 0) //可读性很好
要求将0x5A的第1位(bit1)置1,其余位保持不变:
0000 0000 0000 0000 0000 0000 0101 1010
| 0000 0000 0000 0000 0000 0000 0000 0010 = (1 << 1)
结果:0x5A | 0x1 //垃圾,可读性很差
0x5A | (1 << 1) //可读性很
目的:要求将b的4,5,6,7,8位清0
int b = 0x12345678;
b &= ~(0x1F << 4);
b = b & ~(0x1F << 4);
0x1F:
0000 0000 0000 0000 0000 0000 0001 1111
0x1F << 4:
0000 0000 0000 0000 0000 0001 1111 0000
~(0x1F << 4):
1111 1111 1111 1111 1111 1110 0000 1111
b=0x12345678;
0001 0010 0011 0100 0101 0110 0111 1000
0x12345678 & ~(0x1F << 4):
1111 1111 1111 1111 1111 1110 0000 1111
&0001 0010 0011 0100 0101 0110 0111 1000
0001 0010 0011 0100 0101 0110 0000 1000 //结果:0x12345608
8 7654
目的:要求将b的4,5,6,7,8位置1
int b = 0x12345678;
b |= (0x1F << 4);
b = b | (0x1F << 4);
0x1F:
0000 0000 0000 0000 0000 0000 0001 1111
0x1F << 4:
0000 0000 0000 0000 0000 0001 1111 0000
b=0x12345678;
0001 0010 0011 0100 0101 0110 0111 1000
0x12345678 | (0x1F << 4):
0000 0000 0000 0000 0000 0001 1111 0000
&0001 0010 0011 0100 0101 0110 0111 1000
0001 0010 0011 0100 0101 0111 1111 1000 //结果:0x123457F8
8 7654
4.9.取地址运算符&和解引用运算符*
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
4.10.条件运算符(又称三目运算符)
a)语法格式:整个表达式结果D = 条件表达式A ? 表达示B : 表达式C
语义:如果A为真,D=表达式B的运算结果,否则D=表达式C的运算结果
例如:
int a = 1 ? 2 : 3; //a=2
案例:输入一个负数,求它的绝对值
4.11.注意运算符的优先级
例如:
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);
5.数据类型转换,分两种:隐式转换和强制转换
5.1.隐式转换特点:如果表达式中不同数字的数据类型不同,gcc编译器先将不同的数据类型
转换成相同的数据类型之后再做运算
隐式转换分三种情况:
a)隐式转换过程中必须把占内存小的类型转换成占内容大的类型
例如:
int a = 0, c; //各占4字节
char b = 2; //占1字节
c = a + b; //gcc编译器自动将b转换成int类型然后再和a做加运算
b)如果既有整型数据类型还有浮点数据类型,gcc编译器自动将整型数据类型转换成浮点类型
c)如果既有无符号数据类型还有有符号数据类型,gcc编译器自动将有符号转无符号数据类型
d)隐式转换的致命缺陷代码的可读性很差!
5.2.强制转换(建议使用的转换,目的:提高代码的可读性)
a)强制转换语法格式:目标类型变量 = (目标类型)源类型变量;
例如:
char a = 90;
int b = (int)a; //gcc强制将a转换成int类型在赋值给变量b
b)注意:强制数据类型转换可能会造成数据的丢失
例如:
char a = (char)300; //数据丢失了
printf(“a = %d\n”, a); //a=44 = 300(太大了) - 128 = 172(太大了)-128=44
所以:强制转换都是小转大,或者相等转
5.3.切记:不管哪种类型转换都不会修改变量本身的值
例如:
int a = 555;
char b = (char)a;
printf(“b = %d, a = %d\n”); //b = ? a = 555