运算符与表达式

0.运算符与表达式

什么是运算符? 用来进行某种运算的符号。

如:
    +  -  *  / %

几目运算符?该运算符需要带几个操作数

单目运算符:该运算符只需要带一个操作数。    
     如: ++  --
双目运算符:该运算符需要带两个操作数。
     如: + - * /
三目运算符:该运算符需要三个操作数。
     如: ? :

结合性:优先级相同的情况下决定先算谁后算谁的问题 从左至右结合,从右至左结合

优先级: 在一个含有多个运算符的表达式中,先算哪个运算符后算哪个运算符的问题。 单目运算符 > 算术运算符 > 关系运算符 > 逻辑运算符 > 条件运算符 > 赋值运算符 > 逗号运算符

表达式

在C语言中有相应含义的对象

表达式加上 ; ==> 语句

3+2 算术表达式

a 变量表达式

1 常量表达式

a++

注意:1.只要是个表达式就一定会有值

2. 在函数内部都是以语句形式存在

1. 算术运算符

运算符功能说明举例
+加法,单目取正a+b
-减法,单目取负a-b
*乘法a*b
/除法a/b
%取模(求余)a%b
++自加1,单目a++, ++b
--自减1,单目a–-, --b
  • 关注点

    • 减号也是负号,比如-a是取变量a的相反数

    • 取模运算要求左右两边操作数必须是整型数据
    • 自加自减运算不仅可以对整型操作,也可以对浮点数、指针操作

1)单目运算符

++ -- +(正号) -(负号)

  • 前后缀运算:

    1. 前缀自加自减运算:先进行自加自减,再参与表达式运算

    2. 后缀自加自减运算:先参与表达式运算,在进行自加自减

      表达式表达式的值表达式执行后i的值
      i++ii+1
      ++ii+1i+1
      i--ii-1
      --ii-1i-1

3 / 4 ==> 0
5 / 4 ==> 1
​
3 % 4 ==> 3
5 % 4 ==> 1
​
3++;//error  3 = 3+1  左值有问题
int a = 2;
a++;// a = a+1
​
a+++++a;//erro 
/*
    1.c: In function ‘main’:
1.c:7:13: error: lvalue required as increment operand
  int b = a+++++a;
             ^~
​
*/
注意:
    自加自减运算符单独使用

2)双目运算符

+ - * /  %
注意:
  1. % : 求余,取模。要求两个操作数都必须为整数。

  2. ++ -- :要求操作数必须为一个可写的“左值 lvalue”

  3. 连续操作自加自减符号是不允许出现的

5*1.0/4 ==> 1.25

(double)5/4 ==> 1.25

(double)(5/4) ==> 1.0

2. 关系运算符

都是双目运算符

结合性:从左往右

运算符功能举例说明
>大于a > b判断a是否大于b
>=大于或等于a >= 5判断a是否大于或等于5
<小于3 < x判断3是否小于x
<=小于或等于x <= (y+1)判断x是否小于或等于y+1
==等于(x+1) == 0判断x+1是否等于0
!=不等于c != '\0'判断c是否不等于’\0’
eg:
    2 > 3 > 4  ==> 0
    ==> 0 > 4 ==> 0
    5 > 4 > 3 ==> 0
    ==> 1 > 3 ==> 0
        
   int a = 0;
    
    a != 2  ==>1
       
    5 > 4 > 3 
       ==> 5 > 4 and 4 > 3
     

  • 关注点:

    • 关系运算符用于判断运算符两边的表达式是否满足给定的大小条件

    • 由关系运算符组成的表达式称为关系表达式,其值为布尔型

    • 判断是否相等是双等号==,而不是一个等号

3. 逻辑运算符

双目运算符 除 !

结合性:从左往右

运算符功能说明举例
逻辑非!0
&&逻辑与x > 0 && x < 10
||逻辑或y < 10 || x > 10
  • 运算规则:

    • 逻辑非:将逻辑真、假翻转,即真变假,假变真

    • 逻辑与:将两个表达式串联起来,当且仅当左右两个表达式都为真时,结果为真。并且

    • 逻辑或:将两个表达式并联起来,当且仅当左右两个表达式都为假时,结果为假。或者

  • 惰性运算

    • 在逻辑与运算中,如果左边表达式的值为假,那么右边表达式将不被执行。

    • 在逻辑或运算中,如果左边表达式的值为真,那么右边表达式将不被执行。

    逻辑与 && ---而且,同时 两个操作数都必须为真,结果为真
    逻辑或 || ---或者 只要有一个为真,那么结果为真
    逻辑非 ! ----反 
    非0 为真,0 为假
    逻辑表达式结果有两种 1为真 0为假
    ​
    =============
        
       eg:
        int a = 3, b = 4, c = 5, d = 6;
        int m = 1,n = 1;
        
        (m = a > b) && (n = c > d);
        
        printf("%d %d %d %d %d %d\n",a,b,c,d,m,n);//3 4 5 6 0 1
        
    C语言运算符是“惰性运算”:
        (1) a && b && c
            只有a为真时,才需要判断b的值
            只有a和b都为真时,才需要判断c的值  
        (2) a || b || c
            只要a为真,就不必判断b和c的值啦
            只有a为假,才需要判断b的值 
            只有a和b都为假,才需要判断c的值
            ……。
        In a word, 如果事先知道表达式的值啦,那么后面的运算符(或表达式)就不需要执行啦,这就是C语言运算符的“惰性”.
    ​

    「课堂练习1」

    1. 用逻辑表达式来判断y(年份)是否为闰年: (1) 能被4整除,但不能被100整除 (2) 能被4整除,又能被400整除 满足上述条件之一,则为闰年

      伪代码:
          (1) || (2)
      (1):
          (y % 4 == 0) && (y % 100 != 0)
      (2):
          (y % 400 == 0)
      ==> 
          ((y % 4 == 0) && (y % 100 != 0)) || (y % 400 == 0)
      ==> 
          ((y % 4 == 0) && (y % 100)) || (y % 400 == 0)
          

4. 位运算符

位运算符是指按bit位来进行的运算。 ​ 注意:所有位运算都需要把操作数变成bit序列,然后再按bit位来运算 ​ 位运算符要求操作数是整数。

运算符名称举例功能说明
~位反~a将变量 a 中的每一位取反
&位与a & b将变量 a 和 b 逐位进行与操作
|位或a | b将变量 a 和 b 逐位进行或操作
^位异或a ^ b将变量 a 和 b 逐位进行异或操作
<<左移a << 4将变量 a 中的每一位向左移动4位
>>右移x >> n将变量 x 中的每一位向右移动4位
  • ~ : 按位取反---单目运算符,数据将每一个bit位取反,1变0,0变1

以1字节为列
eg:
    ~4  ==> 251
    00000100
==》11111011
​
    ~2 ==> 253
    00000010
=>  11111101

  • &:按位与,两个都为1,结果才为1

    • 1 & 1 == 1

    • 1 & 0 == 0

    • 0 & 0 == 0

    • 0 & 1 == 0

    以1字节为列
    eg:
    	2 & 3  ==》 2
    	00000010
    	00000011
    ==> 00000010
    
  • | :按位或,两个都为0,结果才为0

    • 1 | 1 == 1

    • 1 | 0 == 1

    • 0 | 1 == 1

    • 0 | 0 == 0

    eg:以1字节为例
    	4 | 5  ==》 5
    	00000100
    	00000101
    ==》00000101
    
    

  • ^ : 按位异或 --- 不同为1,相同为0

    • 1 ^ 0 == 1

    • 0 ^ 1 == 1

    • 0 ^ 0 == 0

    • 1 ^ 1 == 0

    eg:以1字节为例
    	8 ^ 9  ==》 1
    	00001000
    	00001001
    ==> 00000001
    	
    

  • << : 左移,按bit位往左移动

    假设该数 为 x

    x << n :将 x 的bit序列 整体左移 n个bit 位

    高位左移后,直接丢弃

低位空出n 个bit 位 全部补0

  • >> : 右移

    假设该数 为 x

    x >> n :将 x 的bit序列 整体右移 n个bit 位

    低位右移后,直接丢弃

高位空出n 个bit 位 补什么,看x是有无符号 ​ ​ 无符号 :高位补0 ​ 有符号:高位补符号位 ​

eg:
	以1字节为例
	
	8 << 2  => 32
	00100000
	
	8 >> 2   ==>2
	00000010

  • 位运算符操作的对象是数据中的每一位

  • 运算规则:

    • 位反、位与、位或拥有与逻辑运算相似的规则和一样的真值表。

    • 异或运算:相同为0,不同为1

    • 移位运算:移出去的不要,空出来的补零。

      分析以下代码的结果:
      	char a = -8;
      
      	printf("%d\n", a << 6);//-512
      						
      	printf("%d\n", a >> 6); //-1
      
      a:char
      	1111 0110
      a=>int
      	11111111 11111111 11111111 1111 0110
      a << 6
      	11111111 11111111 11111101 1000 0000 (负数的补码)
      	
      a >> 6
      	11111111 11111111 11111111 1111 1111(负数的补码)
      
      

      「课堂练习2」

    问题1: 假设有如下程序,程序输出的结果是什么?

  int main(void)
  {
      char a, b, c, d;
      a = 0x3;//
      b = a|0x8;// 

      c = b<<1;//
  	  d = b >> 3;
      printf("%d %d %d %d\n",a, b, c, d);//3 11 22 1
  }

=============================

结论1:
	一个bit位与0进行“按位与 &”操作,结果为0
	x & 0 == 0 
	如何证明?
		因为x只能为0 or 1
		when x == 0  x & 0 = 0
		when x == 1  x & 0 = 0
	一个bit位与1进行"按位与 &"操作,保留原值
	x & 1 == x
	如何证明?
	显而易见。
		when x == 0  x(0) & 1 == x(0)
		wnen x == 1  x(1) & 1 == x(1)

1: 假设有一个整型变量a, 要把a的第5bit变为0,其他bit位不变,该如何操作?

a的值从键盘上获取

 a: 34
     00000000 00000000 00000000 00100010
     11111111 11111111 11111111 11011111 (~(1 << 5))
     
==>& 00000000 00000000 00000000 00000010
	==> a = a & (~(1 << 5)
========test1.c                                    
	//1. 定义变量
		int a;
	//2. 从键盘获取数据
		scanf("%d", &a);
	//3. 执行设置操作
       	a = a & (~(1 << 5));          	

	//4. 输出结果
		printf("%u\n", a);

=======================

结论2:
	一个bit位与0进行“按位或 |”操作,保留原值,
		x | 0 == x
	一个bit位与1进行“按位或 |”操作,结果为1
		x | 1 == 1

2:

有一个整型变量a,要使a的第5bit设置,其他bit位不变, 该如何操作?

a: 
     00000000 00000001 01100000 00000010
     00000000 00000000 00000000 00100000 (1 << 5)
     
==>| 00000000 00000001 01100000 00100010
 	 //1. 定义变量
		int a;
	//2. 从键盘获取数据
		scanf("%d", &a);
	//3. 执行设置操作
       	a = a |(1 << 5);          	

	//4. 输出结果
		printf("%u\n", a);  
    

==========================

结论3:
		一个bit位与0进行“按位异或 ^”操作,保留原值
			x ^ 0 == x
		一个bit位与1进行"按位异或 ^"操作,结果取反
			x ^ 1 == ~x

3: 有一个整型变量a,要使a的第5bit位保留,其他位取反, 该如何操作?

a: 
     00000000 00000001 01100000 00000010
     11111111 11111111 11111111 11011111 (~(1 << 5))     
==>^ 11111111 11111110 10011111 11011101
      
    //1. 定义变量
		int a;
	//2. 从键盘获取数据
		scanf("%d", &a);
	//3. 执行设置操作
       	a = a ^(~(1 << 5);          	

	//4. 输出结果
		printf("%u\n", a); 

5. 条件运算符(三目运算符)

结合性:从右往左

  • 唯一需要三个操作数的运算符

  • 语法格式:表达式1?表达式2:表达式3

    表达式1?表达式2:表达式3 ===> 这个本身也是一个表达式

    如果表达式1 为真,则整个条件表达式的值为 表达式2的值

    如果表达式1 为假,则整个条件表达式的值为 表达式3的值

    eg:
    	int b = 0;
    	int a = 2 > 3 ? b = 2 : b++;
    
    	==> a == 0
            b == 1
    	
            
     ======================
     int main()
    {
    	int a = 3, b = 4;
    	int c = a > b ? a++ :a < b ? a++ : b++; 
    	// 注意:在条件表达式中不管其他运算符的优先级,先找到其中的表达式1,表达式2和表达式3
    	
    	//a = ?
    	//b = ?
    	//c = ?
    	printf("%d %d %d\n", a, b ,c);// 4 4 3
    }
    
    

注意:

表达式2 和 表达式3 只走其一

6. 赋值运算符

  • 赋值运算符 =

    • 可以连续赋值,结合性:从右往左

    • 赋值运算符的左边(左操作数)必须是可写的地址空间

a = b = c = d = 0;

赋值表达式的值 :就是最后赋值给最左边变量的值

  • 复合赋值运算符

    赋值运算符可以和 位运算符, 算术运算符组合一起使用

    • 当左右两边有相同的操作数时,采用复合赋值符不仅直观,且能提高运算效率

eg:
	a += 2;// a = a+2
	a &= 2; //  

	int a = 8;
    a += 1;// 
	
	a++; // 

7.逗号运算符

语法:
	(表达式1,表达式2,表达式3,... 表达式n)
求值顺序:
	先求表达式1,再求表达式2,再求表达式3,最后求表达式n
	整个逗号表达式的值为n的值
注意:
    1.逗号表达式的优先级最低
    2.运算顺序是从左往右
    3.整个逗号表达式的值取决于最右边的表达式的值
eg:
	int b = 0;
	int  a = 1,2,3,3+4,b++;
	// a = ?
	/*
		china@ubuntu:$ gcc 4.c
        4.c: In function ‘main’:
        4.c:9:13: error: expected identifier or ‘(’ before numeric constant
          int  a = 1,2,3,3+4,b++;
             ^
	china@ubuntu:$ 

	*/
	a = 1,2,3,2+3,4>5,7;

	a = ? //1
	

8. sizeof 运算符

  • 含义:计算指定数据类型或者变量所占据内存的字节数

  • 语法:sizeof(类型)、sizeof(变量),计算变量的字节数时圆括号可以省略

  • 举例:

eg:
	sizeof(2+3.0) ==> 8
   ==> sizeof(5.0) ==> sizeof(typeof(8.0)) ==> sizeof(double) ==> 8

9. return运算符

  • 含义:退出某个函数(如果退出的是主函数main,那么整个程序也就推出)

  • 语法:必须出现在函数体内,可以带函数对应类型的数据

  • 举例:

int main()
{
    printf("hello\n");
    //假如()
    {
        return -1;// 1. 返回结果  2. 结束所属函数
    }
    
    printf("world\n");
    return 0;
 }// main函数返回0 正常结束该程序  -1 异常结束


10.其他的单目运算符

*    间接运算
&    取址
sizeof()     求字节
. ->        分量运算符
[]		   下标运算符
(类型)   类型强转

typeof(5.0 + 4 ) ==> double

(int)(5.0 + 4)

sizeof:求一个对象或类型所占空间的字节数 sizeof(x) sizeof 不要求x存在,但是要求x的类型是确定的 因为只要你的类型是确定,那么我就可以知道你所占内存大小。

11. 优先级与结合性

  • 当表达式出现不同的运算符时,根据优先级来决定谁先执行,比如先乘除后加减

  • 当表达式中出现多个相同优先级的运算符时,更具结合性决定谁先运行,比如从左到右

结合性:

三种从右往左

	1. 单目
	2. 三目
    3. 赋值
    
    
   
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值