C语言操作符详解
1,操作符分类:
- 算数操作符
- 移位操作符
- 位操作符
- 赋值操作符
- 单目操作符
- 关系操作符
- 逻辑操作符
- 条件操作符
- 逗号操作符
- 下标引用,函数调用和结构成员
2,算术操作符
+ - * / %
整形的除法 1/2 --> 0
浮点型除法1.0/2 --> 0.5
1/2.0 --> 0.5
1.0/2.0 --> 0.5
%取模操作符计算的是整出后的余数,取模操作符两端必须是整数
3,移位操作符
<< 左移操作符
>> 右移操作符
注 :移位操作符的操作数只能是整数。移位操作符移动的是二进制位。
这里就要说一下二进制。
我们在编程里常用的进制有二进制(0~1),八进制(0~7),十进制(0~9),十六进制(0~9,a~f)。
整数的二进制表示有三种:原码 反码 补码(在计算机中存储的是补码)
我们知道整形有四个字节,占32个bit位,最高位为符号位,0表示正,1表示负。
对于正的整数来说,原码反码补码是相同的。
对于负的证书来说,原码反码补码是需要计算的。
原码是将整数用二进制数表示,最高位为符号位(1)
反码是符号位不变,其余位取反
补码是反码+1
例如7表示成二进制是111,那么由于它占32个bit位,所以
原码:00000000000000000000000000000111
反码:00000000000000000000000000000111
补码:00000000000000000000000000000111
对于-7
原码:1000000000000yu0000000000000000111(最高位为符号位,1表示负,0表示正)
反码:111111111111111111111111111111111000(符号位不变,其他位按位取反)
补码:111111111111111111111111111111111001(反码+1)
左移操作符,就是左边丢弃,右边补0;
例如:7<<1(7左移1位)在计算机存储的是补码,所以是补码左移
00000000000000000000000000111
左移一位,就是将最左边的丢弃,在最右边补上0;
00000000000000000000000001110(这个计算出来的是补码,我么要是计算输出的数的话,需要将原码算出来,再求他的十进制数)
因为正数的原码,反码,补码相同,所以
原码为:00000000000000000000000001110
那计算出来的十进制数就是2³+2²+2¹=14;所以将7左移一位计算的结果是14。
例如:-7<<1(-7左移1位)
-7:111111111111111111111111111111001
左移一位后:111111111111111111111111111110010(补码)
反码:111111111111111111111111111110001(补码-1)
原码:100000000000000000000000001110(反码符号位不变,其余位取反)
那计算出来的就是-(2³+2²+2¹)=-14;所以将-7左移一位计算出来的是-14。
实际上在a没有复制的情况下,自身的值不会放生改变;
右移操作符分为两种:算术移位和逻辑移位
- 算数移位:右边丢弃,左边补原符号位(我们一般编译器上用的都是算术移位)
- 逻辑移位:右边丢弃,左边补0
算术移位:
例如:7>>1(7右移1位)在计算机存储的是补码,所以是补码右移
00000000000000000000000000111
右移一位,就是将最右的丢弃,在最左补上原符号位(0);
00000000000000000000000000011(这个计算出来的是补码,我么要是计算输出的数的话,需要将原码算出来,再求他的十进制数)
因为正数的原码,反码,补码相同,所以
原码为: 00000000000000000000000000011
那计算出来的十进制数就是2¹+2⁰=3;所以将7右移一位计算的结果是3。
例如:-7>>1(7右移1位)在计算机存储的是补码,所以是补码右移
-7:11111111111111111111111111111001
右移一位后:11111111111111111111111111111100(补码)
反码:11111111111111111111111111111011(补码-1)
原码:1000000000000000000000000100(反码符号位不变,其余位取反)
那计算出来的就是-2²=-4;所以将-7左移一位计算出来的是-4。
逻辑移位:
对于正数来说逻辑移位和算术移位结果是相同的,但是对于符数在不同例如:-7按算术移位计算结果
-7:111111111111111111111111111111111001
算术移位后:011111111111111111111111111111111100
反码:011111111111111111111111111111111011
补码:00000000000000000000000000000100
计算的结果是2²=4。
对于移位运算符,不要移动负位数,这个标准是未定义的。
4,位操作符
位操作符有:
& :按(二进制)位与
| :按(二进制)位或
^ :按(二进制)位异或
注:他们的操作数只能是整数;
按位与&:
int a=3;
int b=-5;
int c=a&b;
printf("%d",c);
3的补码:00000000000000000000000000000011
-5的原码:10000000000000000000000000000101
-5的反码:111111111111111111111111111111111010
-5的补码:111111111111111111111111111111111011
3&-5(都为真表示真,有假则表示假)
所以3&-5:00000000000000000000000000000011(补码)
为正数,原反补码相同,所以打印结果应该是:2¹+2⁰=3;
按位或|:
int a=3;
int b=-5;
int c=a|b;
printf("%d",c);
3的补码:00000000000000000000000000000011
-5的补码:111111111111111111111111111111111011
3|-5(有真为真,同为假则表示假)
所以3|-5:111111111111111111111111111111111011(补码)
为负数;
反码(补码-1):111111111111111111111111111111111010
原码:10000000000000000000000000000101
所以打印结果应该是:-(2²+2⁰)=-5;
按位异或^:
int a=3;
int b=-5;
int c=a^b;
printf("%d",c);
3的补码:00000000000000000000000000000011
-5的补码:111111111111111111111111111111111011
3^-5(相同为0,相异为1)
所以3^-5:111111111111111111111111111111111000(补码)
为负数;
反码(补码-1):111111111111111111111111111111110111
原码:10000000000000000000000000001000
所以打印结果应该是:-(2³)=-16;
应用1:不创建临时变量,实现两个数的交换
1.正常创建临时变量
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
//正常创建临时变量,交换两个数
int main()
{
int a = 3;
int b = 5;
printf("交换前:a=%d,b=%d\n", a,b);
int c = a;
a = b;
b = c;
printf("交换后:a=%d,b=%d\n", a, b);
return 0;
}
2.不创建临时变量,将a+b重新赋给a;(但是这种交换可能会导致溢出)
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
int main()
{
int a = 3;
int b = 5;
printf("交换前:a=%d,b=%d\n", a, b);
a = a+b;
b = a-b;
a = a-b;
printf("交换后:a=%d,b=%d\n", a, b);
return 0;
}
3.利用位操作符
我们可以推得a^a=0;0^a=a;
所以a^a^b=b;a^b^b=a;于是我们就可以利用这种方法完成两个数的交换
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
int main()
{
int a = 3;
int b = 5;
printf("交换前:a=%d,b=%d\n", a, b);
a = a ^ b;
b = a ^ b;
a = a ^ b;
printf("交换后:a=%d,b=%d\n", a, b);
return 0;
}
但是这种方法速度慢,而且只适用于整数,并且可读性不好。所以一般我们交换两个变量还是要用创建中间变量的方式
应用2:编写代码实现:求一个整数存储在二进制中1的个数
#include<stdio.h>
//编写代码实现:求一个整数存储在二进制中1的个数
int main()
{
int a = 10;
int i = 0;
int count = 0;
for (i = 0;i < 32;i++)
{
if (a & (1 << i))//与1按位与能判断最后一位是不是1,再左移判断倒数第二位,二进制中整形存储32位,依次判断。
count++;
}
printf("二进制中一的个数=%d\n", count);
return 0;
}
5,赋值操作符
=
赋值操作是在创建变量之后实现的,创建变量的时候赋的值成为变量初始化。
赋值操作符可以连续赋值,有后往前计算,但是这样写不便于调试,可读性差。
复合赋值符:
+=-=
*=
/=
%=
>>=
<<=
&=
\=
^=
这些运算符都可以写成复合的效果
比如:
a=a+5就可以写成a+=5;
6,单目操作符
! 逻辑反操作符
- 负值
+ 正值
& 取地址
sizeof 操作数的类型长度(以字节为单位)
~ 对一个数的二进制按位取反
-- 前置后置--
++ 前置后置++
* 间接访问操作符(解引用操作符)(类型) 强制类型转换
单目操作符是指只有一个操作数的操作符;
注意:sizeof是一个操作符,计算的是变量所占内存空间的大小,单位是字节
计算类型所创建的变量占据空间的大小,单位是字节。
可以写成int a=10;sizeof(a);
也可以写成 sizeof(int);
可以写成sizeof a;也可以写成sizeof(a);(不是函数)(strlen是库函数,用于求字符串长度)
但需要注意指针变量所占的字节都是相同的4或者8;
~:按位取反,就是每一位都取反(0取1,1取0)
0按位取反:~0
补码:00000000000000000000000000000000
~0:11111111111111111111111111111111 (补码)
反码:11111111111111111111111111111110原码:10000000000000000000000000000001
计算结果为-2⁰=-1;
应用:改变二进制的某一位:0改为1(给这一位按位或1)
00000000000000000000000000001111(使13的倒数第二位变成1)
int a=13;
13的补码:00000000000000000000000000001101
|:00000000000000000000000000000010
这个数有1<<1(1左移一位)得到;
a|=(1<<1);
1改为0(给这一位按位与0,其他位不变,按位与1,就相当于给这一位按位与1再按位取反)
int a=13;
要得到:00000000000000000000000000000101(使13的倒数第四位变成0)
13的补码:00000000000000000000000000001101
& 11111111111111111111111111110111
这个数有 0000000000000000000000000001000按位取反得到,这个数再有1<<4(1左移4位)得到。
00000000000000000000000000001111;
a&=(~(1<<4));
++:前置++:先++,后使用;
后置++:先使用,后++。
--:前置--:先--,后使用;
后置--:先使用,后--。
*:解引用操作符,通常和取地址一起使用,例如:
*p是通过指针变量p存储的地址找到变量a的空间,并对变量a的只进行了改变。
7,关系操作符
>
<>=
<=
!= 用于测试“不相等”
== 用于测试“相等”
若是直接用==比较字符的话,实际上比较的是首元素的地址,对字符的比较应该用strcmp库函数,需要包含<string.h>的头文件。
8,逻辑操作符
&&:逻辑与 (表示并且)
||:逻辑或 (表示或者)
用打印闰年的代码举个例子:
#include <stdio.h>
int main()
{
int year = 1000;
for (year = 1000;year <= 2000;year++) {
if (((year % 4 == 0) && (year % 100 != 0)) || (year % 400 == 0))
{
printf("%d ",year);
}
}
return 0;
}
计算下列代码的输出结果:
#include<stdio.h>
int main()
{
int i = 0, a = 0, b = 2, c = 3, d = 4;
i = a++ && ++b && d++;
//i=a++||++b||d++;
printf("a=%d\nb=%d\nc=%d\nd=%d\n", a, b, c, d);
return 0;
}
输出结果应该为a=1;b=2;c=3;d=4,
a++为后置++,先使用后++,第一项为0,后面不需计算;
#include<stdio.h>
int main()
{
int i = 0, a = 0, b = 2, c = 3, d = 4;
//i = a++ && ++b && d++;
i=a++||++b||d++;
printf("a=%d\nb=%d\nc=%d\nd=%d\n", a, b, c, d);
return 0;
}
计算结果应该为1,3,3,4
这是或者关系,第一项为假,看第二项第二项为真,a和b都已经加过了,第三项不计算,所以d没有加。
总结:&&左边为假,右边就不计算了。
||左边为真,右边就不计算了。
原文地址:https://blog.csdn.net/a002345001/article/details/144307410
免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!