目录
运算符划分
-
按照功能划分:
- 算术运算符
- 关系运算符
- 逻辑运算符
- 按位运算符
-
按照参与运算的操作个数进行划分
-
单目运算符
- 只有一个操作数 如:i++
-
双目运算符
- 有两个操作数 如:a+b
-
三目运算符
- 有三个操作数 如:a > b ? 1:0 如果a>b时,a = 1,如果a<b时,a = 0
-
运算符的优先级表
-
运算符的优先级分为15级别,1级最高,15级最低
-
在表达式中优先级高的优先于优先级低的先运算
-
在一个运算量两侧的,优先级一样时按照运算符的结合性所规定的方向进行运算
优先级 运算符 名称或含义 使用形式 结合方向 说明 1 [] 数组下标 数组名[常量表达式] 左到右 () 圆括号 (表达式)/函数名(形参表) . 成员选择(对象) 对象.成员名 -> 成员选择(指针) 对象指针->成员名 2 - 负号运算符 -表达式 右到左 单目运算符 (类型) 强制类型转换 (数据类型)表达式 ++ 自增运算符 ++变量名/变量名++ 单目运算符 -- 自减运算符 --变量名/变量名-- 单目运算符 * 取值运算符 *指针变量 单目运算符 & 取地址运算符 &变量名 单目运算符 ! 逻辑非运算符 !表达式 单目运算符 ~ 按位取反运算符 ~表达式 单目运算符 sizeof 长度运算符 sizeof(表达式) 3 / 除 表达式/表达式 左到右 双目运算符 * 乘 表达式*表达式 双目运算符 % 余数(取模) 整型表达式/整型表达式 双目运算符 4 + 加 表达式+表达式 左到右 双目运算符 - 减 表达式-表达式 双目运算符 5 << 左移 变量<<表达式 左到右 双目运算符 >> 右移 变量>>表达式 双目运算符 6 > 大于 表达式>表达式 左到右 双目运算符 >= 大于等于 表达式>=表达式 双目运算符 < 小于 表达式<表达式 双目运算符 <= 小于等于 表达式<=表达式 双目运算符 7 == 等于 表达式==表达式 左到右 双目运算符 != 不等于 表达式!= 表达式 双目运算符 8 & 按位与 表达式&表达式 左到右 双目运算符 9 ^ 按位异或 表达式^表达式 左到右 双目运算符 10 | 按位或 表达式|表达式 左到右 双目运算符 11 && 逻辑与 表达式&&表达式 左到右 双目运算符 12 || 逻辑或 表达式||表达式 左到右 双目运算符 13 ?: 条件运算符 表达式1? 表达式2: 表达式3 右到左 三目运算符 14 = 赋值运算符 变量=表达式 右到左 /= 除后赋值 变量/=表达式 *= 乘后赋值 变量*=表达式 %= 取模后赋值 变量%=表达式 += 加后赋值 变量+=表达式 -= 减后赋值 变量-=表达式 <<= 左移后赋值 变量<<=表达式 >>= 右移后赋值 变量>>=表达式 &= 按位与后赋值 变量&=表达式 ^= 按位异或后赋值 变量^=表达式 |= 按位或后赋值 变量|=表达式 15 , 逗号运算符 表达式,表达式,… 左到右 从左向右顺序运算 -
虽然说运算符有很多,但是不用记住,使用小括号()扩起来就好了
结合性简单介绍
- c语言中有两种结合性,一种是左结合型,一种是右结合性
- 左结合性--自左至右运算,右结合性--自右至左运算
- 左结合性 例如:x + y -z,先计算x+y,计算后的结果再减z
- 右结合性 例如:x = y = z, 将z的值赋值给y,再将y的值赋值给x
算数运算符表
运算符 | 术语 | 示例 | 结果 |
---|---|---|---|
+ | 正号 | +3 | 3 |
- | 负号 | -3 | -3 |
+ | 加 | 10 + 5 | 15 |
- | 减 | 10 - 5 | 5 |
* | 乘 | 10 * 5 | 50 |
/ | 除 | 10 / 5 | 2 |
% | 取模(取余) | 10 % 3 | 1 |
++ | 前自增 | a=2; b=++a; | a=3; b=3; |
++ | 后自增 | a=2; b=a++; | a=3; b=2; |
-- | 前自减 | a=2; b=--a; | a=1; b=1; |
-- | 后自减 | a=2; b=a--; | a=1; b=2; |
#include <stdio.h>
int main(int argc, const char * argv[]) {
/*
+ 加法
- 减法
* 乘法
/ 除法
% 取模(取余)
*/
int result;
result = 1 + 1;
printf("加法结果:result = %i\n",result);
result = 1 - 1;
printf("减法结果:result = %i\n",result);
result = 2 * 3;
printf("乘法结果:result = %i\n",result);
result = 10 / 2;
printf("除法结果:result = %i\n",result); // result = 5
result = 10 % 3;
printf("取模结果:result = %i\n",result); // result = 1
return 0;
}
取模运算符的注意点
- 注意:取模运算只能对整数取模,不能对实数取模
// 注意取模运算只能是整数取模不能是实数取模
// result = 10.5 % 3; // 直接报错
- 注意:取模运算的正负性,取决于左边的操作数
// 取模运算的正负性,取决于左边的操作数
result = 10 % -3;
printf("取模正负性结果:result = %i\n",result); // result = 1
result = -10 % -3;
printf("取模正负性结果:result = %i\n",result); // result = -1
result = -10 % 3;
printf("取模正负性结果:result = %i\n",result); // result = -1
result = -0 % -3;
printf("取模正负性结果:result = %i\n",result); // result = 0
- 注意:如果取模运算中,左边操作数小于右边操作数,那结果直接就是左边操作数,不会进行计算了
// 如果取模运算中,左边操作数小于右边操作数,那结果直接就是左边操作数,不会进行计算了
result = 10 % 100;
printf("取模结果:result = %i\n",result); // result = 10
算术运算符的结合性
// 算术运算符的结合性
result = 3 + 4 + 5 + 6;
printf("result的值是%i",result);
算术运算符的优先级和结合性同时存在时
- 先优先级,再按照结合性
// 优先级+结合性
result = 2 + 3 * 4 -4;
printf("result的值是%i\n",result); // 先计算乘法,再从左至右的结合性计算
类型转换
- 隐式转换
// 系统自动进行的转换
int number = 10.8;
printf("number的值是%i\n",number); // number = 10,
// 大类型的转换成小类型的,系统会自动进行转换,由大类型转换为小类型,丢失精度
- 显式转换
// 显式转换-只需要在值前面加(类型)
int value = (int)10.8;
printf("value的值是%i\n",value); // 10;
// 大类型的转换成小类型的,系统会自动进行转换,由大类型转换为小类型,丢失精度
- 在算术运算中,类型不一致时,系统会先将类型统一,统一成大类型进行计算
// 在算术运算中,类型不一致时,系统会先将类型统一,统一成大类型进行计算
int value2 = 10 + 9.9;
// 10是int类型,9.9是double类型,int类型占4个字节,9.9占8个字节,所以先将int转为double类型
// int value2 = 10.0 + 9.9
// int value2 = 19.9
// value2 是一个int类型,但是右边的19.9是double类型,这时候系统会做隐式转换,大类型转为小类型,既结果为19
printf("value2的值是%i\n",value2); // 19;
- 算术运算符的注意点-参与运算的操作数是什么类型,那么计算出来的结果就是什么类型
// 算术运算符的注意点-参与运算的操作数是什么类型,那么计算出来的结果就是什么类型
int value3 = 1 / 2;
printf("value3的值是%i\n",value3); // 打印出来的是0
// 此时你会不会觉得是因为定义的变量是int类型导致的呢?那我就换成double类型的看看
double value3 = 1 / 2;
printf("value3的值是%lf\n",value3); // 打印出来的是0.000000 此时还是0
// 是因为右侧参与运算的都是整数,那么计算的结果肯定是整数
// 那么如果需要打印出0.5该怎么办呢?
double value4 = 1.0 / 2; // 此时一个double除以int类型,肯定是都先转换为doublee类型,计算出的结果就是double类型,i定义的变量也是double类型不需要转换所以打印出的是0.500000
printf("value4的值是%.1lf\n",value4);
int value5 = 1.0 / 2;
printf("value5的值是%i\n",value5); // 0
- 新手注意常犯的错误
// 新手注意饭的错误
double value6 = (double)(1 / 2);
// 右边先计算括号中的1 / 2,那么两个整数相除,结果肯定是整数,所以是0 ,由强转为double类型,为0.000000
printf("value6的值是%lf",value6); // 0.000000
- 在算术运算符中,实数的计算都是double类型,不是float类型
赋值运算符
- 最简单的赋值运算符,将等号右边的值赋值给等号左边的变量
- 赋值运算符的结合性是右结合性
int main(int argc, const char * argv[]) {
// 最简单的赋值运算符,将等号右边的值赋值给等号左边的变量
// 赋值运算符的结合性是右结合性
int number = 10;
int a;
int b;
a = b = 5;
printf("a的值是%i,b的值是%i\n",a,b);
return 0;
}
- 符合赋值运算符
- 定义:在赋值符“=”加上其他的二目运算符可构成复合赋值运算符
赋值运算符的作用是将常量、变量或表达式的值赋给某一个变量。
运算符 | 术语 | 示例 | 结果 |
---|---|---|---|
= | 赋值 | a=2; b=3; | a=2; b=3; |
+= | 加等于 | a=0; a+=2; a = a + 2 | a=2; |
-= | 减等于 | a=5; a-=3; a = a - 3 | a=2; |
*= | 乘等于 | a=2; a*=2; a = a * 2 | a=4; |
/= | 除等于 | a=4; a/=2; a = a / 2 | a=2; |
%= | 模等于 | a=3; a%2; a = a % 2 | a=1; |
int a = 0;
a += 3; // 这种是直接进行赋值,运算效率要好
a = a +3; // 这一种是不是先计算再赋值给a
printf("a的结果是%i\n",a);
// 复合赋值运算,会先进行右边的表达式得到的值在赋值给左边的变量
自增,自减运算符
- 自增自减的第一种写法: 变量++,变量--
int result = 10;
result++;
result++;
printf("变量++,自增后的result值为:%i\n",result); // 12
// 如果想让某一个数减1,可以使用变量--,--变量
int value = 5;
value--;
printf("变量--,自增后的value值为:%i\n",value); // 4
- 自增自减的第二种写法: --变量,++变量
// 第二种写法:++变量,--变量
int result1 = 10;
++result1;
printf("++变量,自增后的result1值为:%i\n",result1); // 11
int result2 = 5;
--result2;
printf("++变量,自增后的result1值为:%i\n",result2); // 4
- ++,-- 在变量前面和++,-- 在变量后面的区别(在变量之前先运算再自增,在变量之后先自增再运算)
// ++,-- 在变量前面和++,-- 在变量后面的区别
// ++ , -- 在后面时,先参与运算然后再自增
int a = 10;
int b = a++;
printf("a的值是%i,b的值是%i\n",a,b);// a的值是11,b的值是10 注意看b的值是10,而不是11,这里是a先赋值给b,然后再自增的
// ++ --在变量之前时,是先自增再赋值
int c = 10;
int d = ++c;
printf("c的值是%i,d的值是%i\n",c,d); // c的值是11,d的值是11 注意看这里d的值同样是11,所以c是先自增再赋值给d
- 自增,自减练习
// 练习
/*
int a = 10;
int b = (a++) + (++a);
// b = a++ ,此时a++的结果是11, 后面++a在a=11的基础上再自增,那么a的值就是12了,10+12
// a =12
printf("b的值是%i,a的值是%i\n",b,a);
*/
/*
int a = 10;
int b = (a++) + (a++);
printf("b的值是%i,a的值是%i\n",b,a); // b = 10 + 11 , a = 12
*/
/*
int a = 10;
int b = (++a) + (++a);
printf("b的值是%i,a的值是%i\n",b,a); // b = 11 + 12 ,a = 12
*/
/*
int a = 10;
int b = (++a) + (a++);
printf("b的值是%i,a的值是%i\n",b,a); // b = 11 + 11, a = 12
*/
int a = 10;
int b = (a++) + (a--);
printf("b的值是%i,a的值是%i\n",b,a); // b = 10 + 11 , a = 10
- 自增的拆分
// 自增的拆分
int a = 10;
int b = a++;
// 拆分:
// 1, int b = a;
// 2, int a = a+1;
printf("b的值是%i,a的值是%i\n",b,a); // b = 10,a = 11
int c = 10;
int d = ++c;
// 拆分
// 1,int c = c + 1;
// 2,int d = c;
printf("d的值是%i,c的值是%i\n",d,c);
// 拆分之后,只是两个表达式的顺序反了. 如果有时确实难懂的话不妨拆分一下
sizeof运算符
-
介绍:sizeof运算符可以用来计算一个变量或一个常量,一种数据类型所占的内存节数
-
格式:sizeof(变量/常量/数据类型)
-
注意:sizeof 不是一个函数而是一个运算符(只要是运算符就会有一个返回值)
-
计算常量的内存字节
// 使用 sizeof 计算常量的内存字节
int number = sizeof(10.9);
printf("10.9的e内存字节是%i\n",number); // 8
- 计算变量的内存字节
int a = 10;
// int number = sizeof(a); // 只要是运算符就会有返回值
int number = sizeof a; // 不加s括号e也可以
printf("a的内存字节是%i\n",number);
- 计算数据类型的内存字节(sizeof的括号不能省略)
// 使用 sizeof 计算数据类型的内存字节
int numChar = sizeof(char);
printf("char 数据类型占用%i个字节\n",numChar); // 1
int numInt = sizeof(int);
printf("int 数据类型占用%i个字节\n",numInt); // 4
int numDouble = sizeof(double);
printf("double 数据类型占用%i个字节\n",numDouble); // 8
int numFloat = sizeof(float);
printf("float 数据类型占用%i个字节\n",numFloat); // 8
逗号运算符
-
在 C 语言中逗号也是一个运算符,称之为逗号运算符,其功能是把多个表达式连接起来组成一个表达式,成为逗号表达式
-
格式: 表达式 1,表达式 2,表达式....表达式 n;
-
例如:a = a + 1,b = 3*4;
-
结合性:从左到右结合性
// 逗号运算符,从左到右依次计算表达式的结果,只要是运算符就会有结果,逗号运算符也不例外
int a = 10;
int b = 5;
int result;
a = a + 10,b = b - 1,result = a + b;
printf("a的值是%i,b的值是%i,result 的值是%i\n",a,b,result);
- 逗号表达式的结果是最后一个表达式的结果
// 定一个一个变量 number 来接收逗号表达式的结果,每个表达式用括号括起来,整体再括起来,逗号表达式的结果是最后一个逗号表达式的结果
int number = ((a = a + 10),(b = b - 1),(result = a + b));
printf("a 的值是%i,b 的值是%i,result 的值是%i,number 的值是%i\n",a,b,result,number);
关系运算符
- 在 c 语言中条件成立为真,条件不成立为假,判断条件是否成立就是判断条件的真假
- 怎么判断条件的真假呢? C 语言中规定任何数值都有自己的真假性,任何非 0 的都为真,也就是说 100,-50,2.3这些都是真,只有 0 是假的
- 关系运算符的结果只有两个结果,真和假
C 语言的比较运算中, “真”用数字“1”来表示, “假”用数字“0”来表示。
运算符 | 术语 | 示例 | 结果 |
---|---|---|---|
== | 相等于 | 4 == 3 | 0 |
!= | 不等于 | 4 != 3 | 1 |
< | 小于 | 4 < 3 | 0 |
> | 大于 | 4 > 3 | 1 |
<= | 小于等于 | 4 <= 3 | 0 |
>= | 大于等于 | 4 >= 1 | 1 |
- 关系运算符的返回值要么真要么假
// > , < , >= , <= , == , !=
int a = 10;
int b = 5; // 怎么知道 a>b 呢? 任何的运算符都有结果
int c = 20;
int result = a > b;
int result1 = a > c;
printf("result的值是%i\n",result); // 1
printf("result1的值是%i\n",result1); // 0
- 关系运算符的优先级: > < >= <=的优先级大于 == , !=
// 关系运算符的优先级: > < >= <=的优先级大于 == , !=
int a = 10;
int b = 5;
int result = 1 == a > b; // 先计算 a 是否大于 b,再拿这个结果与 1 是否相等,
printf("result 的值是%i",result); // 1
- 算术运算符的优先级大于关系运算符(比较运算符)
// 算术运算符的优先级大于关系运算符
int result = 1 + 1 > 2+2;
printf("result 的值是%i\n",result); // 0,先计算 1+1,在计算 2+2,再拿 2>4?
- 关系运算符的结合性是左结合性
// 关系运算符的结合性是左结合性
int result = 10 > 5 > 20;
printf("result 的值是%i\n",result); // 0,先计算 10>5,再拿这个值与 20做比较
- 如果优先级和结合性同时存在,那就先优先级,再结合性
// 如果优先级和结合性同时存在,那就先优先级,再结合性
int result = 10 + 1 > 5 + 4 == 3 > 1;
// 先计算 10+1,再计算 5+4,这两个算术运算符,得出 11 > 9 == 3>1
// 再计算 11 > 9 ,和 3 > 1 这两个优先级比较高的比较运算符表达式,
// 最后计算 1 == 1 等于的表达式
printf("result 的值是%i\n",result); // 11 > 9 == 3 > 1 ---> 1 == 1 ---> 1
- 开发中没有人会按照上面那么写的
int result1 = (10+1) > (5+4) == (3>1);
printf("result1 的值是%i\n",result1); // h实际开发中为了阅读,还是加上括号
逻辑运算符
-
有时候我们需要满足多个条件同时成立才能执行代码,比如登录:需要输入正确的用户名,和正确的密码,才能登录.所以c 语言提供了逻辑运算符
-
C 语言中提供了三个逻辑运算符
- && 逻辑与 表达式 1 && 表达式 2
- || 逻辑非 表达式 1 || 表达式 2
- ! 逻辑非 ! 表达式 2
-
逻辑运算符的运算结果只有两个真和假
-
逻辑与:只有表达式都为真,结果才是真,其余都是假
- 结合性:从左至右
// 逻辑与(一假则假)
int result = 10 > 7 && 5 > 3; // 10>7为真,5>3 为真
printf("result = %i\n",result); // 1
int result1 = 10 > 90 && 8 >1; // 10 > 90为假
printf("result1 = %i\n",result1); // 0
- 逻辑或:只要有一个表达式为真,结果就是真,如果表达式都是假,结果才是假
- 结合性:从左至右
// 逻辑或 (一真则真)
int result = 10 > 8 || 9 > 7;
printf("result = %i\n",result); // 都为真--真
int result1 = 10 > 8 || 9 > 10;
printf("result1 = %i\n",result1); // 一个为真--真
int result2 = 10 > 11 || 9 > 10;
printf("result2 = %i\n",result2); // 都为假--假
int result3 = 10 > 11 || 9 > 8; // 一个为真--真
printf("result3 = %i\n",result3);
- 逻辑非(如果表达式为真,则为假,如果表达式为假,则为真)---取反
- 结合性:从右至左
// 逻辑非
int result = ! 10; // 0
int result1 = ! 0; // 1
printf("result = %i\n",result);
printf("result1 = %i\n",result1);
- 注意点;C 语言规定,任何数值都有真假性,非 0 既真,所有的逻辑运算符可以直接约数值进行计算
- 逻辑与的特点是一假则假,所以如果前面的表达式是假的话,那么后面的表达式就不会计算了
int a = 10;
int result = 10 < 8 && a++ > 5; // a = 10,result = 0
// 由于 10 < 8 为假,所以后面的表达式就不会计算了,a++ 后,a 的值就没有自增
int b = 20;
int result1 = 10 > 8 && b++ >5; // 10 > 8 为真,后面的表达式继续计算,所以 b 的值是 21
printf("a = %i,result = %i\n",a,result);
printf("b = %i,result1 = %i\n",b,result1);
- 逻辑或的特点是一真则真,所以如果前面的表达式是真的话,那么后面的表达式就不会计算了
int a = 10;
int result = 10 > 8 || a++ > 5; // a = 10,result = 0
// 由于 10 > 8 为真,所以后面的表达式就不会计算了,a++ 后,a 的值就没有自增
int b = 20;
int result1 = 10 < 8 || b++ >5; // 10 < 8 为假,后面的表达式继续计算,所以 b 的值是 21
printf("a = %i,result = %i\n",a,result);
printf("b = %i,result1 = %i\n",b,result1);
-
以上两个逻辑运算符的特点称之为:逻辑运算符的短路
-
判断一个数值是否在一个范围内
int a = 10;
if (a > 3 && a < 100){
printf("a在 3-100 之间");
} else{
printf("a 不在 3-100 之间");
}
三目运算符
-
格式: 条件表达式 ? 结果 A: 结果 B
- 如果表达式为真,返回结果 A,如果表达式为假,返回结果 B
-
结合性:左结合性
// 三目运算符
int a = 10;
int b = 20;
int result = a > b;
printf("result = %i\n",result);
// 如果我想获取两个数之间的最大数呢?
if (a>b){
printf("a 和 b 之间最大数是%i\n",a);
}else{
printf("a 和 b 之间最大数是%i\n",b);
}
// 可是上面的办法太麻烦了,x要写这么多行代码
int maxNum = a > b ? a:b; // 这句话的意思是,如果a> b,那就返回 a,如果 a 不大于 b 的话,那就返回 b
printf("a 和 b 之间最大数是%i\n",maxNum);
- 三目运算符练习
// 从控制台输入三个整数,返回最大的整数
printf("请输入三个整数以逗号隔开,回车结束\n");
int num1,num2,num3;
scanf("%i,%i,%i",&num1,&num2,&num3);
int temp = num1 > num2 ? num1 : num2; // 比较 num1 和num2 中的最大值
int maxNum = temp > num3 ? temp : num3; // 拿到 num1 和 num2 的最大值再与 num3 做比较,返回最大值
printf("num1,num2,num3 之间的最大值是:%i\n",maxNum);
int maxNum1 = (num1 > num2 ? num1 : num2) > num3 ? (num1 > num2 ? num1 : num2) : num3;
// 不推荐这种写法是因为,问号之前计算了一次num1 和num2 的最大值,问号表达式之后又计算了一次,无疑消耗了性能
printf("num1,num2,num3 之间的最大值是:%i\n",maxNum1);