本篇文章,我们将展开讲解C语言中的各种常用操作符,帮助大家更容易的解决一些运算类问题。
这里提醒一下小伙伴们,本章知识会大量涉及到二进制序列,不清楚二进制序列的小伙伴,可以去阅读我的另一篇文章《数据在内存中的存储》学习了解。
目录
一.操作符分类
二.操作符讲解
1.算数操作符
2.移位操作符
(1)左移操作符
(2)右移操作符
3.位操作符
(1)& 按位与
(2)| 按位或
(3)^ 按位异或
4.赋值操作符
5.单目操作符
总结
一.操作符分类
- 算术操作符
- 移位操作符
- 位操作符
- 赋值操作符
- 单目操作符
- 关系操作符
- 逻辑操作符
- 条件操作符
- 逗号表达式
- 下标引用,函数调用和结构成员
二.操作符讲解
由于操作符数量过多,所以本期文章我们将仅仅讲解前五种。
1.算数操作符
算数操作符包括 “+,-,*,/,%” 五个。较为简单,小伙伴们只需要注意以下几点:
- 除了“%”操作符之外,其他的几个操作符可以作用于整数和浮点数。
- 对于“/”操作符如果两个操作数都为整数,执行整数除法。只要有浮点数就执行浮点数除法。
- “%”操作符的两个操作数必须为整数,返回的是整除后的余数。
2.移位操作符
<< 左移操作符
>> 右移操作符
移位操作符的左边是要操作的数,右边则是要移动的位数。
要注意的是,移位操作符的操作数只能是整数,移动的对象则是整数的二进制序列。
一个整型占四个字节,也就是32个bit位,要记住,整型在数据中存储的是二进制序列的补码,所以我们对整型的操作都是对其补码进行操作的。
(1)左移操作符
左移操作符,顾名思义就是将整数的二进制序列向左边移动呗,那么它的规则是什么呢???
移位规则:
左边丢弃,右边补0
#include<stdio.h>
int main()
{int n = 6;//00000000 00000000 00000000 00000110-移动前//00000000 00000000 00000000 00001100-移动后int m = n << 1;printf("%d\n", n);printf("%d\n", m);return 0;
}
如上代码,将“6”的二进制序列向左移动一位,便得到了一个新的二进制序列。结果如下:
由结果可以看出,移位操作符并不会改变操作数本身,而且细心的小伙伴们可以看出,向左移动一位不就相当于每一位的数字都“乘2”嘛,也就是将数字翻倍,移动n位,便翻2的n次方倍。
负数的操作与之一样,就是小伙伴们千万不要忘记原码和补码之间的转换。
(2)右移操作符
移位规则:
右移运算分为两种:
1.逻辑移位
左边用0填充,右边丢弃
2.算术移位
左边用原值的符号位填充,右边丢弃
不同的编译器会有不同的右移运算,但是我们平时所使用的绝大多数编译器都是算数右移。
#include<stdio.h>
int main()
{int n = -15;//10000000 00000000 00000000 00001111-原码//11111111 11111111 11111111 11110000-反码//11111111 11111111 11111111 11110001-补码//11111111 11111111 11111111 11111000-移动后补码//11111111 11111111 11111111 11110111-移动后反码//10000000 00000000 00000000 00001000-移动后原码int m = n >> 1;printf("%d\n", n);printf("%d\n", m);return 0;
}
结果如下:
同左移类似,右移则是将数字折半,但是如果是奇数的话,结果则会是比小数小的最临近于小数的负数。比如-15的右移结果就是-8。
3.位操作符
& 按位与
| 按位或
^ 按位异或
位操作符的操作数也必须是整数,也是对其二进制序列动手。
(1)& 按位与
假如我是一个企业高管,我现在需要程序员A与程序员B一起来完成某个项目,这说明,A和B是必不可少的,他们两个少了谁这个项目都完不成。这便是按位与。
口诀:同真则真,有假则假
#include<stdio.h>
int main()
{int a = 6;//00000000 00000000 00000000 00000110-补码int n = -15;//11111111 11111111 11111111 11110001-补码int m = a & n;//00000000 00000000 00000000 00000110-补码//11111111 11111111 11111111 11110001-补码//00000000 00000000 00000000 00000000-m的补码(重点)printf("%d\n", m);return 0;
}
我们习惯上将二进制序列的“1”视为真,“0”视为假,a&n,便是两个二进制序列对应的每一位相与,从而得到一个新的二进制序列。
由上可知,m的二进制序列全为0,也就代表m的值为0,结果如下:
(2)| 按位或
假如我又是一个企业高管,我现在需要程序员A或程序员B来完成某个项目,这说明,A和B他们两个只要有一个能来做这个项目,就能成,如果一个都没有,就做不了。这便是按位或。
口诀:同假则假,有真则真
#include<stdio.h>
int main()
{int a = 6;//00000000 00000000 00000000 00000110-补码int n = -15;//11111111 11111111 11111111 11110001-补码int m = a | n;//00000000 00000000 00000000 00000110-补码//11111111 11111111 11111111 11110001-补码//11111111 11111111 11111111 11110111-m的补码(要点)//11111111 11111111 11111111 11110110-m的反码//10000000 00000000 00000000 00001001-m的原码printf("%d\n", m);return 0;
}
对两个二进制序列的每一位相或,便得到m的补码,但是m的符号位为1,是负数,所以要转化为原码来读。
结果如下:
(3)^ 按位异或
假如我还是一个企业高管……这个不好举例子了哈哈哈直接来看口诀:
相同为0,不同为1
#include<stdio.h>
int main()
{int a = 6;//00000000 00000000 00000000 00000110-补码int n = -15;//11111111 11111111 11111111 11110001-补码int m = a ^ n;//00000000 00000000 00000000 00000110-补码//11111111 11111111 11111111 11110001-补码//11111111 11111111 11111111 11110111-m的补码(重点)//11111111 11111111 11111111 11110110-m的反码//10000000 00000000 00000000 00001001-m的原码printf("%d\n", m);return 0;
}
将两个二进制序列的每一位相异或,结果如下:
4.赋值操作符
所谓赋值操作符,也就是我们经常使用的“ = ”,将一个常量或者常量表达式赋给一个变量。
int a = 1;//不是赋值,是创建之后的初始化
a = 5;//是赋值
int b = 2;
int c = 0;
c = a + b;//也是赋值
除了等号以外,还有一些常用的复合赋值操作符:
+= -= *= /= %= >>= <<= &= |= ^=
这些符合赋值其实是两个运算式的合并,例如:
int a = 2;
a = a + 5 和 a += 5 是一样的效果,后者看起来会更加的简洁
5.单目操作符
所谓单目,也就是这种操作符的操作数只有一个。
- ! 逻辑反操作
- - 负值
- + 正值
- & 取地址
- sizeof 操作数的类型长度(以字节为单位)
- ~ 对一个数的二进制按位取反
- -- 前置后置--
- ++ 前置后置++
- * 间接访问操作符(解引用操作符)
- (类型) 强制类型转换
这些操作符我们大多数都知道,下面我们仅仅讲解一下不是那么熟悉的:
sizeof 操作数的类型长度
sizeof 计算的结果是 size_t 类型
size_t 是无符号整型
对 size_t 类型的数据进行打印,可以使用%zd或%u
int a = 10;
printf("%zd",sizeof(a));
结果为4。
~ 对一个数的二进制按位取反
int a = 0;
printf("%d",~a);
0的补码二进制序列为:
00000000 00000000 00000000 00000000
111111111 111111111 111111111 111111111//为负数,取原码
111111111 111111111 111111111 111111110//反码
10000000 00000000 00000000 00000001//原码
结果为-1。
* 间接访问操作符
int a = 10;
int* p = &a;
*p;//这时候我们的*就是对p进行解引用操作,*p是通过p中存放的地址,找到p指向的对象。
*p 其实就是a。
(类型) 强制类型转换
int a = (int )3.14;
3.14在编译器中会被默认为是double类型,如果直接将其初始化给int型的a,则会在后续操作中出现误差甚至错误,所以要将其强制类型转化为int型。
总结
本期关于操作符的知识讲解到这里就要结束啦,稍后博主将更新C语言基础之——操作符(下)来讲解剩余的操作符。
喜欢博主文章的小伙伴们不要忘记一键三连哦,我们下期再见!