C语言相关概念和易错语法(3)(操作符)

前言:首先,我的博客主要记录的是部分容易遗忘,但是比较重要或是值得了解的知识点。很多基本概念我并不会阐述,所以它更适合用来复习;其次,这些知识点是从我自己的角度出发整理的,因此我认为的重点可能和你不同,有的内容可能不完整或有错误,希望大家多多包涵,如果能指出我的错误,我会非常感激!

必要知识点储备:

(1)二进制、八进制、十进制、十六进制之间的转换技巧

十进制转二进制:

对于比较大的数字,有一个通用的求解方法

如1000,将它先除以2得到500,余数0,记录这个0

将500除以2得到250,余数0,记录这个0

将250除以2得到125,余数0,记录这个0

将125除以2得到62,余数1,记录这个1

将62除以2得到31,余数0,记录这个0

将31除以2得到15,余数1,记录这个1

将15除以2得到7,余数1,记录这个1

将7除以2得到3,余数1,记录这个1

将3除以2得到1,余数1,记录这个1

将1除以2得到0,余数1,记录这个1,停止计算

最后从下到上按顺序写出记录的数字1111 1010 00,这个数就是二进制的1000

二进制转八进制、十六进制:

我们知道2的3次方是8,2的4次方是16,所以3个二进制位就可以表示成一个八进制位

如01 101 011从右向左每三个分一组,换算成十进制数字,这个数字对应八进制的数字

011表示3,101表示5,01表示1,所以这个数字的八进制表示是0135,最前面的0是八进制标志

十六进制同理,每四位一组

如0110 1011换算后是0x6b

(2)原码、补码的相互转换

原码转为补码将原码除符号位取反后+1(负数)

补码转为原码将补码除符号位取反后+1(负数),这种方法更方便

补码存在的意义是使加法减法统一,CPU只能进行加法运算

操作符易忘知识点和易错法则

其中简单的我不会阐述,我会抓出易忘点和易错点

1.移位操作符(左移操作符和右移操作符细则区分)

左移操作符执行规则:左边抛弃,右边补0。

因此对于负数来说,左移后就变成了正数(有且只有这一种可能)

右移操作符的执行规则就比左移操作符的要复杂,有两种操作方式;

(1)逻辑右移:左边用0填充,右边丢弃(类似于左移操作符)

(2)算数右移:左边用该值的原符号位填充,右边丢弃。这意味着在算数右移的规则下,负数右移后还是负数,而逻辑右移下,移后的数一定是正数。

对于绝大部分编译器来说,都是采用算数右移,仍有少部分编译器采用逻辑右移。

但是对于所有编译器来说,左移规则相同。这里一定要注意区分!

注意:a >> -1这种操作未被定义,不要用!

2.位操作符

操作的对象都是二进制的补码,且只能是整数,意思是你输入的17会被转换成二进制再操作

如果你输入-1,则实际操作数是-1的补码

& 按位与:只要有0就是0,全为1才是1

| 按位或:只要有1就是1,全为0才是0

^ 按位异或:相同为0,相异为1(易混)

~ 按位取反:将所有位按位取反,不管它是不是符号位,取反后得到的还是补码,因此如果要打印取反后的数字,还要进行一次补码到原码的转换

相关操作技巧

(1)^ 按位异或:

a ^ a == 0 ;  a ^ 0 == a

接下来通过这个代码仔细体会异或操作


#include <stdio.h>

int main()
{
	int a = 100;

	int b = 200;

	printf("a=%d b=%d\n", a, b);

	a = a ^ b;

	b = a ^ b;

	a = a ^ b;

	printf("a=%d b=%d\n", a, b);
	
    return 0;
}

结果

0bd22832cb2c4ef79c7e55599b12861a.png

重要思考方式:a ^ b相当于一个密码,储存了a和b的信息,如果我拿到b的信息,我就能破解a(将a ^ b这个密码与b异或);如果我拿到a的信息,我就能破解b(将a ^ b这个密码与a异或)

(2)& 按位与

a & 1 == 1说明a的二进制位中最低位是1

a & 1 == 0说明a的二进制位中最低位是0

注意比较的依然是补码

cfc2bab6e4e94b18b5277ecc18d9ca83.png

有一个表达式值得琢磨:


	n = n & (n - 1);

	11111 - n;
	11110 - n - 1;

	11110 - n;//第一次操作后
	11101 - n - 1;

	11100 - n;//第二次操作后
	11011 - n - 1;

	11000 - n;//第三次操作后
	10111 - n - 1;

	10000 - n;//第四次操作后
	01111 - n - 1;

	00000 - n;//第五次操作后

每执行一次,最右边的1就会被去掉,其余位不受影响

(3)& 和 | 修改二进制数操作

合理利用& 和 |可以调整二进制数

让0变成1用|,使用时保证你要变的那位是1,其余都是0,用1 << n来实现

让1变成0用&,使用时保证你要变得那位是0,其余都是1,用 ~( 1 << n )来实现

(4)自定义类型、结构成员访问

注意:int [10]是一个自定义类型,int arr[10]中arr是数组名

struct也是自定义类型,包含成员列表。它相当于一个模具,在实际使用时创建结构体变量。

struct在访问成员时,可用.name表示,点操作符有两个操作数,使用方式是“结构体名.成员名”。第一个不需要时可以不写。

初始化结构体变量时,要么按成员列表顺序创建,要么使用.name初始化。

(5)操作符的优先级、结合性

优先级:一个表达式中运算符优先级高的先执行

一定是相邻操作符才有所谓的优先级之分

如果相邻两个操作符优先级相同,则由结合性决定先后,一般是从左到右结合,但少数从右往左结合,比如赋值操作符=,具体的可查表,这里不再阐述

记住括号优先级最高,其次有自增自减操作符++和--,单目操作符+和-(决定数字正负)。

逗号表达式优先级最低,其次是赋值操作符。

注意:表达式的执行顺序可以被确定,但值的调用顺序不确定,所以当一个表达式中调用的值多次变化时会导致计算结果不确定。

如(i++)+(i++)+(i++)这个表达式的值在不同编译器下有不同解,因为i的调用可能是在++前,也可能是在++后

(6)整型提升(类型小于整型)和算术转换(类型大于整型且类型不同)

缺省整型指的是默认整型int

char中也可以存储数字,字符也是属于整型家族的,可以进行整型运算,只是能存储的大小很有限,你可以把它理解成更短的整型,取值是-128~127

有符号数的整型提升是按符号位提升,因此负数的整型提升补的全是1而不是0,char也有有无符号之分,但默认是不是有符号char得看系统,这个标准没有被定义。

注意整型提升以及之后参与运算的是补码,使用printf打印%d也会发生整型提升,是先提升补码,再转换为原码打印。

算术转换

当int和float相加时,int向float转换(向上转换)后再相加,加后存储的值仍为float类型

一般来说,算术转换的趋势是整型向浮点型转换,由字节少的类型向字节多的类型转换

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值