C语言:操作符详解

本讲内容很丰富,都是非常重要的零基础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。

  • 32
    点赞
  • 33
    收藏
    觉得还不错? 一键收藏
  • 10
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 10
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值