分类
- 算数操作符
- 移位操作符
- 位操作符
- 赋值操作符
- 单目操作符
- 关系操作符
- 逻辑操作符
- 条件操作符
- 逗号操作符
- 下标引用、函数调用和结构成员
算数操作符
+、-、*、/、%int a = 5 / 2;商2余1,a = 2int a = 5 % 2; a = 1float a = 5.0 / 2; a = 2.500000
取模%的左右两边数字必须都是整数,例如5.0 % 2是不合法的。
除了取模%操作符之外,其他几个操作符都必须作用于整数和浮点数
对于/操作符,如果两边都是整数,执行整数除法,只要两边有浮点数,就执行浮点数除法。
移位操作符
<< 左移位操作符;>> 右移位操作符。
移的是二进制位。
左移位操作符规则:左边抛弃,右边补0。
123 | int a = 16; int b = a >> 2; printf("%d\n",b); |
打印的结果是4。
右移1位有除2的效果,左移1位有乘2的效果。
警告⚠️:
位操作符
位是指二进制位,操作数必须是整数
- & 按位与
- | 按位或
- ^ 按位异或
& 按位与
123 | int a = 3; int b = 5; int c = a & b; |
a的二进制位是00000000 00000000 00000000 00000011
b的二进制位是00000000 00000000 00000000 00000101
按位与的结果是00000000 00000000 00000000 00000001,有0则0,全1为1。
| 按位或
123 | int a = 3; int b = 5; int c = a | b; |
a的二进制位是00000000 00000000 00000000 00000011
b的二进制位是00000000 00000000 00000000 00000101
按位或的结果是00000000 00000000 00000000 00000111,有1则1,全0为0。
^ 按位异或
123 | int a = 3; int b = 5; int c = a ^ b; |
a的二进制位是00000000 00000000 00000000 00000011
b的二进制位是00000000 00000000 00000000 00000101
按位或的结果是00000000 00000000 00000000 00000110,有1则1,全1为0。
题目:a = 3,b = 5,交换两个变量的值,不使用第三个变量(即a = 5,b = 3)
加减法-数值过大可能溢出
1234567891011 | int main() { int a = 3; int b = 5; a = a + b; b = a - b; a = a - b; printf("%d\n",a); printf("%d\n",b); return 0;} |
异或法(一个数与自身异或等于0,一个数与0异或不变)
1234567891011 | int main() { int a = 3; int b = 5; a = a ^ b; b = a ^ b; a = a ^ b; printf("%d\n",a); printf("%d\n",b); return 0;} |
题目:编写代码,求一个整数存储在内存中二进制1的个数
12345678910111213141516 | int main() { int a = 0; int count =0; printf("求一个整数存储在内存中二进制1的个数\n"); printf("请输入一个整数:->"); scanf("%d",&a); while (a) { if (a % 2 == 1) { count++; } a = a / 2; } printf("%d\n",count); return 0;} |
赋值操作符
= 就是赋值操作符,当一个变量已经存在,想更改它的值,就用赋值操作符
12 | int a = 100;a = 20; |
a = 20;中的=就是赋值操作符。
1234 | int a = 10;int b = 20;int c = 30;a = b = c + 1; |
a = x = c + 1;是连续赋值,这种写法是不推荐的。
可以改写成
12345 | int a = 10;int b = 20;int c = 30;b = c + 1;a = b; |
警告⚠️:赋值操作符是一个等号=,判断操作符是两个等号==。
复合赋值符
- +=
- -=
- \*=
- /=
- %=
=
- <<=
- &=
- |=
- ^=
单目操作符
只有一个操作数的操作符
| ! | 逻辑反操作 |
|---|---|
| - | 负值 |
| + | 正值 |
| & | 取地址 |
| sizeof | 操作数的类型长度(字节单位) |
| ~ | 对一个数的二进制位按位取反 |
| – | 前置、后置– |
| ++ | 前置、后置++ |
| * | 间接访问操作符(解引用操作符) |
| (类型) | 强制类型转换 |
关系操作符
| > | |
|---|---|
| >= | |
| < | |
| <= | |
| != | 用于测试“不相等” |
| == | 用于测试“相等” |
逻辑操作符
| && | 逻辑与 |
|---|---|
| || | 逻辑或 |
- 逻辑与&&操作符,如果左侧为假,不管右侧是什么,都不再计算。
- 逻辑或||操作符,如果左侧为真,不管右侧是什么,都不再计算。
区分逻辑与和按位与
1 & 2 –> 0
1 && 2 –> 1
区分逻辑或和按位或
1 | 2 –>3
1 || 2 –> 1
&&一个条件为假,结果为假||一个条件为真,结果为真
12345678 | int main(){int i = 0,a = 0,b = 2,c = 3,d = 4;i = a++ && ++b && d++;//i = a++ || ++b || d++;printf("a = %d\n b = %d\n c = %d\n d = %d\n",a,b,c,d);} |
打印的结果是1,2,3,4
12345678 | int main(){int i = 0,a = 0,b = 2,c = 3,d = 4;//i = a++ && ++b && d++;i = a++ || ++b || d++;printf("a = %d\n b = %d\n c = %d\n d = %d\n",a,b,c,d);} |
打印的结果是1,2,3,4
条件操作符
逗号表达式
exp1,exp2,exp3,...expn
逗号表达式,从左往右执行,整个表达式的结果是最后一个表达式的结果。
下标引用、函数调用和结构成员
1、[]下标引用操作符
操作数:一个数组名 + 一个索引值
12 | int arr[10];//创建数组arr[9] = 10;//实用下标引用操作符 |
[]的两个操作数是arr和9
2、( )函数调用操作符
3、访问一个结构的成员
- . 结构体.成员名
- -> 结构体指->成员名
123456789101112131415161718192021 | struct Stu{//里面是成员变量char name[20];int age;char id[20];}; int main(){//使用struct Stu这个类型创建了一个学生变量s1,并初始化struct Stu s1 = {"张三",20,"121312312"};struct Stu* ps = &s1;printf("%s\n",(*ps).name);printf("%s\n",ps->name);//结构体指针->成员printf("%s\n",s1.name);printf("%d\n",s1.age);printf("%s\n",s1.id);//结构体.成员名(点.操作符)} |
表达式求值
隐式类型转换
为了获得精度,表达式中的字符和短整型操作数在使用之前被转换为普通整型,这种转换叫整型提升。
如何进行整型提升?
——整型提升是按照变量的数据类型的符号位来提升的。
123456789101112131415161718192021222324 | int main(){ char a = 3; //3的2进制序列:00000000 00000000 00000000 00000011 //a的值:00000011 char b = 127; //127的2进制序列:00000000 00000000 00000000 01111111 //b的值:01111111 char c = a + b; //a和b如何相加:为了获得精度,表达式中的字符和短整型操作数在使用之前被转换为普通整型,这种转换叫整型提升。 //如何进行整型提升? //——整型提升是按照变量的数据类型的符号位来提升的 //a:00000000 00000000 00000000 00000011 //b:00000000 00000000 00000000 01111111 //a + b =00000000 00000000 00000000 10000010 //截断后 c = 10000010 //对c整型提升: //11111111 11111111 11111111 10000010 - 补码 //11111111 11111111 11111111 10000001 - 反码 //10000000 00000000 00000000 01111110 - 原码 printf("%d\n",c);//打印的结果是-126 return 0;} |
算数转换
如果某个操作符的各个操作数属于不同类型,那么除非其中一个操作数的转换为另一个操作数的类型,否则操作无法进行。
警告:算数转换要合理,否则会有问题。
12 | folat f = 3.14;int num = f;//隐式转换,会有精度丢失。 |
操作符的属性
复杂表达式求值有三个因素影响:
1、操作符的优先级
2、操作符的结合性
3、是否控制结合顺序