分类:
算术操作符
操作符 | 功能 |
---|---|
+ | 加 |
- | 减 |
* | 乘 |
/ | 除 |
% | 取余(两个整数) |
- 除了
%
操作符之外,其他的几个操作符可以作用于整数和浮点数。 - 对于
/
操作符如果两个操作数都为整数,执行整数除法。而只要有浮点数执行的就是浮点数除法。 %
操作符的两个操作数必须为整数。返回的是整除之后的余数。
移位操作符
操作符 | 功能 |
---|---|
<< | 左移 |
>> | 右移 |
左移操作符移位规则:
左边抛弃,右边补0
举例说明:
- 操作数是正数时
int x = 4;
printf("%d\n", x<< 1);
输出结果:
8
- 操作数是负数时
int x = -4;
printf("%d\n", x<< 1);
输出结果:
-8
结论:
- 左移运算本身和数据正负性无关
- 计算机存储的是补码,目的是将减法变为加法
右移操作符移位规则:(哪种移位方式取决于变量的类型)
1.逻辑移位 左边用0填充,右边丢弃(对应的是无符号数)
2.算术移位 左边用原该值的符号位填充,右边丢弃(对应有符号数。补0或补1取决于变量的类型,和内部写入数据无关)
举例说明:
1.无符号数
(1)正数
unsigned int x = 4;
printf("%d\n", x >> 1);
输出结果:
2
画图解释:
(2)负数
unsigned int x = -4;
printf("%d\n", x >> 1);//%d是有符号位显示操作数
输出结果:
2147483646
画图解释:
补充:
unsigned int x = -4;
在这里是合法的
- 存:字面数据必须先转成补码,在放入空间当中。所以,所谓符号位,完全看数据本身是否携带±号。和变量是否有符号无关!
- 取:取数据一定要先看变量本身类型,然后才决定要不要看最高符号位。如果不需要,直接二进制转成十进制。如果需要,则需要转成原码,然后才能识别。(当然,最高符号位在哪里,又要明确大小端)
存的时候不看符号位,取的时候再看是否需要看符号位,再确定是否需要原反补转化
2.有符号数
(1)正数
int x = 4;
printf("%d\n", x >> 1);
输出结果:
2
(2)负数
int x = -4;
printf("%d\n", x >> 1);
输出结果:
-2
注意:
-
移位操作不改变原值。
-
移位时不能移负数位。
位操作符
操作符 | 功能 |
---|---|
& | 按位与 |
丨 | 按位或 |
^ | 按位异或 |
- 位操作是同时进行多位同等比特位的操作
- 同样位操作符作用的对象也是一个数的补码,并且它们的操作数必须是整数
- 按位异或:1. 相同为假(0),相异为真(1);2.任何数和0异或都是它本身;3.异或支持交换率和结合律
- 位操作的应用场景(示例:按位与):将倒数第三个比特位置0
练习:
1.不能创建临时变量(第三个变量),实现两个数的交换。
#include <stdio.h>
int main()
{
int a = 10;
int b = 20;
a = a ^ b;
b = a ^ b;
a = a ^ b;
printf("a = %d b = %d\n", a, b);
return 0;
}
2.求一个整数存储在内存中的二进制中1的个数。
#include <stdio.h>
int main()
{
int num = -1;
int i = 0;
int count = 0;//计数
while (num)
{
count++;
num = num & (num - 1);
}
printf("二进制中1的个数 = %d\n", count);
return 0;
}
赋值操作符
操作符 | 功能 |
---|---|
= | 赋值 |
+= | 相加之后赋值 |
-= | 相减之后赋值 |
*= | 相乘之后赋值 |
/= | 相除之后赋值 |
%= | 取余之后赋值 |
>>= | 右移之后赋值 |
<<= | 左移之后赋值 |
&= | 按位与之后赋值 |
丨= | 按位或之后赋值 |
^= | 按位异或之后赋值 |
- 复合操作符相较于普通的操作符,用复合操作符可以使代码更简洁。
- 赋值运算也是运算,
int x = 10;int y = x;
是将x的值放于CPU中的寄存器中,在内存中开辟y空间,将寄存器中x的值写入内存y空间中,CPU也参与了运算。=
的本质是把运算结果写回内存 - 其他数据运算相关的操作符本质是需将内存中的数据转移到CPU的寄存器中
- float型的浮点数的建议写法
float f = 3.14f
单目操作符
操作符 | 功能 |
---|---|
! | 逻辑反操作 |
+ | 正值 |
- | 负值 |
& | 取地址 |
sizeof | 操作数的类型长度(以字节为单位) |
~ | 对一个数的二进制按位整体取反 |
- - | 前置、后置– |
++ | 前置、后置++ |
* | 间接访问操作符(解引用操作符) |
(类型) | 强制类型转换 |
- !操作符是对一个数做逻辑反操作,而~操作符是对一个数的二进制按位取反。
- sizeof是一个操作符,关键字,而不是函数,求的是操作数的类型长度(以字节为单位)。
sizeof求类型的长度时不可省略括号,求变量的长度时可以省略括号。
证明:printf("%d\n", sizeof a);
- 对于前置++或 - -,是想自加减,再使用;后置++ - -,是先使用再自加减,使用完是直到该语句结束。
画图解释:
- 强制类型转换并没有对数据作任何修改。
有两个意义:(1)让编译器取消报警。(2)给其他人看
关系操作符
操作符 | 功能 |
---|---|
> | 大于 |
>= | 大等于 |
< | 小于 |
<= | 小等于 |
!= | 不等于 |
== | 等于 |
- 注意在编程中== 和=不要写错,导致错误。
- 如果要比较常量和变量是否想等,建议写为
1 == x
而不是x == 1
,这样编译器容易发现错误。
逻辑操作符
操作符 | 功能 |
---|---|
&& | 逻辑与 |
丨丨 | 逻辑或 |
- 区分逻辑与和按位与以及区分逻辑或和按位或
1&2----->0
1&&2---->1
1|2----->3
1||2---->1
- 逻辑操作符进行时会控制求值顺序
int a = 10;
a > 10 && printf("Hello!");//逻辑与当前面当条件不满足时不执行后项
a >= 10 || printf("Hello!");//逻辑或当前项条件为真时也不执行后项
输出结果:
条件操作符
操作符 | 功能 |
---|---|
exp1?exp2:exp3 | exp1为真,结果为exp2,否则结果是exp3 |
- 这个是三目操作符,单目双目以及三目区别是需要的操作数个数不一样,单目只需要一个操作数(数据),而三目需要三个操作数。
逗号表达式
操作符 | 功能 |
---|---|
exp1,exp2,…expN | 从左往右依次执行,整个表达式结果是最后一个表达式的结果 |
示例说明:
int main()
{
int a = 1; int b = 2;
int c = (a>b, a=b+10, a, b=a+1);
printf("%d",c);
return 0;
} //结果是13
特殊操作符
操作符 | 功能 |
---|---|
[ ] | 数组下标操作符,操作数:数组名+一个索引值 |
( ) | 函数调用操作符,接受一个或多个操作数:第一个是函数名,其余是函数参数 |
. | 访问结构体成员 |
-> | 访问结构体成员 |