C语言学习笔记(2)之运算符与表达式

运算符与表达式

  1. 表达式
    表达某一个意思的式子。

    a = b + c

    在C语言中,表达式一般是指用运算符连接操作数的式子

    注意:是表达式就一定会有一个值。

  2. 运算符
    用来进行某种运算的符号就叫运算符。
    如:
    +、-、*、…

    几目运算符?表示的该运算符需要带几个操作数。
    单目运算符:该运算符只需要一个操作数。如:++、–…
    双目运算符:该运算符需要两个操作数。如:+ - *…
    三目运算符:该运算符需要三个操作数。如: ?:(条件运算符)

    结合性:代表的是运算的优先顺序
    例子:
    + 结合性从左至右
    a + b
    先把表达式a的值求出来,再去求表达式b的值。

    C语言中的运算符:
    (1) 算术运算符
    进行算术运算的运算符。

    	单目运算符:
    		++、--
    		
    	双目运算符:
    		+ - * / %
    	
    	重点:
    		1.	整数/整数其结果还是整数,如果想要这个结果为实数,可用分子*1.0
    		2.	隐式类型转换。
    			高精度和低精度进行运算时,其结果自动转变成高精度。
    			比如:
    				int double --> double
    				int short  --> int
    				char short --> int
    				char char  --> int 
    		3.	取余运算符 %,C语言中,%要求两个操作数必须为整数。
    			printf("%d\n",5%3);			//2
    			printf("%d\n",-5%3);		//-2
    			printf("%d\n",5%-3);		//2
    			printf("%d\n",-5%-3);		//-2
    			记忆点:余数与被整除数同符号。
    		4.	++:自增运算符   --:自减运算符
    			i++				i--
    			++i				--i
    			
    			自增运算符使其操作数的值+1,自减运算符使其操作数的值-1。
    			
    			注意:
    				++、--只能作用于变量。
    					i++		
    					5++				//error
    					(a + b)++		//error
    					(a++)++			//error
    				
    			int i = 5;
    				i++:先进行运算,然后再自增加1
    				a = i++ --> (a = i,i = i + 1)
    				++i:先自增加1,然后再进行运算
    				b = ++i --> (i = i + 1,b = i)
    							i的值		表达式的值
    			a = i++			  6             5
    			b = ++i			  6             6
    			c = i--			  4			    5
    			d = --i   		  4             4
    		
    			int i = 6;
    			printf("%d %d\n",i++,++i);//7 8
    			printf的运算顺序是从右至左,打印顺序是从左至右。
    			
    			因为在同一个表达式内如果存在多个++或者--运算会导致编译器优化
    			导致运算顺序被改变了。
    			
    			结论:尽量的避免在一个表达式内使用多个++和--。
    			printf("%d\n",i++);
    			printf("%d\n",++i);
    

    (2) 关系运算符
    用来判断两个表达式数值大小关系的运算符。

    	双目运算符,结合性:从左至右
    	
    	> >= == <= < !=
    	
    	关系表达式:由关系运算符连接操作数的表达式,叫做关系表达式
    	
    	关系表达式的值:1(关系成立)	0(关系不成立)
    	
    	例子:	
    		5 > 4			1
    		2 >= 3			0
    		5 > 4 > 3		0
    

    (3) 逻辑运算符
    表达某种数理逻辑的运算符。

    	!		逻辑非		单目运算符		“取反”	
    	&&		逻辑与		双目运算符		“并且”		结合性:从左至右
    	||		逻辑或		双目运算符		“或者”		结合性:从左至右
    	
    	逻辑表达式的值:1(非0 真)  0(假)
    	
    	任何非0的数都表示真,但是如果表达式的结果为真时,其值只能为1.
    	
    	例子:
    		a = 4,b = 5
    		a && b		1
    		a && 0		0		只要有一个操作数的值为0,其结果必为0
    
    		a || b		1
    		a || 0      1		只要有一个操作数的值为1,其结果必为1
    		!a || b		1
    		
    		a && 0 || b	1
    		
    		5 > 3 && 8 < 4 - !0 
    		---> 1 && 0  ---> 0
    		
    		int a = 1,b = 2,c = 3,d = 4,m = 1,n = 1;
    		(m = a > b) && (n = c > d);
    		printf("%d %d %d %d %d %d\n",a,b,c,d,m,n);//1 2 3 4 0 1
    		
    		C语言中运算符是“惰性运算”:
    		事先如果已经知道了表达式的值,那么它就不会去运算后面的式子了。
    		
    		1)	a && b && c
    			只有当a的值为真时,才有必须去判断b的值
    			只有当a和b的值都为真时,才有必须去判断c的值
    			
    		2)	a || b || c
    			只有当a的值为假时,才有必须去判断b的值
    			只有当a和b的值都为假时,才有必须去判断c的值
    
    	练习:
    		用逻辑表达式来判断某年是不是闰年。
    		1)	能被4整除,但是不能被100整除
    		2)	能被400整除
    		(year % 4 == 0 && year % 100 != 0) || (year % 400 == 0)
    

    (4) 位运算符
    位运算符是指按bit位来进行运算的运算符,所有的位运算都需要把操作数变成
    bit序列,然后再按bit为来运算。

    	位运算符要求操作是整数(整型、字符型)
    	
    	&		按位与
    	|		按位或
    	^		按位异或
    	~		按位取反
    	<<		按位左移
    	>>		按位右移
    	
    	除了~是单目运算符外,其它的位运算符都是双目运算符。
    	结合性:从左至右
    	
    	
    	1)	~(按位取反)
    		0 --> 1
    		1 --> 0
    		例子:
    			int a = ~3;
    			printf("%d\n",a);//-4
    			printf("%u\n",a);//2^32 - 4
    			
    			0000 0000 0000 0000 0000 0000 0000 0011		 3	
    			1111 1111 1111 1111 1111 1111 1111 1100 	~3
    			1111 1111 1111 1111 1111 1111 1111 1011		-1
    			0000 0000 0000 0000 0000 0000 0000 0100     -4
    			
    	2)	&(按位与)
    		a 		b		a&b
    		1		0		 0
    		1		1		 1
    		0		0		 0
    		0		1		 0
    		只有两个bit位操作数都为1时,结果才为1,否则即为0
    
    		int a = 3 & 5;
    		printf("%d\n",a);//1
    		
    		结论:
    			一个bit位与0进行按位&运算时,结果总为0
    				x & 0 == 0
    			一个bit位与1进行按位&运算时,结果保留原值
    				x & 1 == x
    
    	3)	|(按位或)
    		a 		b		a|b
    		1		0		 1
    		1		1		 1
    		0		0		 0
    		0		1		 1
    		只有两个bit位操作数都为0时,结果才为0,否则即为1				
    
    		int a = 3 | 5;
    		printf("%d\n",a);//7
    		
    		结论:
    			一个bit位与1进行按位|运算时,结果总为1
    				x | 1 == 1
    			一个bit位与0进行按位|运算时,结果保留原值
    				x | 0 == x					
    
    	4)	^(按位异或)
    		a 		b		a^b
    		1		0		 1
    		1		1		 0
    		0		0		 0
    		0		1		 1
    		不同为1,相同即为0			
    
    		int a = 3 ^ 5;
    		printf("%d\n",a);//6
    		
    		结论:
    			一个bit位与0进行按位^运算时,结果保留原值
    				x ^ 0 == x
    			一个bit位与1进行按位^运算时,结果取反
    				x ^ 1 == ~x	
    		
    		交换两个变量的值的方法:
    		1.	利用中间变量法
    			int a = 5,b = 6;
    			int c;
    			c = a;
    			a = b;
    			b = c;
    		
    		2.	异或法
    			a = a ^ b;
    			b = b ^ a;
    			a = a ^ b;
    			
    			位运算只与当前位有关,因为他运算既没有进位,也没有借位。
    			a  	b	a = a ^ b;b = b ^ a;a = a ^ b;		a	b
    			0  	0                                       0   0
    			1	1										1	1
    			0	1										1	0
    			1	0										0	1
    		
    	5)	<<(按位左移)
    		按bit位整体向左移动
    			
    		a << n
    		规则:
    			把a先转换成二进制,在二进制的基础上按bit位整体向左移动n位。
    			高位左移后直接舍弃n位,低位会空出n位,直接补0
    		
    		如果左移后舍弃的高位都是0,那么左移n位,就表示在原值的基础上乘以2
    		的n次方。
    
    		假设有一个字符型变量a,要把a的第5bit变成0,其它bit位不变,该如何操作?
    			xxxx xxxx
    		&	1101 1111
    			xx0x xxxx
    
    		1<<5 0000 0001	
    		~	 0010 0000
    			 1101 1111
    		    
    			a = a & ~(1 << 5);
    
    	6)	按位右移( >> )
    		按bit位整体向右移动
    			
    		a >> n
    		规则:
    			把a先转换成二进制,在二进制的基础上按bit位整体向右移动n位。
    			低位右移后,低n位直接舍弃,高位空出n位,补什么?
    				对于无符号的,高位补0
    				对于有符号的,高位补符号位。
    				
    		int a = -1;
    		a = a >> 31;
    		printf("%d\n",a);//-1
    		printf("%u\n",a);//2^32-1
    		
    		1111 1111 1111 1111 1111 1111 1111 1111 		-1的补码
    		1111 1111 1111 1111 1111 1111 1111 1111			a >> 31
    					
    		unsigned int a = -1;
    		a = a >> 31;
    		printf("%d\n",a);//1
    		printf("%u\n",a);//1
    		
    		1111 1111 1111 1111 1111 1111 1111 1111 		-1的补码
    		0000 0000 0000 0000 0000 0000 0000 0001			a >> 31
    		
    		char a = -1;
    		int b = a >> 31;
    		printf("%d\n",b);//-1
    		printf("%u\n",b);//2^32-1
    
    		1111 1111										-1(char)的补码
    		1111 1111 1111 1111 1111 1111 1111 1111			char --> int
    
    		unsigned char a = -1;
    		int b = a >> 31;
    		printf("%d\n",b);//0
    		printf("%u\n",b);//0	
    
    		1111 1111										-1(char)的补码
    		0000 0000 0000 0000 0000 0000 1111 1111			char --> int
    		0000 0000 0000 0000 0000 0000 0000 0000 		a >> 31
    		
    	数据类型的作用:
    		1.	决定保存数据的空间的大小
    		2.	在短变长和右移时数据类型决定运算方式。
    

(5) 赋值运算符
= 双目运算符 结合性从右至左。

		a = x
		赋值运算符要求左边的操作数必须为一个“可写的地址”。
		
		3 = 4//error
		i++ = 4//error
		i = 6//right
		
		赋值表达式:由赋值运算符连接操作数的式子
		
		赋值表达式的值就是最后赋值给左边变量的那个值
		
		b = a = 6;	-->		b = (a = 6)
		
		复合赋值运算符:赋值运算符可以和算术运算符、位运算符组成复合的赋值运算符
			+= -= %= /= *= <<= >>= |= &= ^= 
		
			例子:
				i += 6;--> i = i + 6;

(6) 条件运算符
?: 三目运算符,结合性从右至左。

		语法:
			表达式1 ? 表达式2 : 表达式3
		
			if(表达式1)
			{
				表达式2;
			}
			else
			{
				表达式3;
			}
			
		求值顺序:
			如果表达式1的值为真,则整个条件表达式的值就是表达式2的值
			如果表达式1的值为假,则整个条件表达式的值就是表达式3的值
		
		例子:
			a = 5 > 4 ? 1 : 0;
			a = 1

(7) 逗号运算符
,

		双目运算符 结合性从左至右
		
		语法:
			表达式1,表达式2
			
		求值顺序:	
			先求表达式1的值,再求表达式2的值,整个逗号表达式的值为表达式2的值。
			
		例子:
			int a = 5,b = 6;
			a = (a = 6,a + b);
			printf("a = %d\n",a);//a = 12

(8) 指针运算符
*(指向符)
&(求地址符)

(9) 求字节运算符
sizeof()

		单目运算符,求一个对象(常量/变量/类型..)所占空间的字节数
		sizeof(4) --> 4
		sizeof(7.8) --> 8
		int i = 5;
		sizeof(i) --> 4
		sizeof(int) --> 4
		
		sizeof(1.0f) --> 4
		char a = 1,b = 2;
		sizeof(a + b) --> 4

(10)分量运算符
. ->

		求结构体中的成员变量的

(11)下标运算符
[]

		取数组的元素
		
		int a[10];
		a[0],a[1],....a[9]

(12)强制类型转换运算符
()

语法:	
	(类型)
	
	如:
		float b = 3.6;
		int a = (int)b;

(13)其它

	优先级:
		优先级决定如果在一个语句中,出现多个运算符,那么到底是哪个运算符先进行运算。
		我们在运算一个表达式的时候,先要看优先级,再看是否有惰性运算,再看结合性
		以下是运算符优先级及结合性的总结表:
			运算符						结合性
		()	[]	->	.					自左向右
		! 	~	++	--	*(指向)			自右向左				单目运算符
		*(算术)	/	%					自左向右				算术运算符
		+	-	
		<	<=	>	>=					自左向右				关系运算符
		==	!=	
		&	^	|	<<	>>				自左向右				位操作运算符
		&&								自左向右				逻辑运算符
		||
		?:								自右向左				条件运算符
		= 	+= 	-= 	*= 	/=				自右向左				赋值运算符
		%= 	&= 	^= 	|= 	<<=	>>=
		,								自左向右				逗号运算符
		自上而下优先级越低,同级优先级的运算符,实际优先级左侧优先

作业:
1.	取整型变量x中第p位开始的n个bit
			(x >> (p + 1 - n)) & ((1 << n) - 1)
			or
			(x >> (p + 1 - n)) & ~(~0 << n)
		
2.	将x中第p位开始的n个bit位取反,其余各位保持不变	
	x = x ^ (((1 << n) - 1) << (p + 1 - n))
	
3.	分析如下程序的输出结果
	char c = -56 >> 30;
		printf("%d\n",c);//-1
		printf("%u\n",c);//2^32 - 1
			
	0000 0000 0000 0000 0000 0000 0011 1000		|-56|
	1111 1111 1111 1111 1111 1111 1100 0111 	取反
	1111 1111 1111 1111 1111 1111 1100 1000		+1(-56的补码)
	1111 1111 1111 1111 1111 1111 1111 1111		-56 >> 30
	1111 1111									c(长变短)
	1111 1111 1111 1111 1111 1111 1111 1111		短变长
		
	char c = -56u >> 30;
	printf("%d\n",c);//3
	printf("%u\n",c);//3
	
	1111 1111 1111 1111 1111 1111 1100 1000		+1(-56的补码)
	0000 0000 0000 0000 0000 0000 0000 0011		-56u >> 30
	
4.	循环位移的实现
	1.	将x循环右移n位
			x = (x << (sizeof(x)*8 - n)) | ((unsigned)x >> n);
	
	2.	将x循环左移n位
		x = (x << n) | ((unsigned)x >> (sizeof(x)*8 - n));
  • 4
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值