【C语言 |操作符】操作符详解,一文精通所有操作符!

目录

一、前言

二、算术操作符

1.加号 “ + ”

2.减号 “ - ”

3.乘号 “ * ”

4.除号“ / ”

5.除法取余数" % "

三、移位操作符

1.左移操作符<<

正数

负数

2.右移操作符>>

逻辑移位 

算术移位

四、位操作符

1.& 按位与

2.| 按位或

3.^ 按位异或

五、赋值操作符

1.赋值 =

​编辑

2.复合赋值操作符

六、单目操作符

1. !  逻辑反操作

2.- 负值

3.+ 正值

4.& 取地址

​编辑

5.sizeof  操作数的类型长度

6.~  对一个数的二进制按位取反

​编辑

7.++前置、后置++

​编辑

8.-- 前置、后置--

​编辑

9.* 解引用操作符

​编辑

10.(类型) 强制类型转换

​编辑

七、关系操作符

1.>大于

2.>= 大于等于

3.<小于

4.<=小于等于

5.!=   不等于

6.==     等于

八、逻辑操作符

1.&&  逻辑与

​编辑

2.|| 逻辑或

​编辑

九、三目操作符

十、逗号表达式

​编辑

十一、下标引用、函数调用和结构成员

1. [ ] 下标引用操作符

2. ( ) 函数调用操作符

3. 访问一个结构的成员

. 结构体.成员名

-> 结构体指针->成员名

十二、 隐式类型转换

1.整形提升

2.算术转换

3.操作符的属性


一、前言

操作符呢又叫运算符,C语言中有着各种各样的操作符,这篇文章讲的是各种操作符的介绍。


二、算术操作符

算数操作符一般作用于两个操作数之间,我们学数学应该 很熟悉


1.加号 “ + ”

+ 实现两个数的相加 

#include<stdio.h>

int main()
{
	int num1 = 1;
	int num2 = 2;
	int Add = num1 + num2;
	printf("Add == %d",Add);

	return 0;
}

 


2.减号 “ - ”

- 实现两个数的相减

#include<stdio.h>

int main()
{
	int num1 = 4;
	int num2 = 2;
	int Red = num1 - num2;
	printf("Red == %d",Red);

	return 0;
}


 

3.乘号 “ * ”

* 实现两个数的相乘

#include<stdui.h>
int main()
{
	int num1 = 4;
	int num2 = 2;
	int Take = num1 * num2;
	printf("Take == %d", Take);

	return 0;
}


4.除号“ / ”

/ 实现两个数的除法

#include<stdio.h>

int main()
{
	int num1 = 5;
	int num2 = 2;

	float num3 = 5;
	float num4 = 2;

	int Rem1 = num1 / num2;  //整形除整形
	float Rem2 = num3 / num4;  //浮点型除浮点型
	float Rem3 = num3 / num2;  //浮点型除整形
    float Rem4 = num1 / num4;  //整形除浮点型


	printf("Rem1 == %d\n", Rem1);
	printf("Rem2 == %f\n", Rem2);
	printf("Rem3 == %f\n", Rem3);
    printf("Rem4 == %f\n", Rem4);


	return 0;
}

为什么Rem1跟 Rem2 Reme3 Rem4值会不一样呢

那是因为我们规定 

当两个操作数为整数相除,执行的是整数除法

当两个操作数中有一个或两个都是浮点型的话,执行的是浮点型除法


5.除法取余数" % "

% 实现两个数的除法取余数操作

取模操作符 的两个操作数必须是两个整形 !!!

#include<stdio.h>
int main()
{
	int num1 = 5;
	int num2 = 2;

	int Sur1 = num1 % num2; 

	printf("Sur == %d\n", Sur1);


	return 0;
}


三、移位操作符

移位操作符一般作用于两个操作数之间,移位操作符移动的二进制的位

大家都知道 , 整数在内存中存储的是补码 , 所以移位针对的是补码

正数:原码 反码 补码相同

负数:原码  反码 补码需要计算(符号位不变其他位 取反加一)


1.左移操作符<<

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

  • 正数

#include<stdio.h>
int main()
{
	int num1 = 3;
	
	int num2 = num1 << 1;

	printf("num1 == %d num2 ==%d",num1,num2);

	return 0;
}

上面就是正数一个例子

 3

原码为 0000 0000  0000  0000  0000  0000  0000  0011

反码为0000 0000  0000  0000  0000  0000  0000  0011

补码为0000 0000  0000  0000  0000  0000  0000  0011

3 <<1

补码向左整体移一位(左边舍弃右边取0)

补码为0000 0000  0000  0000  0000  0000  0000  0110

反码为0000 0000  0000  0000  0000  0000  0000  0110

原码为 0000 0000  0000  0000  0000  0000  0000  0110

还原回原码是 6


  • 负数

#include<stdio.h>
int main()
{
	int num1 = 3;
	
	int num2 = num1 << 1;

	printf("num1 == %d num2 ==%d",num1,num2);

	return 0;
}

上面就是负数一个例子

 -3

原码为 1000 0000  0000  0000  0000  0000  0000  0011

反码为  1111 1111 1111 1111 1111 1111 1111 1111 1100

补码为  1111 1111 1111 1111 1111 1111 1111 1111 1101

-3 << 1

补码向左整体移一位(左边舍弃右边取0)

补码为 1111 1111 1111 1111 1111 1111 1111 1111 1010

反码为 1111 1111 1111 1111 1111 1111 1111 1111 1001

原码为 1000 0000 0000 0000 0000 0000 0000 0000 0110

还原回原码是 -6


2.右移操作符>>

右移采用的算术右移还是逻辑右移是取决于编译器的,两种方式都是不一样的的

对于正数而言这两种方式都无伤大雅 ,结果都是一样的,因为正数符号位是0

所以为了检测下面两种结果,我们赋值一个负数来验证

  • 逻辑移位 

移位规则:左边用0填充,右边丢弃

  • 算术移位

移位规则:左边用原该值的符号位填充,右边丢弃


我用的vs编译器来验证的

如果说 

-5

原码为 1000 0000  0000  0000  0000  0000  0000  0101

反码为  1111 1111 1111 1111 1111 1111 1111 1111 1010

补码为  1111 1111 1111 1111 1111 1111 1111 1111 1011

-5 >> 1

补码向右整体移一位

算术移位话

补码为 1111 1111 1111 1111 1111 1111 1111 1111 1101(左边用原该值的符号位填充,右边丢弃

反码为 1111 1111 1111 1111 1111 1111 1111 1111 1100

原码为  1000  0000  0000  0000  0000  0000  0000  0011

结果应该是-3

逻辑移位

补码为 0111 1111 1111 1111 1111 1111 1111 1111 1101(左边用0填充,右边丢弃)

反码为 0111 1111 1111 1111 1111 1111 1111 1111 1100

原码为 0000  0000  0000  0000  0000  0000  0000  0011

结果应该是3

int main()
{
	int num1 = -5;
	
	int num2 = num1 >> 1;

	printf("num1 == %d num2 ==%d",num1,num2);

	return 0;
}

 所以我们看出在vs编译器中采用的是算术右移的方式,当然绝大多数编译器都采用的是算术右移的方式进行操作

当然不要移动负数位,这个是标准未定义的---不允许的

int num = 10;
num>>-1;//error

四、位操作符

位操作符一般作用于两个操作数之间,有是通过补码进行操作

注:他们的操作数必须是整数。


1.& 按位与

规则:只要有0就是0,都为1才是1

int main()
{
	int num1 = -5;

	int  num2 = 3;
	
	int num3 = num1 & num2;

	printf("num3 == %d",num3);

	return 0;
}

3

原码为 0000 0000  0000  0000  0000  0000  0000  0011

反码为  0000 0000  0000  0000  0000  0000  0000  0011

补码为 0000 0000  0000  0000  0000  0000  0000  0011

-5

原码为 1000 0000  0000  0000  0000  0000  0000  0101

反码为  1111 1111 1111 1111 1111 1111 1111 1111 1010

补码为  1111 1111 1111 1111 1111 1111 1111 1111 1011

3 & -5

3补码为  0000 0000  0000  0000  0000  0000  0000  0011

-3补码为  1111  1111   1111   1111  1111   1111    1111 1011

3 & -5补码 0000 0000  0000  0000  0000  0000  0000  0011

3 & -5反码 0000 0000  0000  0000  0000  0000  0000  0011

3 & -5原码 0000 0000  0000  0000  0000  0000  0000  0011

值为3

 当然还有一个拿 按位与 操作符可以实现快速统计二进制个数

大家可以看一下我这个文章


快速统计二进制中1的个数-CSDN博客

2.| 按位或

规则:只要有1就是1,都为0才是0

int main()
{
	int num1 = -5;

	int  num2 = 3;
	
	int num3 = num1 | num2;

	printf("num3 == %d",num3);

	return 0;
}

3

原码为 0000 0000  0000  0000  0000  0000  0000  0011

反码为  0000 0000  0000  0000  0000  0000  0000  0011

补码为 0000 0000  0000  0000  0000  0000  0000  0011

-5

原码为 1000 0000  0000  0000  0000  0000  0000  0101

反码为  1111 1111 1111 1111 1111 1111 1111 1111 1010

补码为  1111 1111 1111 1111 1111 1111 1111 1111 1011

3 | -5

3补码为  0000 0000  0000  0000  0000  0000  0000  0011

-5补码为  1111  1111   1111   1111  1111   1111    1111 1011

3 | -5补码  1111  1111   1111   1111  1111   1111   1111 1011

3 | -5反码  1111  1111   1111   1111  1111   1111   1111 1010

3 | -5原码  1000 0000 0000 0000 0000 0000 0000 0101

值为-5


3.^ 按位异或

规则:相同为0,相异为1

int main()
{
	int num1 = -5;

	int  num2 = 3;

	int num3 = num1 ^ num2;

	printf("num3 == %d", num3);

	return 0;
}

 

3

原码为 0000 0000  0000  0000  0000  0000  0000  0011

反码为  0000 0000  0000  0000  0000  0000  0000  0011

补码为 0000 0000  0000  0000  0000  0000  0000  0011

-5

原码为 1000 0000  0000  0000  0000  0000  0000  0101

反码为  1111 1111 1111 1111 1111 1111 1111 1111 1010

补码为  1111 1111 1111 1111 1111 1111 1111 1111 1011

3 | -5

3补码为  0000 0000  0000  0000  0000  0000  0000  0011

-5补码为  1111  1111   1111   1111  1111   1111    1111 1011

3 ^ -5补码  1111  1111   1111  1111  1111   1111 1111 1000

3 ^ -5反码  1111  1111   1111  1111  1111   1111 1111 0111

3 ^ -5原码  1000 0000 0000 0000 0000 0000 0000 1000

值为-8

 当然还有一个拿 异或 操作符可以实现不创建临时变量  交换两个整数

A  ^  A  == 0;

0  ^  A  == A;

大家可以看一下我这个文章

交换两个变量-CSDN博客


五、赋值操作符

1.赋值 =

=  在变量创建的时候给一个初始值叫做舒适化,变量创建好了,再给一个值叫做赋值

int main()
{
	int a = 0;//初始化
	a = 9;//赋值
	printf("a == 9",a);
	return 0;
}

赋值以后它的值就改变了

2.复合赋值操作符

比如

+=        -=        /=        %=        *=        >>=        <<=        

&=        |=        ^=   

当然这也很简单不难理解,这样写更加简洁。

就相当于是

m + m  =             m += m                                m >> m  =             m >>= m

m - m  =             m -= m                                m << m  =             m <<= m

m / m  =             m /= m                                m & m  =             m &= m

m * m  =             m *= m                                m | m  =             m |= m

m % m  =             m %= m                                m ^ m  =             m ^= m


六、单目操作符

单目操作符顾名思义就是作用于单个操作数

1. !  逻辑反操作

假如说flag为真  那么!flag就是为假

int main()
{
	int flag = 1;

	if (flag)
	{
		printf("真");
	}
	if (!flag)
	{
		printf("假");
	}
	return 0;
}

好比这个代码flag为真进入for语句,!flag为假不进入,结果只打印了一个真

真! =  假

假! =  真


2.- 负值

正常的 数学里面负号


3.+ 正值

正常的 数学里面正号


4.& 取地址

每一个创建的变量都会去开辟一块空间,&取地址操作符就是知道它开辟空间的首地址

int main()
{
	int num = 0;

	printf("%p",&num);//%p用来打印地址

	return 0;
}


5.sizeof  操作数的类型长度

sizeof以字节为单位,sizeof是操作符,不是库函数。
sizeof计算的是变量或类型创建变量的内存大小,和内存里存放什么数据没有关系!!

sizeof()   括号里面不能进行计算

#include<stdio.h>
int main()
{
	char arr[10] = "abc";
	printf("%d\n", sizeof(arr));//该数组10个元素,每个元素1个字节,总大小10*1=10
	printf("%d\n", sizeof(a));//a里面有一个元素,占四个字节1*4=4
	printf("%d\n", sizeof a);//因为sizeof不是函数,所以对于变量可以不带括号
	printf("%d\n", sizeof(int));//整形也是4字节
	//printf("%d\n", sizeof int);//但是关键字int外的括号不能省略
	return 0;
}

6.~  对一个数的二进制按位取反

也是一样的针对于补位来操作

int main()
{
	int num1 = 0;
	int num2 = ~num1;

	printf("%d",num2);

	return 0;
}

0

原码为 0000 0000  0000  0000  0000  0000  0000  0000

反码为 0000 0000  0000  0000  0000  0000  0000  0000

补码为 0000 0000  0000  0000  0000  0000  0000  0000

~0

补码为 1111 1111 1111 1111 1111 1111 1111 1111 1111

反码为 1111 1111 1111 1111 1111 1111 1111 1111 1110

原码为 1000 0000  0000  0000  0000  0000  0000  0001

值为-1


7.++前置、后置++

这就是一个赋值与运算顺序的问题

前置++  先自增再赋值

后置++ 先赋值再自增

int main()
{
	int a = 1;

	int b = ++a;//先自增再赋值

	int c = 1;

	int d = c++;//先赋值再自增

	printf("b = %d,c = %d",b,d);
	return 0;
}


8.-- 前置、后置--

这就是一个赋值与运算顺序的问题

前置--  先自减再赋值

后置-- 先赋值再自减

int main()
{
	int a = 1;

	int b = --a;//先自减再赋值

	int c = 1;

	int d = c--;//先赋值再自减

	printf("b = %d,c = %d",b,d);
	return 0;
}


9.* 解引用操作符

它又叫间接引用操作符

int * p = &a;    把a的地址传到指针p中

对指针p 解引用 

*p == a

&a = p

int main()
{
	int a = 9;
	int* p = &a;
	printf("%d",*p);


10.(类型) 强制类型转换

强制类型转换是一种临时的转换

强扭的瓜不甜,强制类型转换万不得已就不用

int main(void)
{
	float num = 3.14; //定义了一个浮点型数据
	printf("%d",(int)num);//强制转换为整形  ,然后打印
}


七、关系操作符

关系操作符主要作用为判断两个操作数的关系


1.>大于


2.>= 大于等于


3.<小于


4.<=小于等于


5.!=   不等于


6.==     等于

注意!!!!

==等于 跟 = 赋值 ,不一样刚开始很容易将两个弄混,尤其是一些判断语句,刚开始很容易出错


八、逻辑操作符

判断两个操作数的关系


1.&&  逻辑与

就相当于并且,两个条件都为真才为真

#include<stdio.h>
int main()
{
	int a = 0;
	int b = 5;
	int c = a && b;
	printf("%d\n", c);;//全真为1,否则为0

	return 0;
}


2.|| 逻辑或

就相当于或者,两个条件有一个为真就为真

#include<stdio.h>
int main()
{
	int a = 0;
	int b = 5;
	int d = a || b;
	printf("%d\n", d);//有真为1,全假为0
	return 0;
}


九、三目操作符

三目操作符(条件操作符)

exp1 ? exp2 : exp3
对语句1判断,为真则执行语句2,为假则执行语句3
int main()
{
	int a = 1;
	a > 2 ? printf("语句1") : printf("语句2");
	return 0;
}




a > 2 ? printf("语句1") : printf("语句2");

//就相当于

if(a > 2 )
{
printf("语句1");        //更简洁一点
}
else
{
printf("语句2");
}

十、逗号表达式

exp1,exp2,exp3,…

逗号表达式,就是用逗号隔开的多个表达式。
逗号表达式,从左向右依次执行。整个表达式的结果是最后一个表达式的结果。
#include<stdio.h>
int main()
{
	int a = 1, b = 2;
	int c = (a += 1, b += 1, a += 2, a + b);
	printf("%d", c);
}


十一、下标引用、函数调用和结构成员

1. [ ] 下标引用操作符

操作数:一个数组名 + 一个索引值
arr[5]
[ ]操作符,arr跟5是两个操作数

2. ( ) 函数调用操作符

接受一个或者多个操作数:第一个操作数是函数名,剩余的操作数就是传递给函数的参数。

函数名 参数都是操作数   ()是操作符


3. 访问一个结构的成员

访问结构体成员用,操作符(左边必须是结构体)

访问结构体指针成员用->操作符(左边必须是结构体变量)

. 结构体.成员名

#include <stdio.h>
struct Stu
{
 char name[10];
 int age;
 char sex[5];
 double score;
};

void set_age1(struct Stu stu)
{
 stu.age = 18;
}

int main()
{
 struct Stu stu;
 
 stu.age = 20;//结构成员访问
 set_age1(stu);

 return 0;
}

-> 结构体指针->成员名

#include <stdio.h>
struct Stu
{
 char name[10];
 int age;
 char sex[5];
 double score;
};

void set_age2(struct Stu* pStu)
{
 pStu->age = 18;//结构成员访问
}

int main()
{
 struct Stu stu;
 struct Stu* pStu = &stu;//结构成员访问
 
pStu->age = 20;//结构成员访问
 set_age2(pStu);

 return 0;
}

十二、 隐式类型转换

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

1.整形提升

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

有符号正数补1,有符合负号补0

无符号整形补0

int main()
{
	char a = 4;  
	char b = 127;
	char c = a + b;
	printf("%d",c);
	return 0;
}

3原码0000 0000 0000 0000 0000 0000 0000 0011

127原码0000 0000 0000 0000 0000 0000 0111 1111

a是char类型占8个比特位,把3放进a中发生截断

0000 0011

b是char类型占8个比特位,把127放进b中发生截断

0111 1111

a+b两个整形相加 需要整形提升

所以整形提升的时候,高位补充符号位,即为3
提升之后的结果是:
0000 0000 0000 0000 0000 0000 0000 0011
所以整形提升的时候,高位补充符号位,即为127
提升之后的结果是:
0000 0000 0000 0000 0000 0000 0111 1111
c原码0000 0000 0000 0000 0000 00001000 0000

c是char类型占8个比特位,把127放进c中发生截断

10000000

%d打印出来整形再次整形提升,高位补充符号位,即为c

提升之后的结果是:
c补码11111111111111111111111110000010(负数的补码转化为原码要转化)
c反码1111111111111111111111110000001
c原码1000000000000000000001111110
结果为-126

2.算术转换

针对大于char类型数据

long double
double
float
unsigned long int
long int
unsigned int
int
如果某个操作数的类型在上面这个列表中排名较低,那么首先要转换为另外一个操作数的类型后执行运算。
向上转换

3.操作符的属性

复杂表达式的求值有三个影响的因素。
1. 操作符的优先级
2. 操作符的结合性
3. 是否控制求值顺序
果两者的优先级相同,取决于他们的结合性。
所以在我看来多用()圆括号将自己的逻辑框起来能避免很多麻烦
优先级汇总表在网上都有大家可以去自行查看
简单记就是:! > 算术运算符 > 关系运算符 > && > || > 赋值运算符

创作不易,留个赞咯!!!

希望对你有用 

  • 43
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
CSDN IT狂飙上传的代码均可运行,功能ok的情况下才上传的,直接替换数据即可使用,小白也能轻松上手 【资源说明】 基于MATLAB实现的有限差分法实验报告用MATLAB中的有限差分法计算槽内电位;对比解析法和数值法的异同点;选取一点,绘制收敛曲线;总的三维电位图+使用说明文档 1、代码压缩包内容 主函数:main.m; 调用函数:其他m文件;无需运行 运行结果效果图; 2、代码运行版本 Matlab 2020b;若运行有误,根据提示GPT修改;若不会,私信博主(问题描述要详细); 3、运行操作步骤 步骤一:将所有文件放到Matlab的当前文件夹中; 步骤二:双击打开main.m文件; 步骤三:点击运行,等程序运行完得到结果; 4、仿真咨询 如需其他服务,可后台私信博主; 4.1 期刊或参考文献复现 4.2 Matlab程序定制 4.3 科研合作 功率谱估计: 故障诊断分析: 雷达通信:雷达LFM、MIMO、成像、定位、干扰、检测、信号分析、脉冲压缩 滤波估计:SOC估计 目标定位:WSN定位、滤波跟踪、目标定位 生物电信号:肌电信号EMG、脑电信号EEG、心电信号ECG 通信系统:DOA估计、编码译码、变分模态分解、管道泄漏、滤波器、数字信号处理+传输+分析+去噪、数字信号调制、误码率、信号估计、DTMF、信号检测识别融合、LEACH协议、信号检测、水声通信 5、欢迎下载,沟通交流,互相学习,共同进步!

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值