🦖作者:学写代码的恐龙
🦖博客主页:学写代码的恐龙博客主页
🦖专栏:【初级c语言】
🦖语录:❀未来的你,一定会感谢现在努力奋斗的自己❀
一:操作符分类
1:算术操作符
2:移位操作符
3:位操作符
4:赋值操作符
5:单目操作符
6:关系操作符
7:逻辑操作符
8:条件操作符
9:逗号表达式
10:下标引用、函数调用和结构成员
二:算数操作符
+ - * / %
注意:对于除法操作符来说,两边的操作数都是整数,执行的是整数除法,即就是结果只取整数部分。如果想计算出小数,除号的两端至少有一个操作数是浮点数
//除法操作符 int main() { int ret1 = 10 / 3; printf("%d\n", ret1); double ret2 = 10.0 / 3; printf("%lf\n",ret2); printf("%.1lf\n", ret2);//得到一位小数 return 0; } //结果: 3 3.333333 3.3
//取模(取余)操作符(得到余数) int main() { int ret = 10 % 3; printf("%d\n", ret); return 0; } //结果: 1
注意:取模操作符两边的操作数只能是整数(整型类型),除了%操作符,其他几个操作符可以用于整数和浮点数
三:移位操作符
<< 左移操作符 >> 右移操作符
注:移位操作符的操作数只能是整数。 这里说的移位是移的二进制位
//移位操作符 int main() { int a = 10; int b = a << 2;//a向左移动两位的结果放到b里 int c = a >> 1;//a向右移动一位的结果放到c里 printf("%d\n", b); printf("%d\n", c); return 0; } //结果: 40 2
既然上面已经说到移位操作符移动的是二进制位,那就先来给大家介绍一下二进制。整数的二进制表示形式其实有三种:原码、反码、补码
例如:
12-数值 二进制:1100 八进制:14 十进制:12 十六进制:C 这里的12只是一个数值,我们可以用不同的进制将其表示出来 以上这些都可以用来表示12
对于正数,它的 原码、反码、补码都是相同的
例如: 10的二进制是1010,在计算机中一个整型在计算机中占4个字节(32bit),补全就是:00000000000000000000000000001010,这是正10,在计算机中-10如何表示呢?在计算机中用二进制的最高位区分正负,最高位如果是0,那就表示正数,最高位如果是1,那就表示负数,因此:二进制的最高位在计算机中又被称作符号位,所以-10在计算机中用10000000000000000000000000001010表示。
原码:按照一个数的正负,直接写出它的二进制表示形式得到的就是原码
例如:10的原码:00000000000000000000000000001010 -10的原码:10000000000000000000000000001010
正数的原码、反码、补码都是相同的,负数的反码和补码要经过计算
反码:原码的符号位不变,其他按位取反得到的就是反码
例如:10的反码:00000000000000000000000000001010(正数的原码、反码、补码都是相同) -10的反码:11111111111111111111111111110101
补码:反码加1得到的就是补码
例如:10的补码:00000000000000000000000000001010(正数的原码、反码、补码都是相同) -10的补码:11111111111111111111111111110110
内存中存的是二进制的补码形式,所以在参与移位的时候,移的是补码
原码、反码、补码三者之间的转换
可见:不管是原码到补码,还是补码到原码,都可以通过“符号位不变,其他位按位取反后再+1”得到,这便是计算机的奇妙之处
接着介绍左移操作:
3.1:左移
3.1.1:正数左移
以10为例,要对其进行移位操作,首先要得到10的补码,10的补码是00000000000000000000000000001010,向左移动一位形象来说就是把10的二进制的补码向左移动一位,这时右边就空出来一位,这时就需要进行补0,最终得到00000000000000000000000000010100,对应十进制就是20.
int main() { int a = 10; int b = a << 1;//把a向左移动一位的结果放到b里 printf("%d\n", a); printf("%d\n", b); return 0; } //结果: 10 20 //注意:a的值并不变
3.1.2:负数左移
以-10为例,要对其进行移位操作首先要得到-10的补码,根据上面的分析我们直到-10的补码是:11111111111111111111111111110110,和正10一样,如果要对其进行左移一位的操作,形象来说就是把-10的二进制的补码向左移动一位,这时右边就空出来一位,这时就需要进行补0,最终得到11111111111111111111111111101100,需要注意的是:我们得到的是补码,而在屏幕上打印出来的是由二进制的原码形式转化出来的数字,因此我们需要把的得到的补码转化为原码的形式,通过上面介绍的方式我们并不难得出该补码的原码是:10000000000000000000000000010100,该原码对应的十进制就是-20,最终-10左移1位得到的就是-20.
//-10左移一位 int main() { int a = -10; int b = a << 1; printf("%d\n", a); printf("%d\n", b); return 0; } //结果: -10 -20
可见对一个十进制数字左移一位有×2的效果。
3.2:右移
首先右移运算分两种:
1. 逻辑移位 左边用0填充,右边丢弃 2. 算术移位(平时比较常见) 左边用原该值的符号位填充,右边丢弃
具体采用何种右移主要取决于编译器,大多数编译器都采用算数右移
//算数右移:将-1向右移动一位 int main() { int a = -1; int b = a >> 1; printf("%d\n", a); printf("%d\n", b); return 0; } //结果: -1 -1
注意:无论是向左移还是向右移都不能移动负数位!
四:位操作符
& //按位与 | //按位或 ^ //按位异或
注意:以上三个操作符的操作数必须是整数,同时也是针对二进制位(内存中的补码)进行操作的
4.1:按位与
//按位与 int main() { int a = 3; //00000000000000000000000000000011(3的原、反、补码) int b = -5; //10000000000000000000000000000101(-5的原码) //11111111111111111111111111111010(-5的反码) //11111111111111111111111111111011(-5的补码) int c = a & b; //00000000000000000000000000000011(3的补码) //11111111111111111111111111111011(-5的补码) //按位与的操作是:对应的二进制位上有0,与的结果就是0,只有当两个都是1,结果才是1。 //00000000000000000000000000000011(按位与得到的结果,这还是内存中的补码形式,打印出来的是二进制位对应的原码形式,但是这里的符号位是0,说明是正数,那么它的原码、反码、补码是一样的) //此时打印出来的结果就是3 printf("%d\n", c); return 0; } //结果: 3
4.2:按位或
//按位或 int main() { int a = 3; //00000000000000000000000000000011(3的原、反、补码) int b = -5; //10000000000000000000000000000101(-5的原码) //11111111111111111111111111111010(-5的反码) //11111111111111111111111111111011(-5的补码) int c = a | b; //00000000000000000000000000000011(3的补码) //11111111111111111111111111111011(-5的补码) //按位或的操作是:对应的二进制位上有1,或的结果就是1,只有当两个都是0,结果才是0。 //11111111111111111111111111111011(按位与得到的结果,这还是内存中的补码形式,打印出来的是二进制位对应的原码形式,这里的符号位是1,说明是负76数,此时我们就需要求出它的原码) //10000000000000000000000000000100 //10000000000000000000000000000101(打印时需要的原码) //此时打印出来的就是-5 printf("%d\n", c); return 0; } //结果: -5
4.3:按位异或
//按位异或 int main() { int a = 3; //00000000000000000000000000000011(3的原、反、补码) int b = -5; //10000000000000000000000000000101(-5的原码) //11111111111111111111111111111010(-5的反码) //11111111111111111111111111111011(-5的补码) int c = a ^ b; //00000000000000000000000000000011(3的补码) //11111111111111111111111111111011(-5的补码) //按位异或的操作是:对应的二进制位相同为0,不同为1。 //11111111111111111111111111111000(按位与得到的结果,这还是内存中的补码形式,打印出来的是二进制位对应的原码形式,这里的符号位是1,说明是负数数,此时我们就需要求出它的原码) //10000000000000000000000000000111 //10000000000000000000000000001000(打印时需要的原码) //此时打印出来的就是-8 printf("%d\n", c); return 0; } //结果: -8
4.4:不创建临时变量,实现对两个整数的交换
4.4.1:方法一
//不创建临时变量,实现对两个整数的交换 int main() { int a = 3; int b = 5; printf("%d %d\n", a, b); a = a + b;//把a与b的和8放到a里面 b = a - b;//此时a里面是a与b的和8,再减去b(5)得到的就是a的值(3),把这个值放到b里面去,此时的b就是之前a的值了,也就是3 a = a - b;//因为此时的a里面存的还是a与b的和(8),b的值是之前a的值了,也就是3,此时a-b就是就是之前b的值5,把5放到a里面 //经过上面3个表达式就实现了不创建临时变量,实现对两个整数的交换 printf("%d %d\n", a, b); return 0; } //结果: 3 5 5 3
注意:此方法存在一个问题就是:当a和b的数值比较大的时候,它们各自不溢出,但当加到一起时就有可能出现溢出的情况。