操作符和进制

目录

一,操作符的分类

二,一些操作符的介绍 1.0

算数操作符

赋值操作符

单目操作符

条件操作符

三,二进制和进制转换

原码,反码,补码

四,移位操作符

左移操作符

右移操作符

五,位操作符:&,|,^,~

六,逗号表达式

七,下标访问[],函数调用()

八,操作符的优先级和结合性

1.优先性

2.结合性

九,表达式求值

1.整型提升

2.算数转换

3.问题表达式解析


一,操作符的分类

1.算数操作符:+,-,*,/,%

2.移位操作符:<< ,>>

3.位操作符:&,|,^

4.赋值操作符:=,+=,-=,*=,/=,%=,<<=,>>=,&=,|=,^=

5.单目操作符:!,++,--,&,*,+,-,~,sizeof,(类型)

6.关系操作符:>,>=,<,<=,==,!=

7.逻辑操作符:&&,||

8.条件操作符:?,;

9.逗号表达式:,

10.下标引用:[ ]

11.函数调用: ( )

12.结构成员访问:. ,- >

因为有一些操作符涉及一些关于进制的问题所以操作符就和进制一起讲了。

二,一些操作符的介绍 1.0

上面我们列举了一些操作符,有些是我们熟悉的有些可能见都没见过。这里主要讲一些不常见的操作符。因为有些操作符会涉及进制的问题这里把顺序打乱了,之后会在讲完进制之后在介绍。

算数操作符

1.%

都知道 / 是除的意思,/ 在c语言中取的数值是两个数相除的商,而 % 取的数值是两个数相除的余数。%一般叫做“取模”。

赋值操作符

赋值操作符看上去很多,其实它一点都不难。它的主要组成就是其他的一些操作符加上=。

如a+=1,的意思就是a=a+1,其他的操作符也是这种形式,这里需要大家理解一下这种形式我在给大家简单的描述一下:这里=前面的操作符我们就叫它执行操作符用T来表示,把要执行的变量用I来表示,把=后面的数用W表示,就有:I = I T(T要操作的就是I和W) W,这样T就变成了普通的操作符。由此也可以看出T一定是双目操作符。

单目操作符

单目操作符的意思是给一个变量就能执行的操作符。这里的单目操作符中的+,-是正号和负号的意思。大家都应该认识它就是非的意思。

下面重点讲一下++,--, 这里以++为例--和++的用法差不多。++分为前置++,如++a。和后置++,如a++。这两的区别是调用,前置的++是先++再调用,后置++是先调用再++。++这个用法主要用在循环中,这两个的区别一般也会在循环中体现。

&这里是取地址符号,大家也知道地址在c语言中的重要程度。取地址在指针用的较多。这里不作过多的扩展,这里的知识会在指针中详细的呈现。这里只要知道&a就是取出a变量所在内存中的地址即可。

*是简引用操作符,int*p的意思是p是指针变量,int是指针所指向的变量类型,在int*p中存放的地址,*p是指向地址中的内容。这里可能你听的比较模糊,在指针中会详细的讲解。你现在只要知道*主要用于指针当中*p的意思是引用地址中的数值。(在指针中还会详细的讲解这里不是太懂也没有关系)  ~ 会在讲完进制以后介绍。

sizeof  我们都知道sizof是一个库函数这里为什么是单目操作符呢?,这里留个悬念,在讲函数调用操作符的时候会详细说明。

(类型)这是强制转换操作符,如char a=0;(int) a=0;这里就把原本的char类型强制的转换成了,int类型。

条件操作符

这里的条件操作符,也很简单。不知道大家有没有见过这样的表达式:a>b?a:b这里的?就是判断a是否大于b的意思,大于取a小于取b。这里的 ;就非常的常见了你会发现你写的每一行代码的结尾都会写 ;。;的作用也跟它的位置有关,;的作用就是结束标志,在代码后面加上;就代表这你这行代码就写完了,代码会在这里截至然后运行下一行。

三,二进制和进制转换

二进制想必大家都听说过,二进制中只有0,1。一开始的计算机就是使用的二进制进行编写的。

二进制中的0,1其实指的是电信号,0为断开,1为闭合。但是用这种二进制写代码太麻烦了于是编程语言发生了进化。

我们生活中主要接触的是十进制,十进制由0~9的数字组成,满10进一。

同理二进制由0,1的数字组成,满2进一。

十进制的123的解释

百位十位个位
十进制的位123
权重10^210^110^0
权重值1*10^22*10^13*10^0
求值1*100                     +2*10                       +3*1=123

二进制的1010化为十进制是10

二进制位1010
权重2^32^22^12^0
权重值1*2^30*2^21*2^10*2^0
求值1*80*41*20*1
=10

十进制的123化为二进制是多少呢?

这就是十进制转换为二进制的方法,那么二进制转换为八进制和十六进制怎样转换呢?

首先,介绍一下8进制和16进制。8进制是由0~7的数字组成,满8进一。16进制是由0~15的数字表示,其中10~15用A~F表示。满16进一。经分析可得8是2^3所以三个二进制位可以表示一个八进制位,16是2^4所以四个二进制位表示一个16进制位。如果,十进制转换为八进制和十六进制可以先转换为二进制在转换为八进制和十六进制。

原码,反码,补码

整数的二进制由三种分别是:原码,反码,补码。

一般的整数二进制的第一位是符号位,0代表的是正数,1代表的是负数。大家应该知道int类型分为unsigned int和signed int。unsigned int表示无符号位,一般的int都是有符号位的。无符号位都是正数。

正整数的原码,反码,补码都相同。

负整数的原码,反码,补码个不相同:

原码:就是整数转换为二进制的数值。

反码:是在原码的基础上,符号位不变其他的位按位取反。

补码:是在反码的基础上+1。

补码转换位原码也可以符号位不变,其余的位按位取反再+1。

对于整数来说数据在内存中是以补码的形式存储的。用补码的形式存储有利于负数的运算。

int是4个字节,一个字节是八个比特位,所以int有32个比特位。

这就是用补码的运算,这里10-10的二进制位超出了32位所以就把最左边的1给挤出内存了,所以得到的结果位0。

这里介绍完了二进制接着来介绍操作符;

四,移位操作符

<<左移操作符

>>右移操作符

注意:移位操作符的操作数只能是整数

左移操作符

移位规则:左边抛弃,右边补0

#include<stdio.h>
int main()
{
	int num = 10;
	int b = num << 1;
	printf("%d\n", b);
	printf("%d\n", num);
	return 0;
}

运行结果:

原理:

右移操作符

移位规则:右移的规则有两种

1.逻辑右移:左边补0,右边抛弃

2.算数右移:左边用原有的符号位填充,右边抛弃

大部分编译器用的是算数右移。

#include<stdio.h>
int main()
{
	int num = 10;
	int b = num >> 1;
	printf("%d\n", b);
	printf("%d\n", num);
	return 0;
}

运行结果:

原理:

注意:不要移动负数位这是规定。

五,位操作符:&,|,^,~

注意:操作数只能是整数

1.&按位与  执行规则:有0为0,都是1才为1

2.|按位或  执行规则:有1为1,都是0才为0

3.^按位异或  执行规则:相同取0,相异取1

4.~按位取反 执行规则:把1改为0,把0改为1

直接上代码:
 

#include<stdio.h>
int main()
{
	int num1 = -2;
	int num2 = 3;
	printf("%d\n", num1 & num2);
	printf("%d\n", num1 | num2);
	printf("%d\n", num1 ^ num2);
	printf("%d\n", ~0);
	return 0;
}

运行结果:

大家可以根据前面的描述来推出它的原理,这里实在是太多了就不一一展示了。

一道变态的面试题:

不能创建临时变量(第三变量),实现两个数的交换。

#include<stdio.h>
int main()
{
	int a = 10;
	int b = 20;
	a = a ^ b;
	b = a ^ b;
	a = a ^ b;
	printf("a=%d,b=%d", a, b);
	return 0;
}

看到这个代码,可能很多人是疑惑的这真的可以完成两个数的交换吗?这正是位操作符的神奇之处,位操作符在嵌入式中是非常常见如果是要学习嵌入式的同学,可要好好的学习了。

下面就给大家展现一下它的原理解开这神秘的面纱:

因为10和20有一点的大我就用1和2来展示一下原理,方便大家的理解,这里我也不用32位来表示了。

a=0001

b=0010

a=a^b=0011(此时a的值被改为了0011)

b=a^b=0001(此时神奇的一幕发生了b的值变为了1)

这里就不难明白它的原理:a^a^b=b,很神奇对不对有没有激起你探索的欲望。其实还远不只如此下面在给大家一个悬念,可以自己试着思考一下感受一下,如何查找一个二进制有几个1呢?可以一步步来分析,答案会在下期揭晓。

六,逗号表达式

逗号表达式就是用逗号隔开的多个表达式,逗号表达式可能我们接触的比较少,但它比较的简单。

逗号表达式,从左到右执行。整个表达式的结果是最后一个表达式的结果。

如代码:if(a=b,c/2,d>0)

前面的表达式也会执行,但判断if()函数能否执行的还是d>0这个条件。

下面再给大家一个有关循环的代码:
 

int main()
{
	int a = Num();
	Count(a);
	while (a>0)
	{
		//业务处理
		a = Num();
		Count(a);
	}
	return 0;
}
int main()
{
	int a = Num();
	Count(a);
	while (Count(a),a = Num(),a > 0)
	{
		//业务处理
		a = Num();
		Count(a);
	}
	return 0;
}

通过这两个代码的对比你能更好的了解逗号表达式。

七,下标访问[],函数调用()

下标访问[],主要用于数组中的元素调用 如arr[1],这就是在调用下标为1的数组数值。

函数调用(),主要用于给函数传递数据,建立形参。所以这也可以说明函数都是要有函数调用()才可以使用,这里也就可以证明sizeof是不是函数。

这里sizeof并没有使用函数调用()也能得出int类型的大小为4,这足以证明sizeof是个单目操作符,而不是函数。

细心的的朋友会发现,操作符的知识基本上是介绍完了,就剩下一个结构体成员访问操作符,这里要和大家说声抱歉了,结构体是一个很大的概念我就觉得还是单独写一期比较好,所以这里就不过多的介绍了,后期在结构体中会详细的讲解。

八,操作符的优先级和结合性

1.优先性

操作符如此之多,那谁先执行谁后执行呢?这就和操作符的优先性有关了。

2.结合性

在我们用操作符时肯定还会遇到操作符优先性相同的情况,这是就会用的操作符的结合性,结合性其实就是操作符执行的顺序,有从左向右执行如 5*6/2,是先算5*6然后算6/2。也有从右向左执行的如=。

操作符优先级图表:

链接:C 运算符优先级 - cppreference.com

其实()的优先级是很高的,所以可以使用它改变其他运算符的优先级。

九,表达式求值

1.整型提升

C语言中总是缺乏整型类型的精度来运行,为了解决这个问题会把char和short类型的操作数转换为普通整型这个转换过程叫做整型提升。

如何进行整型提升的呢?

拿char类型举例,char是1个字节8个比特位。它在整型提升的时候是在前面不它的符号位。

2.算数转换

这个可能比较简单,其实算数转换就是在两个类型不相同时用强制转换符它的类型转换成相同的再进行计算。

3.问题表达式解析

操作符有如此之多的规则,所以我们要更加注意操作符的使用,使用不当可能会出现错误。这里的错误不是语法错误而是代码错误,你会发现你写的代码在不同的编译器代码执行的结果是不行同的。

a*b+c*d+e*f

这个表达式就存在着错误,由于*的优先级比+高,可以保证第一个*先执行+后执行,但不能保证最后面的*会比第一+先执行。因为两个操作符隔得距离太远,无法有效的判断优先级。

c+--c;

由于后置--比+的优先级高,但没有办法很好的确定c的值,所以表达式的结果就会发生变动。

像这种问题表达式的例子还有很多所以我们在写代码的时候还是脚踏实地的一步一步的写,不要写这种迷迷糊糊的表达式。首先,你写的代码你要看得懂其次你写的代码他人也要看到懂,这样有益于代码的管理,修改,传递

结语:这里的第九个板块表达式的求值,作者也是理解的半斤八两可能会有些读者看的晕头转向。不要着急,这是作者的问题。你只需要理解一下这方面的知识,注意一下书写就好。

  • 31
    点赞
  • 50
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值