【C语言初阶】操作符详解

发布于:2023-01-04 ⋅ 阅读:(308) ⋅ 点赞:(0)

1.算数操作符

这里我们用A=10 B=3 来演示用法

算数操作数 含义 用法实例
+ A+B=13
- A-B=7
* A*B=30
/ A/B=3
% 取模(取余数) A%B=1

注意

  • 除了 % 操作符之外,其他的几个操作符可以作用于整数和浮点数。
  • 对于 / 操作符如果两个操作数都为整数,执行整数除法。而只要有浮点数执行的就是浮点数除法。
    比如:5.0/2 == 2.5
    5/2.0 == 2.5
    5.0/2.0 == 2.5
  • % 操作符的两个操作数必须为整数。返回的是整除之后的余数。

2.移位操作符

移位操作符
<< 左移操作符
>> 右移操作符

注意

移位操作符的操作数只能为整数,移动的是二进制
用二进制位表示。
整数在内存中存储的是二进制的补码,移动操作符,移动的是存储在内存中的补码。

2.1左移操作符

移位规则

左边抛弃,右边补0

图解:

在这里插入图片描述

代码演示

#include<stdio.h>
int main()
{
	int a = -4;
    //原码:10000000000000000000000000000100
	//反码:11111111111111111111111111111011
	//补码:11111111111111111111111111111100

	int b = a << 1;//补码向左移动一位,右边空位补0
	//b的补码 11111111111111111111111111111000
	//反码:  11111111111111111111111111110111
	//原码:  10000000000000000000000000001000
	//转换为十进制为-8
	printf("a=%d b=%d\n", a, b);
  //左移实际上有扩大而二倍的效果
	return 0;
}

在这里插入图片描述

2.2右移操作符

移位规则

  1. 逻辑移位
    左边用0填充,右边丢弃
  2. 算术移位
    左边用原该值的符号位填充,右边丢弃

图解

在这里插入图片描述
其实规定用那种方法,C语言没有规定,具体情况具体分析,比如我们要对一个负数进行移位,如果我们使用逻辑右移,左边补0的话,它的符号位就会丢失,所以我们尽可能去避免,去使用算数右移,补符号位

代码演示

#include<stdio.h>
int main()
{
	int a = -4;
    //原码:10000000000000000000000000000100
	//反码:11111111111111111111111111111011
	//补码:11111111111111111111111111111100

	int b = a >>1;//补码向右移动一位,用算数右移,左边补符号位
	//b的补码 11111111111111111111111111111110
	//反码:  11111111111111111111111111111101
	//原码:  10000000000000000000000000000010
	//转换为十进制为-2
	printf("a=%d b=%d\n", a, b);

	return 0;
}

在这里插入图片描述

3.位操作符

3.1位操作符的使用

位操作符
& 按位与
l 按位或
^ 按位异或

注意

操作数必须是正数

代码演示
按位与

参加运算的两个数据,按二进制位进行“与”运算。
运算规则:0&0=0; 0&1=0; 1&0=0; 1&1=1;

#include<stdio.h>
int main()
{
	int a = 3;
	int b = -5;
	int c = a & b;
	//3的补码:00000000000000000000000000000011(正数的原反补码相同)
	
	//-5的原码:10000000000000000000000000000101
	//-5的反码:11111111111111111111111111111010
	//-5的补码:11111111111111111111111111111011

	//按位与: 00000000000000000000000000000011(c的补码)
	//因为c的符号位为0,为正,所以原反补码相同。
	//所以c转换为十进制为3
	printf("%d\n", c);
	return 0;
}

按位或

参加运算的两个对象,按二进制位进行“或”运算。
运算规则:0|0=0; 0|1=1; 1|0=1; 1|1=1;

#include<stdio.h>
int main()
{
	int a = 3;
	int b = -5;
	int c = a | b;
	//3的补码:00000000000000000000000000000011(正数的原反补码相同)

	//-5的原码:10000000000000000000000000000101
	//-5的反码:11111111111111111111111111111010
	//-5的补码:11111111111111111111111111111011

	//按位或: 11111111111111111111111111111011(c的补码)
	//c的反码:11111111111111111111111111111010
	//c的原码:10000000000000000000000000000101
	//所以c转换为十进制为-5
	//内存中存储的是补码,从内存中拿出来打印输出是原码
	printf("%d\n", c);
	return 0;
}

按位异或

参加运算的两个数据,按二进制位进行“异或”运算。
运算规则:0^0=0; 0^1=1; 1^0=1; 1^1=0;

#include<stdio.h>
int main()
{
	int a = 3;
	int b = -5;
	int c = a ^ b;
	//3的补码:00000000000000000000000000000011(正数的原反补码相同)

	//-5的原码:10000000000000000000000000000101
	//-5的反码:11111111111111111111111111111010
	//-5的补码:11111111111111111111111111111011

	//按位或: 11111111111111111111111111111000(c的补码)
	//c的反码:11111111111111111111111111110111
	//c的原码:10000000000000000000000000001000
	//所以c转换为十进制为-8
	//内存中存储的是补码,从内存中拿出来打印输出是原码
	printf("%d\n", c);
	return 0;
}

3.2小牛试刀-面试题

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

代码实现

#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\n", a, b);
	return 0;
}

解释之前我们来举一个例子,3^3=0; 5^5=0; 3^5=6(011 ^101=110)
3^5 ^5=3(因为5 ^5=0,3 ^0=3), 同理3 ^5 ^3=5

4.赋值操作符

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

int weight = 120;//体重
weight = 89;//不满意就赋值

4.1复合赋值符

复合赋值符 用法
+= a+=1 a=a+1
-= a-=1 a=a-1
*= a*=1 a=a*1
/= a/=1 a=a/1
%= a%=1 a=a%1
>>= a>>=1 a=a>>1
<<= a<<=1 a=a<<1
&= a&=1 a=a&1
l= al=1 a=al1
^= a^=1 a=a^1

5.单目操作符

5.1单目操作符的介绍

单目操作符
逻辑反操作
- 负值,对一个正整数取负数 -5
+ 正值,+5
& 取地址
sizeof 操作符的类型长度(以字节为单位)
~ 对一个数的二级制按位取反
++ 前置++,后置++
前置–,后置–
* 间接访问操作符(解引用操作符)
(类型) 强制转换类型

5.2代码演示

逻辑反操作

#include<stdio.h>
int main()
{
	int flag = 0;
	if (!flag)//原本flag=0,为假,不打印hehe,!对flag逻辑取反,为真,打印hehe
	{
		printf("hehe\n");
	}
	return 0;
}

取地址和解引用操作符

#include<stdio.h>
int main()
{
	int a = 10;
	int* p = &a;//&,取出a的地址
	*p = 20;//*,解引用操作符,找到a的地址
	printf("%d\n", a);
	return 0;
}

sizeof操作符类型的长度

#include<stdio.h>
int main()
{
	int a = 0;
	printf("%zu\n", sizeof(a));//a的类型为int型,在内存中占4个字节,所以打印出来为4
	return 0;
}

前置++,后置++

#include<stdio.h>
int main()
{
	int a = 4;
	int b = ++a;//前置++,先++,后使用
	//a=a+1,b=a;先对a进行++,在将a的值赋给b
	printf("%d\n", b);
	return 0;
}
//同理前置--,后置--
#include<stdio.h>
int main()
{
	int a = 4;
	int b = a++;//后置++,先使用,后++
	//b=a,a=a+1;先把a的值赋给b,在对a进行++
    //最终打印为:a=5,b=4
	printf("%d\n", b);
	printf("%d\n", a);
	return 0;
}

强制转换类型()

#include<stdio.h>
int main()
{
	int a = (int)3.14;//强制把3.14的类型转换成int型
	printf("%d\n", a);//打印结果为:3
	return 0;
}

6.关系操作符

关系操作符
> 大于
< 小于
<= 小于等于
> = 大于等于
!= 不等于
== 等于

7.逻辑操作符

逻辑操作符
&& 逻辑与
l l 逻辑或

区分逻辑与和按位与
区分逻辑或和按位或
1&2----->0
1&&2---->1 (1和2不为0,都为真,逻辑与后为真,为1)
1|2----->3
1||2---->1

代码演示

#include<stdio.h>
int main()
{
	int a = 0;
	int b = 1;
	if (a || b)//a=0为假,b=1为真,逻辑或ab,为真。打印hehe
	{
		printf("hehe\n");
	}
	return 0;
}

8.条件操作符

exp?exp2:exp3
如果exp1为真,则exp2为真,否则exp3为真

代码演示

#include<stdio.h>
int main()
{
	int a = 3;
	int b = 0;
	//if (a > 5)
	//	b = 3;
	//else
	//	b = -3;
	//我们用条件表达式来写
	b = (a > 5 ? 3 : -3);
	printf("%d\n", b);
	return 0;
}

9.逗号操作符

exp1, exp2, exp3, …expN
逗号表达式,就是用逗号隔开的多个表达式。
逗号表达式,从左向右依次执行。整个表达式的结果是最后一个表达式的结果。

int a = 1;
int b = 2;
int c = (a > b, a = b + 10, b = a + 1);//逗号表达式

10。表达式求值

表达式求值的顺序一部分是由操作符的优先级和结合性决定。
同样,有些表达式的操作数在求值的过程中可能需要转换为其他类型。

10.1隐式型转换

C的整型算术运算总是至少以缺省整型类型的精度来进行的。
为了获得这个精度,表达式中的字符和短整型操作数在使用之前被转换为普通整型,这种转换称为整型提升

整形提升的意义

表达式的整型运算要在CPU的相应运算器件内执行,CPU内整型运算器(ALU)的操作数的字节长度
一般就是int的字节长度,同时也是CPU的通用寄存器的长度。
因此,即使两个char类型的相加,在CPU执行时实际上也要先转换为CPU内整型操作数的标准长
度。
通用CPU(general-purpose CPU)是难以直接实现两个8比特字节直接相加运算(虽然机器指令
中可能有这种字节相加指令)。所以,表达式中各种长度可能小于int长度的整型值,都必须先转
换为int或unsigned int,然后才能送入CPU去执行运算。

如何进行整形提升

整形提升是按照变量的数据类型的符号位来提升的

在这里插入图片描述

10.2算数转换

如果某个操作符的各个操作数属于不同的类型,那么除非其中一个操作数的转换为另一个操作数的类型,否则操作就无法进行。下面的层次体系称为寻常算术转换。

算数转换针对的是大于等于int的不同类型进行计算,向范围更大的类型进行算数转换,但如果是小于int类型的时候我们会进行整形提升

在这里插入图片描述

10.3操作符的属性

复杂表达式的求值有三个影响的因素。

  1. 操作符的优先级
  2. 操作符的结合性
  3. 是否控制求值顺序。

两个相邻的操作符先执行哪个?取决于他们的优先级。如果两者的优先级相同,取决于他们的结合性。

操作符的优先级
从上往下,优先级依次递减
在这里插入图片描述