C语言操作符详解篇(全)

文章目录

  • 前言
  • 1. 算数操作符
  • 2.移位操作符
    • 2.1. 左移操作符
    • 2.2. 右移操作符
  • 3.位操作符
    • 3.1 &
    • 3.2 |
    • 3.3 ^
    • 3.4 ~
  • 4.赋值操作符
  • 5.单目操作符
  • 6.关系操作符
  • 7.逻辑操作符
    • &&
    • ||
    • 结合
  • 8.条件操作符
  • 9.逗号表达式
  • 10.表达式求值
    • 10.1.隐式类型转换
    • 10.2.算数转换
  • 11.操作符的准确使用
  • 总结

前言

  • 我们在学习C语言时肯定会用到不同的操作符来完成我们的功能,本章便是这些操作符的介绍与具体使用。

1. 算数操作符

  • 算数操作符有四种,他们分别为:
  • 加 “+”,减 “-”,乘 “ * ”,除 “/”, 取模 “%
  • 值得注意的是,在C语言中乘号用 " * " 表示, 除号用 " / " 表示。
  • 取模号 " % " 求的是余数,比如 5除3余2 ,那么2便是计算的结果。
  • 通俗易懂,通过我们的数学知识很清楚的知道他们的作用。
int main()
{
	int a = 20;
	int b = 12;
	
	printf("a + b = %d\n", a + b);
	printf("a - b = %d\n", a - b);
	printf("a÷b = %d\n", a / b); // 这里20除12等于1,他不会显示后面的小数,除非计算式两边至少有一个浮点数
	printf("a×b = %d\n", a * b);
	printf("a % b = %d\n", a % b); // 这里20模12余数是8,结果便是8

	return 0;
}

C语言操作符详解篇(全)_第1张图片

  • 值得注意的是,当计算式两边至少有一个浮点数的时候,相除才会计算出小数.

2.移位操作符

首先,我们来补充一个小知识:

  • 我们都知道,一个数在内存中是以二进制数来存放的,存放的是这个数的补码,那么什么是补码呢?
  • 一个数的二进制有原码,反码和补码,在计算中是用补码来计算的,而打印出来的是原码,这三个码之间有这样的关系,原码符号位不变,其它位按位取反得到反码,反码加一得到补码,而又补码要得到原码,反过来就是了.
  • 正数的原码反码补码相同,而负数则需要结果上面的计算来得到.
  • 由上可以得到,移位操作符,移位其实移的是在内存中储存的二进制数的补码.

2.1. 左移操作符

(<<) : 补码左移,左边抛弃,右边补0.

#include 

int main()
{
	int a = 10;
	// a是一个整数所以他的原码,反码,补码相同
    // 原码:00000000000000000000000000001010
    // 反码:00000000000000000000000000001010
    // 补码:00000000000000000000000000001010
	int b = 15;
	int c = -5;
	// c为负数
	// 原码:10000000000000000000000000000101
	// 反码:11111111111111111111111111111010
	// 补码:11111111111111111111111111111011
	// 左移后:11111111111111111111111111110110 
	// 减一:11111111111111111111111111110101
	// 取反得到计算后的原码:10000000000000000000000000001010 - (-10)

	printf("%d\n", a << 1); // 左移1 // 00000000000000000000000000010100 - 20
	printf("%d\n", b << 1); // 左移1 // 00000000000000000000000000010100 - 30
	printf("%d\n", c << 1); // 左移1
	// 补码左移 右边补 0
	// 00000000000000000000000000010100 - 20

	return 0;
}

C语言操作符详解篇(全)_第2张图片

  • 不难看出,左移操作符具有乘以 2 的效果.

2.2. 右移操作符

(>>):右移操作符与左移操作符计算过程几乎相同,有一点不同的是,右移操作符分为算数右移和逻辑右移:

  • 算数右移: 左边补符号位,右边抛弃.
  • 逻辑右移: 左边补0,右边抛弃.
  • 通常来说进行右移时是逻辑右移.
#include 

int main()
{
	int a = 10;
	int b = -5;

	printf("%d\n", a >> 1); // 5
	printf("%d\n", b >> 1); // -3
	// b计算过程
	// 原码:10000000000000000000000000000101
	// 反码:11111111111111111111111111111010
	// 补码:11111111111111111111111111111011
	// 右移:11111111111111111111111111111101
	// 减一:11111111111111111111111111111100
	// 取反:10000000000000000000000000000011
	// 右移1后的数为 10000000000000000000000000000011 - (-3)

	return 0;
}

C语言操作符详解篇(全)_第3张图片
无论是左移还是右移,我们都不能移动负数为,如: a >> -1.

3.位操作符

同样的,位操作符也是对补码进行计算

3.1 &

  • 按位与是 : 如果两个二进制补码相同位数上有一个为零则为0,都为1则为1.
#include 

int main()
{
	int a = -5;
	// 原:10000000000000000000000000000101
	// 反:11111111111111111111111111111010
	// 补:11111111111111111111111111111011
	int b = 3;
	// 原:00000000000000000000000000000011
	// 补:00000000000000000000000000000011

	// a & b
	// 补:11111111111111111111111111111011
	// 补:00000000000000000000000000000011
	// 有一个0则为0,都为1则1
	// 得:00000000000000000000000000000011
	// 为整数:3
	printf("%d", a & b);

	return 0;
}

C语言操作符详解篇(全)_第4张图片

3.2 |

  • 按位或是 : 如果两个二进制补码相同位数上只要有一个为1则为1,全0则0.
#include 

int main()
{
	int a = 10;
	// 补:00000000000000000000000000001010
	int b = -2;
	// 原:10000000000000000000000000000010
	// 反:11111111111111111111111111111101
	// 补:11111111111111111111111111111110

	// a | b
	// 00000000000000000000000000001010 
	// 11111111111111111111111111111110
	// 11111111111111111111111111111110 结果
	// 减一:11111111111111111111111111111101
	// 取反:10000000000000000000000000000010 (-2)
	printf("%d", a | b); // -2

	return 0;
}

C语言操作符详解篇(全)_第5张图片

3.3 ^

  • 按位异或是:相同为0,相异为1.
#include 

int main()
{
	int a = 3;
	// 补:00000000000000000000000000000011
	int b = 5;
	// 补:00000000000000000000000000000101

	// a ^ b
	// 00000000000000000000000000000011
	// 00000000000000000000000000000101
	// 00000000000000000000000000000110 - 6
	printf("%d\n", a ^ b); // 6
	printf("%d\n", a ^ 0); // a
	printf("%d\n", b ^ 0); // b
	printf("%d\n", a ^ a); // 0

	return 0;
}

C语言操作符详解篇(全)_第6张图片

  • 值得注意的是:
  • a ^ 0 = a;
  • b ^ 0 = b;
  • a ^ a = 0;
  • 那么可以得到:
  • a ^ a ^ b = b;
  • b ^ b ^ a = a;

有一道经典题目:不创建临时变量交换两个变量的值。我们便可以用上述推理来实现

#include 

int main()
{![在这里插入图片描述](https://img-blog.csdnimg.cn/82c60be1cb6f4fc0b0a5b41971123922.png#pic_center)

	int a = 3;
	int b = 5;

	printf("交换前:%d %d\n", a, b);

	a = a ^ b;
	b = a ^ b;
	a = a ^ b;

	printf("交换后:%d %d\n", a, b);

	return 0;
}

C语言操作符详解篇(全)_第7张图片

3.4 ~

按位取反是补码二进制位如果是1则变为0,如果是0则变为1。

#include 

int main()
{
	int a = 3;
	// 补:00000000000000000000000000000011
	// 反:11111111111111111111111111111100  补码变负
	// -1:11111111111111111111111111111011
	// 原:10000000000000000000000000000100  -4
	printf("%d", ~a);

	return 0;
}

C语言操作符详解篇(全)_第8张图片

4.赋值操作符

  • =
    例如:a = 5,这里将5赋值给变量a

  • 复合型:

  • +=

  • -=

  • /=

  • *=

  • %=

  • &=

  • |=

  • ^=

  • (<<=)

  • (>>=)
    例如:a+=2其实就是a=a+2,其他的复合型都是如此

5.单目操作符

  -            负值
  +            正值
  ++           a++:后置加加  ; ++a:前置加加(都是a+=1)
  --           与++效果相同
  !            逻辑反操作
  &            取地址符号
  ~            二进制数按位取反
  *            解引用操作
  sizeof       求类型长度(以字节为单位)
  (类型)        强制类型转换

这里对++和!作讲解

++
首先看代码:

#include 

int main()
{
	int a = 1;
	int b = a++; // 先把a的值赋给b,a再自增1
	int c = ++a; // a先自增1,再赋值给c

	printf("%d\n", a); // 3
	printf("%d\n", b); // 1
	printf("%d\n", c); // 3

	return 0;
}

前置加加和后置加加其实在上述代码里其实效果很明显了,只要我们用一次++,其对应变量就要自增1。–与++的运用效果是相同的,只不过说是自减1。

!:!= 就是不等于,其相当于非。!0 就是真,!1就是假。

6.关系操作符

  • (>)
  • (>=)
  • (<)
  • (<=)
  • (!=)
  • (==)

上述操作符多用在判断语句中,用来决定程序进程变化。

7.逻辑操作符

&&

逻辑与:如 a&&b ,当a,b都为真时,表达式为真,当其中有一个为假时为假

#include 

int main()
{
	int a = 0;
	int b = 1;
	int c = 2;
	int d = 3;
	int i = a++ && ++b && c++; // a++表达式结果为a的值,此时a=0,由&&的性质有一个为假就为假,则后面都不计算了
    //但是a++还是要进行计算的,也就是a要自增1
	printf("%d %d %d %d\n", a, b, c, d);
    // 结果为 1 1 2 3
	return 0;
}

||

逻辑或:如 a || b,当a,b中只要有一个为真,表达式为真,都为假表达式才为假

#include 

int main()
{
	int a = 1;
	int b = 2;
	int c = 3;
	int d = 4;
	int i = a++ || b++ || ++d || c--; // a++表达式结果为a,此时a=1为真,由||性质,整个表达式结果为真,则后面的不计算了
	// a++还是要计算的,也就是a要自增1

	printf("%d %d %d %d\n", a, b, c, d);
	// 结果为 2 2 3 4

	return 0;
}

结合

我们可以通过判断闰年这个经典的题目来熟悉掌握&& ||。

#include 

int main()
{
	int n = 0;
	scanf("%d", &n);

	if (((n % 4 == 0) && (n % 100 != 0)) || (n % 400 == 0))
	{
		printf("%d年是闰年!\n", n);
	}
	else
	{
		printf("%d不是闰年!\n", n);
	}

	return 0;
}

8.条件操作符

exp1 ? exp2:exp3;

  • 如果 exp1 为真,表达式结果为 exp2
  • 如果 exp1 为假,表达式结果为 exp3

例如求两个变量的最大值:

#include 

int main()
{
	int a = 0;
	int b = 0;
	scanf("%d %d", &a, &b);

	printf("max = %d\n", (a > b ? a : b));

	return 0;
}

9.逗号表达式

  • 优先级最低
  • 用逗号隔开多个表达式
  • 整个表达式由左向右依次计算,计算结果为最后一个表达式的结果
#include 

int main()
{
	int a = 1;
	int b = 2;

	int c = (a += 2, b = b + 1, a += 1, a / 2);

	printf("%d", c); // 2

	return 0;
}

我们可以看到从左向右依次计算,最后a = 4,4 / 2 = 2,所以最后c的值为2;

10.表达式求值

10.1.隐式类型转换

CPU在进行运算的时候一般使用整形int,所以在有些时候,当一个小于整形的类型进行计算时,计算机就会先进行整形提升再进行运算,这就是隐式类型转换。

(通用CPU是难以直接实现两个非整形的直接相加运算)

例:

// char short int long ...
//  1     2    4
int main()
{
	//char --> signed char
	char a = 3;
	//截断
	//00000000000000000000000000000011
	//00000011 - a
	//
	char b = 127;
	//00000000000000000000000001111111
	//01111111 - b
 
	char c = a + b;
	//00000011
	//01111111
	//整型提升
	//00000000000000000000000000000011 - a
	//00000000000000000000000001111111 - b
	//00000000000000000000000010000010 - a + b =c
	//截断
	//10000010 - c
	printf("%d\n", c);
	//%d 是打印十进制的整数
	//11111111111111111111111110000010 - 补码
	//11111111111111111111111110000001 - 反码
	//10000000000000000000000001111110 - 原码
	//-126
	return 0;
	}

————————————————
版权声明:本文为CSDN博主「戊子仲秋」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/Locky136/article/details/127812345=

输出结果:

输出:-126

注:

char:

有符号的char的取值范围是:-128~127

无符号的char的取值范围是:0~255

  • 以上是一位大佬的讲解(写的很详细),这里直接引用他的,大家可以多看看他的博客,一定会有很大的帮助的。
    ——@戊子仲秋

10.2.算数转换

long double:最高

double

float unsigned long int

long int

unsigned int

int

  • 当我们再利用两个不同类型的变量来进行计算时,其算数级低的会自动升级到算数级高的类型去进行计算,如果进行一些不正当的算数转换,会导致数据丢失。

如:

#include 

int main()
{
	float e = 2.717f;
	int w = e;

	printf("%d", w);

	return 0;
}

运行结果为:

输出: 2

可以看到,e值小数点后面的数丢失了,这是由高级到低级转换的结果(不能用)

11.操作符的准确使用

  • 操作符之间有其对应的优先级,当我们进行运算时,优先比较相邻两个操作符的优先级,如果一个表达式很复杂,简易用()来分明其运算顺序,不然在不同的编译器上可能会有不同的运算结果。

总结

C语言中操作符的使用可以说是司空见惯的,如何正确的使用是我们必须掌握的,学到后面,我们可以尝试着巧妙运用操作符去解决一些复杂的问题,这需要我们不断地练习与巩固。在此,感谢大家的阅读!

你可能感兴趣的:(操作符,c语言)