本讲内容很丰富,都是非常重要的零基础C语言知识,涉及各种操作符的分类,具体用法,进制转换等等。
1. 操作符的分类
算数操作符:+ - * /(整除) %(取模)
移位操作符:<<(左移操作符) >>(右移操作符)
位操作符:&(按位与) |(按位或) ^(按位异或)
赋值操作符:=,+=,-=,*=,/=。%=,<<=,>>=,&=,|=,^=
单目操作符:!,++,--,&,*(解引用操作符),+(正),-(负),~(按位取反), sizeof(),()(强制类型转换)
关系操作符:> , >= , < , <= , == , !=
逻辑操作符:&&(逻辑与),||(逻辑或)
条件操作符:?:(excep1?excep2:exccep3)
逗号表达式:,(英文逗号)
下标引用操作符:[ ]
函数调用:( )
结构成员访问操作符:.(英文的点),->
2. 进制转换
2.1 二进制转换为十进制
以十进制为例,123对应的十进制数字可以表示为123 = 1 * 100 + 2 * 10 + 3 * 1
相应的,二进制1101对应的十进制可以表示为:1 * 8 + 1 * 4 + 0 * 2 + 1 * 1=13,所以1101的十进制数为13。
2.2 十进制转化为二进制
最简单的方法就是辗转相除法,具体操作方法如图所示。
2.3 二进制转化为八进制和十六进制
2.3.1 2进制转化为8进制
八进制数字是由0~7的数字组成的,每一位最多需要三个二进制位,具体步骤请看图。
2.3.2 2进制转化为16进制
同理,十六进制的每一位为0,1,2,3,4,5,6,7,8,9,(0~9)和a,b,c,d,e,f(a~f),每一位最多需要四个二进制位,画图解析,请看图。
3. 原码,反码,补码
正整数的原码,反码,补码相同,负整数的原码,反码,补码表示各不相同,转换方法如图:
对于整型来说,数据在内存中存储的是二进制补码
实例支撑巩固
4. 移位操作符
4.1 左移操作符
口诀:左边抛弃,右边补0.
int main()
{
int n = 10;
//原码0000000000000000000000000000000000001010
//反码0000000000000000000000000000000000001010
//补码0000000000000000000000000000000000001010(内存中存储的数据)
int a = n << 1;
//n<<1 0000000000000000000000000000000000010100(表达式的结果)
printf("%d\n",a );//20是表达式的值(也就是移位后的结果)
printf("%d\n", n);//10,移位后,n的值是不变的
return 0;
}
4.2 右移操作符
移位规则
算术右移:左边用该值的符号位填充,右边丢弃。
VS编译器下,使用的是算数右移
逻辑右移:左边用0填充,右边丢弃。
值得注意的是,无论是逻辑右移还是算术右移,正数的结果都是一样的,因此,下面,我们再用负整数来验证VS编译器采用的6是逻辑右移还是算术右移。
5. 位操作符:& | ^ ~
& 按位与 | 按位或 ^ 按位异或 ~ 按位取反,他们的操作数都必须是整数。
请看代码:
运用:例一 不创建临时变量就实现两个数的交换。
方法一:
画图分析
缺陷:如若a 和 b 的值非常大,则求和后的值容易超过整形的最大值。
方法二:
异或操作符的特点:相同为0,相异为1。
a ^ a = 0; 0 ^ a = a;
缺点:可读性不高
例二:求一个整数存储在内存中的二进制数中1的个数(内存中存放的是二进制的补码)
方法1:a & 1 == 1,则表示a的二进制数最低位为1
a & 1 == 0,则表示a的二进制数最低位为0
00000000000000000000000000001010 :10
00000000000000000000000000000001 :1
10 & 1 : 00000000000000000000000000000000,count不变
10最低位取掉,继续按位与1,结果为1,则count++
10右移一位, 00000000000000000000000000000101
再进行按位与 00000000000000000000000000000001
结果: 00000000000000000000000000000001,结果为1,count++,再进行移位,重复运算重复操作
方法2:把方法一整合
方法三:
根据实现结果发现:该程序对于负数的输出结果有差错,进行改正:改成有符号数unsigned int
这样才有考虑正负数的问题。
方法四:
n&(n-1)
例四:判断一个数是否是2的次方数
例三:二进制位置0或者置1
6. 单目操作符
常见单目操作符:!,++,--,&,*,+,-,~,sizeof(),(类型)(强制类型转换)
7. 逗号表达式
逗号表达式:从左向右依次计算(前面的运算可能会影响后面的运算),整个表达式的接过是最后一个表达式的结果。
代码1:
代码2:
代码三:
对代码进行修改优化:
8. 下标访问[ ],函数调用{}
8.1 下标引用操作符:[ ]和函数调用操作符
操作数:一个数组名+一个索引值(下标)
sizeof能省略括号,但是函数后面的括号是不能去掉的。因此sizeof()是操作符,而不是函数。
9. 结构成员访问操作符
9.1 结构体
C语言的内置类型:char,short,long,int ,float,doiuble等。但是光有他们是不够的,如描述一位学生,需要知道它的姓名,性别,年龄,身高,体重等多个信息混合一起所形成的描述一个复杂结构。因此C语言增加了结构体这种自定义类型。
结构是一些值的集合,这些值称为成员变量。结构的每一位成员可以是不同类型的变量,如:标量,数组,指针,甚至是其他的结构体。
9.1.1 结构的声明
形式:
struct tag
{
member - list;(成员列表)
}variable-list;(变量列表)
比如,描述一位学生:名字+年龄+成绩
如果不按照顺序初始化:
结构体套上一个结构体的变量初始化方法+打印方法:
结构成员访问操作符:. 。用法:结构体变量 . 成员名
9.1.2 结构体成员的间接访问
->使用方式:结构体指针->成员名
10. 操作符的属性:优先级和结合性
操作符用在表达式中用于计算
10.1 优先级
相邻操作符的优先级越高,越先被执行
10.2 结合性
如果两个操作符的优先级相同,则比较结合性。根据运算符是左结合还是右结合决定运算顺序。大部分运算符从左到右结合,少数运算符如赋值操作符是从右向左结合。
记忆重点(记住重要的,其他在使用时查表):按照优先级从高到低排序
圆括号()(圆括号的优先级最高,可以使用它改变其他运算符的优先级)
自增运算符++,自减运算符--
单目操作符+和-(正负号)
乘法*,除法/
加法+,减法-
关系运算符<,>
赋值运算符=
11. 表达式求值
11.1 整型提升
为什么要进行整型提升?
C语言中整型算术运算总是至少以缺省整形类型(默认int类型,4个字节)的精度来进行的。为了获得这个精度,表达式中的char(字符0),short(短整型)类型操作数就会被转换为普通整型(空间小的类型转换为空间较大的类型int,把范围扩大了,范围扩大,精度更高),这种转换称为整型提升。如:(字符是属于整型家族的,字符以ASCII码形式存储)
整型提升的意义:CPU内整型运算器(ALU)的操作数一般是int字节长度(即4Byte),同时也是通用寄存器的长度。表达式的整型运算就是在ALU中进行的,因此对于长度小于int类型长度的操作数,要进行转换,将其转换为int 或者 unsigned int类型(转换成CPU类型操作数的标准长度),再在CPU 中进行运算。
整型提升的方法:有符号整数提升按照变量的数据类型的符号位。
无符号整数提升,直接高位补0。
总结:在进行表达式求值时有char,short等类型大小比int小的类型时,要发生整型提升。(各个操作数属于同一数据类型)
11.2 算术转换
在进行表达式求值时,出现数据类型大小比int大或者相等的类型,并且出现不同的数据类型时,要发生算术转换。下面的层次体系称为寻常算术转换:(下面的转换成上面的)
long double
double
float
unsigned long int
long int
unsigned int
int
当出现两个不同类型的操作数时,排名靠后的操作数转换成排名靠前的操作数类型,再进行运算。
11.3 问题表达式解析
11.3.1 表达式1
a * b + c * d + e * f计算顺序:由于*的优先级比+高,但是优先级是在相邻两个操作符之间比较的。计算的顺序可能有:a * b,c * d,a * b + c * d,e * f,a * b + c * d + e * f。或者:a * b,c * d,e * f,a * b + c * d,a * b + c * d + e * f。
11.3.2 表达式2
c + --c;自减运算符的优先级比加法运算符高,因此先计算--。对于下面的代码,则有歧义:
A. c的值提前准备好了:c=5;先算--c(先减再用),得到c=4;再算c+(--c),得到c = 5(提前准备好) + 4 = 9;
B. c的值没有提前准备:c=5;先算--c,得到c = 4;再算c+(--c),得到c= 4(后面计算得到的) + 4 = 8;这是VS编译环境下的答案。
11.3.3 表达式3
这样的非法表达式辨析度不高,而且在不同的编译器下有不同的结果 。
11.3.4 表达式4
11.3.5 表达式5
VS环境下的计算结果:
gcc环境下的结果:10 4。