操作符详解(上)
我们了解在C语言中有许多的操作符,这里我们详细介绍部分操作符
一,算术操作符(双目操作符)
1:‘+’,‘-’,‘*’
这三种算数操作符就相当于数学运算中的加法,减法,和乘法,是对两个数进行数学运算,
int a=1;
int b=2;
\\加法
int c=a+b;(结果为3)
\\减法
int c=b-a;(结果为1)
\\乘法
int c=a*b;(结果为2)
2:‘/’,‘%’
==‘/’==进行的操作相当于数学运算中的除法,但有些许不同,分为两种情况
第一种:当该操作符两端都为整形,结果也为整形,该操作符是将两数相除取商,例如5/3应该是商1余2,但结果只会显示商1
第二种:若想要输出的结果为小数,那么就需要除号两边之一为浮点数,并且输出的结果也要为浮点数,
‘%’ 进行的操作为将%号两边的数相除取余,例如5/3应该是商1余2,但结果只会显示余数2,
因为上述操作符运算所需变量为两个,也就是运算对象的个数是2,所以又被称作双目操作符。
一,单目操作符
1:‘+’,‘-’
这里的‘+’,‘-’并不是算数中的加号与减号,而是表示正数与负数,通常来说负数前会有‘-’号,而正数前的‘+’号通常省略。
2:‘!’
'!'为逻辑反操作符,用于对布尔值进行反转,举个例子:条件判断中,一般条件成立即为真,布尔值为非0,加上!后非0为假,0为真,也就是条件成立为假,不成立为真,我们设计一个简单的代码来看一下具体效果:
#include<stdio.h>
int main()
{
int a = 0;
while (scanf("%d", &a) != EOF)
{
if (a > 0)
{
printf("%d\n", a);
}
else
{
printf("NO\n");
}
}
return 0;
}
这是没有加‘!’操作符时的结果,
#include<stdio.h>
int main()
{
int a = 0;
while (scanf("%d", &a) != EOF)
{
if(!(a > 0))
{
printf("%d\n", a);
}
else
{
printf("NO\n");
}
}
return 0;
}
这是加上!操作符后的结果。
3:‘&’
用于获取变量的内存地址。
4:‘*’
间接引用和解引用操作符,获取指针所指向的值。
5:‘sizeof’
用于获取数据类型或对象在内存中的大小(以字节为单位)
6:‘++’与‘–’
自增‘++’与自减‘–’,作用分别为将操作数的值增加1和减少1。
在实际操作中又分为前置和后置两种情况,
‘++’和‘–’前置为操作数先变化后使用,后置为操作数先使用后变化,如下图所示:
#include<stdio.h>
int main()
{
int a = 1;
int b = 1;
int c = 1;
int d = 1;
printf("%d\n",++a);
printf("a=%d\n",a);
printf("%d\n",b++);
printf("b=%d\n",b++);
printf("%d\n",--c);
printf("c=%d\n",--c);
printf("%d\n",d--);
printf("d=%d\n",d--);
return 0;
}
其输出结果为:
这里可以看到前置和后置操作符最终输出的结果并不相同。
介绍完C语言中比较简单的两种操作符,我们再来介绍一下比较复杂的操作符,位操作符
三,移位操作符
在介绍移位操作符前,还得先介绍十进制数字在计算机中的存储方式以及源码,反码,补码。
十进制数在计算机中通常不是直接储存的,而是先转化位二进制数在进行存储。而为了区分正负数,计算机对有符号整数采用了不同的编码储存方式,也就是源码,反码,补码。
在现代的计算机中主要采用的数字集成电路完成,数字电路通过高低电平只能表示0和1,所以就出现了,计算机只会识别0和1。无论是存储还是计算,计算机均采用二进制体系完成。
在C语言中不同数据类型的大小不一样,如int类型每个占4个字节,而每个字节又等于8个比特位。
sizeof(int)=1byte=8bit每个比特位存储的便是0或1。
一个int类型共有32个比特位,每个比特位只能是0或1,也就是说在计算机中整型是采用二进制的方式存储的,那么int的取值范围便是-231~231-1
了解了上面的基本概念后,我们就来详细了解一下源码,反码和补码,
注意,源码,反码和补码只能应用在整数中
而正整数和负整数的存储是不一样的,我们分开讨论:
正整数:正整数的源码=反码=补码
负整数:负整数在计算机中是以补码的形式进行储存的,那么该如何得到负整数的补码?
首先,我们要了解计算机区分正,负整数的原理,在计算机中为了区分正负整数,在整形的32位比特位中,正整数的最高位比特位为0,而负整数的最高位为1,将负整数的源码除了最高位的符号位按位取反得到负整数的反码,反码加1得到负整数的补码。
下面以x64环境下的整型存储为例:
int a=5;
a的源码=反码=补码为:0000 0000 0000 0000 0000 0000 0000 0101
int b=-5;
b的源码为:1000 0000 0000 0000 0000 0000 0000 0101
反码为:1111 1111 1111 1111 1111 1111 1111 1010
补码为:1111 1111 1111 1111 1111 1111 1111 1011
而计算机之所以会有三种储存整形的方式的原因都是因为计算的难易,
源码的一个缺点是存在两种不同的表示方式来表示0(0000 和 1000),这可能导致一些不必要的复杂性。
反码的一个优点是消除了0的两种表示,但缺点是进行加减运算时相对复杂。
补码是最常用的表示法,特别是在现代计算机中。补码的一个主要优点是它使得加法运算更加简单,因为对于任何整数x,都有 x + (-x) = 0,这在补码表示下总是成立。另一个优点是只有一个0的表示(0000),这使得处理更加简单。
下面就介绍2种移位操作符:
>>(右移操作符)和<<(左移操作符)
注意:移位操作符的操作数只能是整数
3.1 <<(左移操作符)
3.2 <<(左移操作符)
移位规则:将整数的补码整体向左移动一位,左边的抛弃,右边空的补0;
演示:
#include<stdio.h>
int main()
{
int num = 1;
num = num << 1;
printf("%d\n", num );
return 0;
}
输出结果:
移位图解:
3.2 >>(右移操作符)
右移操作符相对左移来说较为复杂,分为逻辑右移和算术右移
逻辑右移:左边⽤0填充,右边丢弃
逻辑右移一位图解:
算术右移:左边⽤原该值的符号位填充,右边丢弃
图解:
注意:对于移位运算符,不要移动负数位,这个是标准未定义的
四.位操作符
注意:位操作符的操作数必须是整数
4.1‘&’按位与
该操作符在二进制层面上对两个数进行操作,它比较两个数的相应位,只有当两个相应的位都为1时,结果位才为1,否则为0;
代码和图解演示:
#include<stdio.h>
int main()
{
int num1 = 6;
int num2 = 13;
int num3 = num1 & num2;
printf("%d\n", num3 );
return 0;
}
图解:(前面为0的位省略)
4.2‘|’按位或
该操作符在二进制层面上对两个数进行操作,它比较两个数的相应位,只要两个数中任意一个数的相应位为1,那么结果位就为1,否则为0;
代码和图解演示:
#include<stdio.h>
int main()
{
int num1 = 2;
int num2 = 13;
int num3 = num1 | num2;
printf("%d\n", num3 );
return 0;
}
图解:(前面为0的位省略)
4.3‘^’按位异或
该操作符在二进制层面上对两个数进行操作,它比较两个数的相应位,当两个数的相应位不同时,结果位为1;当两个数的相应位相同时,结果位为0。
代码和图解演示:
#include<stdio.h>
int main()
{
int num1 = 3;
int num2 = 13;
int num3 = num1 ^ num2;
printf("%d\n", num3 );
return 0;
}
图解:(前面为0的位省略)
4.4‘~’按位取反
该操作符用于对二进制数的每一位执行逻辑非操作。具体地说,它将二进制数中的每个0变为1,每个1变为0。
代码和图解演示:
#include<stdio.h>
int main()
{
int num1 = 2;
num1 = ~num1;
printf("%d\n", num1 );
return 0;
}
图解:(前面为0的位省略)