C语言中的运算符
-
表达式:有一个或者多个操作数(变量\常量\字面值)与运算符组成
-
表达式的值:根据运算符运算规则,表达式最终的结果
-
C语言中的运算符种类:
-
算数运算符:+(加) , -(减) , *(乘) , /(除) , %(取余、模运算) , ++(自增) , --(自减)
-
关系运算符:<(小于)、>(大于)、<=(小于等于)、>=(大于等于)、==(等于、判等)、!=(不等于)
-
逻辑运算符:&& (与)、||(或) 、!(非)
-
赋值运算符:
-
简单赋值运算符: = (简单赋值)
-
复合赋值运算符:
- 算术复合赋值运算符:+=、-=、*=、/=、%=
- 位运算复合赋值运算符:&=、|=、^=、<<=、>>=
-
-
位运算符:&(位与)、|(位或)、~(位非)、^(位异或)、<<(位左移)、>>(位右移)
-
条件运算符:?:(条件运算符、三元运算符、三目运算符)
-
逗号运算符: ,
-
指针运算符:&(取地址符)、*(寻址符、解引用符)
-
求字节运算符:sizeof
-
结构体运算符: . (结构体变量访问成员运算符) , -> (结构体指针)
-
特殊运算符: () (更改优先级运算符) , [] (下标运算符) , {} (列表运算符)
-
-
学习运算符主要学习什么?
- 运算规则
- 优先级
- 结合性
- 操作数个数
一 、算数运算符
1.1 + , - , * , / , %
-
都是二元运算符(二元:两个操作数)
-
运算规则: 与数学中基本一致
-
特别注意的地方: 没有特别区分浮点除法和整数除法
-
C语言中算数运算符的结果类型由左右操作数类型决定.
-
例如: 左右擦作数类型都为int时,结果为int (整除,不会四舍五入) ;
-
左右操作数为double时,结果为double(浮点数除法, );
-
一边为int ,一边为double ,结果是double (结果会为范围大的的类型);
- 小技巧:若要使整数除法转换成浮点数除法 可以把一边变成double, 先用1.0乘以前面一个数 或者类型转换 (double) a / b ; (注意区分前后顺序)
-
代码:
int a = 10, b = 3; double c = a / b; printf("%.2lf\n", c); // 3.00 c = 1.0 * a / b; printf("%.2lf\n", c); //3.33 c = (double)a / b; // 类型转换 printf("%.2lf\n", c); // 3.33 c = double(a / b); printf("%.2lf\n", c); // 3.00
-
-
/ 和 % 要求右操作数不能为0
-
% 取余运算符 :
- 要求左右操作数必须为整数
- py 往负无穷取 , C语言往0取;且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
-
取余运算常用在:
- 缩小数据范围
- 判断整除 a%b == 0;
-
1.2 ++ 、 –
-
++ 称之为自增运算符、–称之为自减运算符、都属于一元运算符
-
以++为例:(–与++操作规则相同)
-
前自增(前++):++操作数
- 先对操作数进行自加一操作,然后取操作数的值
-
后自增(后++):操作数++
- 先取操作数的值,后对操作数进行自加1的操作
-
-
注意:
- printf("%d",a++);就是打印出来a++之前的值
- 因为a先取值,再执行++
- a++;
- printf("%d",a); 打印出来的就是a++之后的值
- 因为a++,先取值再++已经执行完毕了
- printf("%d",a++);就是打印出来a++之前的值
-
在实际开发中,如果在一个表达式中使用了自增或自减运算符,则其操作数不要在表达式中出现多次。
-
eg:
int i=0; printf(“%d\n”, ++i); //1 printf(“%d\n”, i);//1 int i=0; printf(“%d\n”, i++);//0 printf(“%d\n”, i);//1 int i=0; printf(“%d\n”, ++i); printf(“%d\n”, i++); printf(“%d\n”, --i); printf(“%d\n”, i--); printf(“%d\n”, i); I = 0; printf(“%d\n”, ++i + ++i + i); //会先把所有对i的操作 处理完 最后使用最后一个操作完的i值进行符号运算 I = 0; printf(“%d\n”, ++i + --i + i-- + i++ + i);
-
二、关系运算符
-
== 、 != 、> 、<、 >=、<=
-
关系运算符都是二元运算符,结合性都是从左到右
-
>、<、>=、<=的优先级都高于 == 、!=
-
关系运算符的结果只有0和1,0表示不成立(false),1表示成立(true)
-
代码:int a = 5;
printf("%d\n",a>=1); //1 printf("%d\n",a>10); //0 printf("%d\n",1< a< 3); //1 // 1< a <3这种写法py是支持的,但是C语言不支持 //C语言中上面表达式的结果恒定为1
三、逻辑运算
-
&&(逻辑与)、 ||(逻辑或)、!(逻辑非)
-
从结果上说,1表示真,0表示假
-
从操作数上说,非0表示真,0表示假
-
&&和||从结合性上来说都是从左到右的
-
&&的优先级高于||
-
代码: a && b || c && d
int a ; scanf("%d\n",&a); if (a % 2 ==1) {}; if (a % 2 ) {}; // a % 2 ==1和 a % 2 结果一样 例:// a == 0 a的值为0 // a != 0 a的值则为1 (非0则为1) a = !!a int a = 1 , b = 0; printf("%d\n" , b++ && a++); //逻辑与运算左侧出现0,则最终结果为0,后面不会再执行,叫做逻辑短路问题,a++不再执行 printf("%d\n", a); // 1 printf("%d\n", b); // 1
-
逻辑短路问题:
-
逻辑与的短路问题:
- 当左操作数为假的时候,右操作数不执行
-
逻辑或的短路问题:
- 当左操作数为真的时候,右操作数不执行
-
代码:
int a = 1, b = 0; printf("%d\n", a && b); // 0 printf("%d\n", a || b); // 1 printf("%d\n", !a || b); // 0 printf("%d\n", b++ && a++); // 0 printf("%d\n", a); // 1 printf("%d\n", b); // 1 a = 1; b = 0; printf("%d\n", ++b || ++a); // 1 printf("%d\n", a); // 1 printf("%d\n", b); // 1
-
四、条件运算符
-
?::条件运算符、三元运算符、三目运算符
-
唯一的一个三个操作数的运算符
-
操作数1 ? 操作数2 : 操作数3
-
表示根据操作数1的真假,如果结果为真,操作数2执行并作为表达式结果;如果结果为假,则操作数3执行,并作为表达式结果
-
代码:
int a ; scanf("%d" , &a); a%2 == 0 ? printf("偶数\n") : printf("奇数\n"); printf(a%2 == 0 ? printf("偶数\n") : printf("奇数\n"); //与上面结果一样
-
五、位运算符
-
位运算符就是直接操作内存二进制的运算符
-
常见的:&(位与)、|(位或)、~(位非)、^(位异或)、<<(位左移)、>>(位右移)
-
运算符的含义:
-
&:二元运算符,将左右操作数内存直接按位进行与运算
-
代码:
short a = 18,b = 9; short c = a & b; //a : 0000 0000 0001 0010 //b : 0000 0000 0000 1001 //c : 0000 0000 0000 0000 printf("hd \n", c ); // c = 0 c = 17 & 13; printf("hd \n", c ); //1
-
-
|:二元运算符,左右操作数内存按位进行或操作
-
代码:
short a = 18,b = 9; short c = a | b; //a : 0000 0000 0001 0010 //b : 0000 0000 0000 1001 //c : 0000 0000 0001 1011 printf("hd \n", c ); // c = 27 c = 17 | 13; printf("hd \n", c ); //29
-
-
~:一元运算符,将操作数内存按位取反
-
代码
short a = 2; short c = ~a; //a : 0 000 0000 0000 0010 //~a : 1 111 1111 1111 1101 printf("%hd\n",c); //-3 c = ~b; // 0000 0000 0000 0000 // 1111 1111 1111 1111(补码) // 1111 1111 1111 1110(反码) // 1000 0000 0000 0001(原码) printf("%hd\n",c); unsigned short a = 2, b = 0; unsigned short c = ~a; // 1111 1111 1111 1101 // 1111 1111 1111 1111 2^16-1 printf("%hu\n", c); // 2^16-3 c = ~b; printf("%hu\n",c); // 2^16-1
-
-
^:位异或,二元运算符,左右操作数内存按位进行异或运算
-
相应位相同为0,不同为1
-
代码:
short a = 17, b = 9; short c = a ^ b; // a: 0000 0000 0001 0001 // b: 0000 0000 0000 1001 // c: 0000 0000 0001 1000 printf("%hd\n", c); //24 short a = 17, b = 9; a = a ^ b; // a' = a ^ b; b = a ^ b; // b' = a' ^ b = a ^ b ^ b; a = a ^ b; // a'' = a' ^ b' = a ^ b ^ a; printf("a = %hd\n", a);// a = 9 printf("b = %hd\n", b);// b = 17 //规律: // [0] ^ 1 -> 1 ^ 1 -> [0] // [0] ^ 0 -> 0 ^ 0 -> [0] // [1] ^ 1 -> 0 ^ 1 -> [1] // [1] ^ 0 -> 1 ^ 0 -> [1] //写法2: a ^= b ^= a ^= b ;
-
-
位移运算符:
-
位移:将操作数内存中每一位向特定方向(向左、向右)移动指定位数。
-
位移运算通常操作数为无符号整型
-
<< :位左移运算符
- 操作数1 << 操作数2 :将操作数1内存每一位往左移动操作数2位
- 高位移出舍弃,低位补零
- 往右移动n位相当于乘以2的n次
-
>>:位右移运算符
- 操作数1 >> 操作数2 :将操作数1内存每一位往右移动操作数2位
- 高位移出舍弃,低位补零
- 往右移动n位相当于除以2的n次
-
代码:
int a = 16; printf("%d\n",a << 1); //32 printf("%d\n",a << 2); //64 printf("%d\n",a << 3); //128 printf("%d\n",a << 4); //256 printf("%d\n",a << 5); //512 int a = 316; printf("%d\n",a >> 1); //158 printf("%d\n",a >> 1); //79 printf("%d\n",a >> 1); //39 printf("%d\n",a >> 1); //19 int a = 10 , b = 15; int c = (a + b) >> 1; //加和除以2
- 代码例子:
int a = 11; //1011 //打印a二进制的低四位,不能直接打印1011 //1:右移用最后一位进行取余,b = a % 2; //2: & 1 或者 | 0
-
-
-
六、赋值运算符
-
简单赋值运算符
-
= :二元运算符,结合性从右到左,将右操作数的值赋给左操作数,要求左操作数必须为可被修改的变量。
-
赋值运算符优先级倒数第二低 (逗号为最低)
-
代码
int a , b , c ; a = b = c = 10;
-
-
复合赋值运算符 (简写形式)
- 算术复合赋值运算符:+=、-=、*=、/=、%= (简化代码)
- 位运算复合赋值运算符:&=、|=、^=、<<=、>>=
- eg: a += b -> a = a+b
七、逗号运算符
-
,:逗号运算符
-
一般形式:操作数1,操作数2 :先执行操作数1,在执行操作数2,然后将操作数2作为整个逗号表达式的结果
-
优先级最低,二元运算符,结合性从左到右。
-
例子:
-
代码:
int num; num = 100 , 200; //赋值的=要比逗号,优先级高 printf("%d\n",num); //100 printf("%d\n",(num = 100 , 200)); // 200 ,先执行赋值,再执行逗号,所以是200 num = (1,2,3,4,5,6) printf("%d\n",num); // 6 int num = 13; num += num -=num *= num /= num //结合性从右到左 ,复合运算符 printf("%d\n",num) // 0
-
八、C语言中的类型转换
-
C语言中的类型转换共分为2类:显示类型转换,隐式类型转换
-
显示类型转换(强制类型转换)
-
(希望转换成的类型)操作数:将操作数转换成括号中的类型 (根据程序员的操作意识)
- (double)10/3 (double)(10/3) // 转换符的优先级很高,需要用小括号来改变优先级
-
-
隐式类型转换
-
并不是程序员的主动行为,而是计算机自动完成的类型转换
-
通常出现在不同类型操作数进行运算时
-
C语言要求进行运算时左右操作数类型一定要一致
- 例子:
10.0 / 3 double int | (隐式类型转换) double
- 例子:
-
-
不同类型进行运算时,数据范围较小的类型会自动提升到范围较大的类型
char , short ——>会被提升至 int (默认)——>提升至 long ——> long long ——> 自定义数据类型 float ——> double(默认)——> long double short & float ——> int & double ——> (小范围提升至大范围)double & double ——> 结果为double
-
隐式类型转换的陷阱:
- unsigned int <-> int :int 转换为 unsigned int ,把int的符号位一起当作数据位一起读取
-1 int ——> unsigned int 2^32-1 - 代码:
unsigned int size = 10; if (size > -1) { printf("AA\n"); } else { printf("BB\n"); }
- unsigned int <-> int :int 转换为 unsigned int ,把int的符号位一起当作数据位一起读取