操作符
前言:
本篇的目的主要有两点:
- 各种操作符的介绍
- 表达式求值
1. 操作符的分类
- 算术操作符
- 移位操作符
- 位操作符
- 赋值操作符
- 单目操作符
- 关系操作符
- 逻辑操作符
- 条件操作符
- 逗号表达式
- 下标引用、函数调用和结构成员
注:本篇的重点是操作符的前5类
2.算数操作符
- 加号,减号,乘号的用法,本质上和数学里的运算没区别。
#include<stdio.h>
int main()
{
int a,b,c;
a=5;
b=3;
//==加号==
c=a+b;
printf("%d\n",c);
//==减号==
c=a-b;
printf("%d\n",c);
//==乘号==
c=a*b;
printf("%d\n",c);
return 0;
}
运行结果:
8
2
15
除号与取余操作符
除号就不是简单的直接相除了,要考虑除号两边的数据类型,整型/整型结果还是整型。
#include<stdio.h>
int main()
{
int a;
double b;
//整型/整型
a=5/2;
//浮点型/整型
b=5.0/2;
printf("%d\n",a);
printf("%lf\n",b);
return 0;
}
运行结果:
2
2.500000
- 数学中:5/2=2.5
- 程序中:5/2=2.5
- 程序中:5.0/2=2.500000
这里涉及到了自动类型转换;
整型/整型=整型,就会把小数部分舍去;
浮点型/整型=浮点型,整型/浮点型=浮点型,浮点型/浮点型=浮点型,即不会舍去小数部分;
所以,在写程序时,要注意区分。
你也是可以进行强制类型转换,(数据类型),括号就是强制类型转换符
#include<stdio.h>
int main()
{
printf("%lf\n",(double)5/2);
printf("%d\n",5/2);
return 0;
}
运行结果:
2.500000
2
总结:对于 / 操作符如果两个操作数都为整数,执行整数除法。而只要有浮点数执行的就是浮点数除法
取余运算符%
#include<stdio.h>
int main()
{
printf("%d\n",5%2);//5/2的余数,即1
printf("%d\n",4%10);//4/10的余数是4
return 0;
}
运行结果:
1
4
这里注意:%操作符的两边的操作数必须是整数
总结:. % 操作符的两个操作数必须为整数,返回的是整除之后的余数。
3.移位操作符
移位操作符的作用对象是二进制并且是整数,整型数据是其二进制的补码形式存储在计算机中的;
左移操作符
移位规则是:左边抛弃、右边补0
#include<stdio.h>
int main()
{
int b=0;
int a=5;
b=a<<1;//a的二进制的补码向左移一位
printf("%d\n",a);
printf("%d\n",b);
return 0;
}
运行结果:
5
10
为什么是10呢?
#include<stdio.h>
int main()
{
int a=-5;
int b=0;
b=a<<1;//a的二进制补码向左移一位
printf("%d\n",a);
printf("%d\n",b);
return 0;
}
运行结果:
-5
-10
为什么是-10呢?
总结:
- 左移操作符移动的是二进制的补码;
- 正数的原码,反码,补码相同,负数的原码,反码,补码不同需要转换;
- 计算机中是以二进制的补码形式储存,所以注意负数;
- 左移位规则是:左边抛弃、右边补0;
- 打印是打印的十进制,所以左移后要将补码转换成原码,再转换成十进制数;
- 正数的二进制首位是0,0表正号,即正数的符号位;负数的二进制的首位是1,1表示负号,即负数的符号位;
右移操作符
移位规则:
首先右移运算分两种:
- 逻辑移位
左边用0填充,右边丢弃- 算术移位(平常见的多,绝大多数编译器是算数右移)
左边用原该值的符号位填充,右边丢弃
#include<stdio.h>
int main()
{
int a=5;
int b=a>>1;//这里说一下算数右移
printf("%d\n",a);
printf("%d\n",b);
return 0;
}
运行结果:
5
2
为什么是2呢?
#include<stdio.h>
int main()
{
int a=-1;
int b=0;
b=a>>1;
printf("%d\n",a);
printf("%d\n",b);
return 0;
}
运行结果:
-1
-1
为什么是-1呢?
总结:
- 右移操作符也是移补码,右移操作符分为两种,逻辑右移和算数右移;
- 但在绝大多数的编译器上运行的结果都是算术右移;
- 算数右移补的不是0,而是原先的符号位,正数原先的符号位为0,负数原先的符号位为1;
- 警告⚠ :
对于移位运算符,不要移动负数位,这个是标准未定义的,如2>>-1是不对的;也不要超过范围移,如int类型a,a>>50也是不对的;
4.位操作符
位操作符与移位操作符不一样
位操作符两边也必须是整数
按位与
1.对二进制位进行按位与,与的是补码
2.按位与的规则:
- 对应的二进制位都为1才为1,一个0一个1为0,两0为0;
#include<stdio.h>
int main()
{
int a=3;
int b=-5;
int c=a&b;//这里计算的是a与b的补码
printf("%d\n",c);
return 0;
}
运行结果:
3
为什么是3呢?
按位或
1.对二进制进行按位或,或 的也是补码;
2.按位或的规则:
有1则为1,全0则为0;
或的两边也要是整数;
#include<stdio.h>
int main()
{
int a=3;
int b=-5;
int c=a|b;//这里计算的是a与b的补码
printf("%d\n",c);
return 0;
}
运算结果:
-5
为什么是-5呢?
按位异或
对二进制进行按位异或
按位异或的规则:
1.相同为0,相异为1
2.异或的两边也是整数
#include<stdio.h>
int main()
{
int a=3;
int b=-5;
int c=a^b;//这里是a与b的二进制补码
printf("%d\n",c);
return 0;
}
运行结果:
-8
补:
异或有三个性质:
1.a^a=0;
2.a^0=a
3.异或是遵循交换律,即a^ b^a=a ^a ^b
现有一例题:不能创建临时变量(第三个变量),实现两个数的交换。
//法一:但a,b太大容易溢出
#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",a,b);
return 0;
}
运行结果:
a=20 b=10
//法二:可读性差,不如创建临时变量,只能交换整数,有局限性
#include<stdio.h>
int main()
{
int a=10;
int b=20;
a=a^b;
b=a^b;//即把a代入,a^b^b,b^b=0,所以a^b^b=a^0=a
a=a^b;//把a,b带入,即a^b^a=0^b=b
printf("a=%d b=%d",a,b);
return 0;
}
运行结果:
a=20 b=10
总结:
- 位操作符的三个都是针对整数的二进制的补码;
- 按位与的规则:两个1才为1,有0则0;
- 按位或的规则:有1则为1,两个0则为0;
- 按位异或的规则:相同为0,相异为1;
5.赋值运算符
赋值操作符是一个很棒的操作符,他可以让你得到一个你之前不满意的值。也就是你可以给自己重新赋值。
赋值操作符可以连续赋值
#include<stdio.h>
int main()
{
int a=120;
a=50;
printf("%d\n",a);
int x=3;
int y=4;
int b=0;
b=a=x+y;
printf("%d\n",b);
return 0;
}
运行结果:
50
7
复合赋值符
#include<stdio.h>
int main()
{
int a=5;
int b=5;
a=a+5;
b+=5;//b=b+5
printf("%d %d",a,b);
//其余的用法一个道理
return 0;
}
运行结果:
10 10
总结:
- 赋值操作符可以改变原来的数,可以连续;
- 复合操作符,可以简化代码;
6.单目操作符
单目操作符是指,只有一个操作数的符号
逻辑反操作符
将原来的真变为假,将原来的假变为真
C语言中0表示假,非0即真
#include<stdio.h>
int main()
{
int a=5;
printf("%d\n",a);
printf("%d\n",!a);
if(!a)//将原来的真变为假
printf("hehe\n");
else
printf("haha");
return 0;
}
运行结果:
5
0
haha
补:
- 布尔类型,只能用来表示真假,真:true 假:false
- 声明头文件#include<stdbool.h>
#include<stdio.h>
#include<stdbool.h>
int main()
{
_Bool flag=true;
if(flag)
printf("hehe");
if(false)
printf("haha");
return 0;
}
运行结果:
hehe
注意声明头文件时是小写的b,用的时候是大写的B
负号操作符,正号操作符
负号操作符:变为相反数,正变为负,负变为正
正号操作符:正号,一般省略,写不写都无所谓
#include<stdio.h>
int main()
{
int a=5;
int b=-7;
printf("%d\n",-a);
printf("%d\n",-b);
return 0;
}
运行结果:
-5
7
取地址操作符与间接访问操作符(解引用操作符)
- &是用来取出某个对象在内存中的地址,可以是变量,字符,数组,数组元素;
- *则是存通过指针变量找到对象,即解引用;
#include<stdio.h>
int main()
{
int a=7;
printf("%p\n",&a);
int* p=&a;//int*是整型指针类型,p是指针变量
*p;
printf("%d\n",a);
printf("%d\n",*p);//可以简单理解为a
return 0;
}
运行结果:
00000025D56FFBE4//地址不是不变的
7
7
sizeof()操作符
- 求操作数所占空间大小,单位是字节
- sizeof既是关键字,也是操作符
- sizeof内部的表达式是不参与计算的
#include<stdio.h>
int main()
{
int a=5;
short s=5;
printf("%d\n",sizeof(a));
printf("%d\n",sizeof(int));
printf("%d\n",sizeof(s=s+a));//最终的空间由s决定
printf("%d\n",s);//sizeof内部的表达式是不参与计算的
//''''''''
return 0;
}
运行结果:
4
4
2
5
~取反操作符
- 作用:对一个数的二进制按位取反,包括符号位
- 按位取反~,操作数也得是整数
#include<stdio.h>
int main()
{
int a=0;
printf("%d",~a);
return 0;
}
运行结果:
-1
为什么是-1呢?
自增,自减操作符
- 前置自增(++a):先自增1,即a=a+1;后使用a的值
- 后置自增(a++):先使用a的值,再自增1,即a=a+1
- 前置自减(–a):先自减1,即a=a-1;后使用a的值
- 后置自减(a–):先使用a的值,再自减1,即a=a-1
#include<stdio.h>
int main()
{
int a=3;
int b=++a;
printf("%d %d",a,b);
return 0;
}
运行结果:
4 4
#include<stdio.h>
int main()
{
int a=3;
int b=a++;
printf("%d %d",a,b);
return 0;
}
运行结果:
4 3
自减的道理与自增一样,大家可以试试!
总结:
本章专门介绍了部分操作符的原理及用法,希望对你有所帮助,如果对你帮助很大,或喜欢本篇的话,不妨点个赞,如果想要学习更多操作符,不妨点个关注,下篇我们接着介绍,如果有什么疑问或者看法,欢迎在评论区发言。
拜拜,我们下篇见!!!