你真的了解操作符吗?看看这一篇,你会有不一样的收获。

操作符

前言:

本篇的目的主要有两点:

  • 各种操作符的介绍
  • 表达式求值

1. 操作符的分类

  • 算术操作符
  • 移位操作符
  • 位操作符
  • 赋值操作符
  • 单目操作符
  • 关系操作符
  • 逻辑操作符
  • 条件操作符
  • 逗号表达式
  • 下标引用、函数调用和结构成员

注:本篇的重点是操作符的前5类


2.算数操作符

你真的了解操作符吗?看看这一篇,你会有不一样的收获。_第1张图片

  • 加号,减号,乘号的用法,本质上和数学里的运算没区别。
#include
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
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
int main()
{
	printf("%lf\n",(double)5/2);
	printf("%d\n",5/2);
	return 0;
}

运行结果:
2.500000
2

总结:对于 / 操作符如果两个操作数都为整数,执行整数除法。而只要有浮点数执行的就是浮点数除法


取余运算符%

#include
int main()
{
	printf("%d\n",5%2);//5/2的余数,即1
	printf("%d\n",4%10);//4/10的余数是4
	return 0;
}

运行结果:
1
4

这里注意:%操作符的两边的操作数必须是整数
总结:. % 操作符的两个操作数必须为整数,返回的是整除之后的余数。


3.移位操作符

你真的了解操作符吗?看看这一篇,你会有不一样的收获。_第2张图片
移位操作符的作用对象是二进制并且是整数,整型数据是其二进制的补码形式存储在计算机中的;

左移操作符

移位规则是:左边抛弃、右边补0

#include
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呢?
你真的了解操作符吗?看看这一篇,你会有不一样的收获。_第3张图片


#include
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表示负号,即负数的符号位;

右移操作符

移位规则:
首先右移运算分两种:

  1. 逻辑移位
    左边用0填充,右边丢弃
  2. 算术移位(平常见的多,绝大多数编译器是算数右移)
    左边用原该值的符号位填充,右边丢弃
#include
int main()
{
	int a=5;
	int b=a>>1;//这里说一下算数右移
	printf("%d\n",a);
	printf("%d\n",b);
	return 0;
}

运行结果:
5
2

为什么是2呢?
你真的了解操作符吗?看看这一篇,你会有不一样的收获。_第4张图片


#include
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.位操作符

位操作符与移位操作符不一样
位操作符两边也必须是整数

你真的了解操作符吗?看看这一篇,你会有不一样的收获。_第5张图片

按位与

1.对二进制位进行按位与,与的是补码
2.按位与的规则:

  • 对应的二进制位都为1才为1,一个0一个1为0,两0为0;
#include
int main()
{
	int a=3;
	int b=-5;
	int c=a&b;//这里计算的是a与b的补码
	printf("%d\n",c);
	return 0;
}

运行结果:
3

为什么是3呢?
你真的了解操作符吗?看看这一篇,你会有不一样的收获。_第6张图片
你真的了解操作符吗?看看这一篇,你会有不一样的收获。_第7张图片


按位或

1.对二进制进行按位或,或 的也是补码;
2.按位或的规则:
有1则为1,全0则为0;
或的两边也要是整数;

#include
int main()
{
	int a=3;
	int b=-5;
	int c=a|b;//这里计算的是a与b的补码
	printf("%d\n",c);
	return 0;
}

运算结果:
-5
为什么是-5呢?

你真的了解操作符吗?看看这一篇,你会有不一样的收获。_第8张图片
你真的了解操作符吗?看看这一篇,你会有不一样的收获。_第9张图片


按位异或

对二进制进行按位异或
按位异或的规则:
1.相同为0,相异为1
2.异或的两边也是整数

#include
int main()
{
	int a=3;
	int b=-5;
	int c=a^b;//这里是a与b的二进制补码
	printf("%d\n",c);
	return 0;
}

运行结果:
-8

你真的了解操作符吗?看看这一篇,你会有不一样的收获。_第10张图片
你真的了解操作符吗?看看这一篇,你会有不一样的收获。_第11张图片
补:
异或有三个性质:
1.a^a=0;
2.a^0=a
3.异或是遵循交换律,即a^ b^a=a ^a ^b

现有一例题:不能创建临时变量(第三个变量),实现两个数的交换。

//法一:但a,b太大容易溢出

#include
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
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.赋值运算符

赋值操作符是一个很棒的操作符,他可以让你得到一个你之前不满意的值。也就是你可以给自己重新赋值。

你真的了解操作符吗?看看这一篇,你会有不一样的收获。_第12张图片

赋值操作符可以连续赋值

#include
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

复合赋值符

你真的了解操作符吗?看看这一篇,你会有不一样的收获。_第13张图片

#include
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.单目操作符

单目操作符是指,只有一个操作数的符号
你真的了解操作符吗?看看这一篇,你会有不一样的收获。_第14张图片

逻辑反操作符

将原来的真变为假,将原来的假变为真
C语言中0表示假,非0即真

#include
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
#include
#include
int main()
{
	_Bool flag=true;
	if(flag)
	 	printf("hehe");
	if(false)
		printf("haha");
	return 0;
}

运行结果:
hehe

注意声明头文件时是小写的b,用的时候是大写的B


负号操作符,正号操作符

负号操作符:变为相反数,正变为负,负变为正
正号操作符:正号,一般省略,写不写都无所谓

#include
int main()
{
	int a=5;
	int b=-7;
	printf("%d\n",-a);
	printf("%d\n",-b);
	return 0;
}

运行结果:
-5
7

取地址操作符与间接访问操作符(解引用操作符)

  • &是用来取出某个对象在内存中的地址,可以是变量,字符,数组,数组元素;
  • *则是存通过指针变量找到对象,即解引用;
#include
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
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
int main()
{
 	int a=0;
	printf("%d",~a);
	return 0;
}

运行结果:
-1

为什么是-1呢?
你真的了解操作符吗?看看这一篇,你会有不一样的收获。_第15张图片
自增,自减操作符

  • 前置自增(++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
int main()
{
	int a=3;
	int b=++a;
	printf("%d %d",a,b);
	return 0;
}

运行结果:
4 4

#include
int main()
{
	int a=3;
	int b=a++;
	printf("%d %d",a,b);
	return 0;
}

运行结果:
4 3

自减的道理与自增一样,大家可以试试!


总结:

本章专门介绍了部分操作符的原理及用法,希望对你有所帮助,如果对你帮助很大,或喜欢本篇的话,不妨点个赞,如果想要学习更多操作符,不妨点个关注,下篇我们接着介绍,如果有什么疑问或者看法,欢迎在评论区发言。

拜拜,我们下篇见!!!

你可能感兴趣的:(c语言)