C语言学习之解密操作符篇

一篇文章干懂操作符


算数操作符

移位操作符

位操作符

赋值操作符

单目操作符

关系操作符

逻辑操作符

条件操作符

逗号表达式

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

2.算数操作符

+      -    *     /       %

1.   +   -    *   和正常运算一样是最基本的运算。

2.  /  除法分为两种 第一种为整形除法 (要求  /  两边同时为整数 )

                                  第二种为浮点数除法( 要求 /  两边至少有一边为浮点数)

3.除了%以外,其他的几个操作数都可以作用于整数和浮点数。

4.%的两个操作数只能为整数。

3.移位操作符

<<   左移操作符

>>   右移操作符

注意: 移位操作符的操作数只能是整数。

移位操作符,顾名思义移动位置的操作符,那么移动什么位置呢? 答案是二进制位。


下面我先带大家了解一下计算机对于整形数据储存的方式以及对二进制位的了解。

     计算机中对于整形的存储方式是存储整形的补码。那么什么是补码呢?我们具体举一个例子:例如定义一个变量a ,并且给变量a 赋值为5,那么他对应的二进制数字是 0101,由于一个整形(int),对应的是四个字节,32个比特位,所以在计算机中a是 以 00000000000000000000000000000101存储的,其中正数对应的二进制的原码反码补码都相同,为他的原码。然而负数在计算机中存储的方式和正数有所不同,由于计算机中整数的存储和计算都使用的是补码,而负数的补码不是原码,其中原码--->补码的过程:(原码符号位不变其余的按位取反变成反码,反码+1变成补码。)

    其中二进制位最高位对应的是符号位,1为负,0为正。


3.1左移操作符

移位规则:

左面抛弃,右面补0

3.2右移操作符

移位规则:

首先右移运算分为两种:

1. 逻辑右移

    左边用0填充,右面丢弃

2. 算数右移

    左边用符号位补充,右面丢弃

我使用的编译器:vs2019 遵循算数右移

注意: 无论是向左移动还是向右移动都不要移动负数位,这个是标准未定义的。

4.位操作符

位操作符包括:

&    //按位与

|     // 按位或

^     // 按位异或

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

位操作符操作规则:

&   //  有0则0 ,相同为1 

|     //  有1则1, 同0为0

^     //   相同为0,相异为1

这里我们用具体的代码举例子:
 

&:

int main()
{
	int a = 3;

	//00000000000000000000000000000011

	int b = 5;

	//00000000000000000000000000000101

	int c = a & b;

	//a:00000000000000000000000000000011
	//b:00000000000000000000000000000101
    
    //根据规则 有0则0,相同为1  
    //c:00000000000000000000000000000001
	

    return 0;
}

|:

int main()
{
	int a = 3;

	int b = 5;

	int c = a | b;
	//a:00000000000000000000000000000011
	//b:00000000000000000000000000000101
	//c:00000000000000000000000000000111
	printf("%d", c);
	return 0;
}

^:

int main()
{
	int a = 3;
	int b = 5;

	int c = a ^ b;
	//a:00000000000000000000000000000011
	//b:00000000000000000000000000000101
	//c:00000000000000000000000000000110
	printf("%d", c);
	return 0;
}

5.赋值操作符

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

//如果对于你自己的体重不满意,就可以通过如下修改

int  weight = 130;
weight = 90;

复合赋值符:

+=

-=

*=

/=

%=

>>=

<<=

&=

|=

^=

这些运算符号都可以写成复合的效果。

例如:

int a = 0;
a = a + 10;
//可以写成 a += 10;

6.单目操作符

6.1单目操作符的介绍

!       逻辑反操作

-        负值

+        正值

&        取地址

sizeof    操作数的类型长度(以字节为单位)

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

--       前置、后置--

++       前置、后置++

*        间接访问操作符(解引用操作符)

(类型)    强制类型转换

6.2这里我们详细讲解一下sizeof 这个操作符

1. sizeof 与数组

#include <stdio.h>
void test1(int arr[])
{
 printf("%d\n", sizeof(arr));//(2)
}
void test2(char ch[])
{
 printf("%d\n", sizeof(ch));//(4)
}
int main()
{
 int arr[10] = {0};
 char ch[10] = {0};
 printf("%d\n", sizeof(arr));//(1)
 printf("%d\n", sizeof(ch));//(3)
 test1(arr);
 test2(ch);
 return 0;
}

大家觉得这段代码对应的1、2、3、4运行出来的结果是什么呢?

答案:(1).40 (2)4 / 8(3)10(4)4 / 8

为什么会出现如此结果呢?

(1)sizeof 括号里面放的是数组名,而sizeof 里面的数组名代表的是整个数组地址,所以求出来的结果是4*10 与(3)1*10,答案解法相同

(2) 在函数中arr代表的是首元素地址,作为一个地址在32位机器上,占4个字节,在64位机器上占8个字节,所以结果是4 / 8.

7.关系操作符

关系操作符:

>

>=

<

<=

!=         用于测试不等 

==        用于测试相等

这些关系运算符都比较简单,但是一定要注意不要把 == (判断相等)写成  = (赋值)了。

8.逻辑操作符

逻辑操作符:

&&                 逻辑与 (并且)

||                    逻辑或 (或者)

这两个逻辑操作符与位操作符非常之相似这里我给大家比较一下区别。

1 & 2 = 0;
1 && 2 = 1;
  
1 | 2 = 3;
1 || 2 = 1;

逻辑与和逻辑或的特点:

逻辑与和逻辑或关注的是真假,逻辑与中一旦左面为假右面就不会进行计算。而逻辑或左边为真右面就不会计算,这里有一个电路中短路的逻辑。
 

9. 条件操作符

exp1 ? exp2 : exp3

真         计算    不计算

假        不计算   计算

条件操作符也叫做三目操作符(因为包含三个操作数)。

10.逗号表达式

exp1 , exp 2, exp3 , .....expN

逗号表达式就是用逗号隔开的多个表达式。

逗号表达式,在代码中,从左到右依次计算表达式的结果是最后一个表达式的结果。

11.下标引用、函数调用和结构体成员

1. [  ] 下标引用操作符

操作数:一个数组名+ 一个被索引的数

 int arr [ 10 ] ;  //创建数组

 arr [ 9 ]  =  10 ; //使用下标引用操作符

 [ ] 对应的两个操作数是arr 和 9.

2. ( ) 函数调用操作符

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

#include <stdio.h>
 void test1()
 {
 printf("hehe\n");
 }
 void test2(const char *str)
 {
 printf("%s\n", str);
 }
 int main()
 {
 test1();            //实用()作为函数调用操作符。
 test2("hello bit.");//实用()作为函数调用操作符。
 return 0;
 }

3.访问一个结构的成员操作符

.    结构体 .  成员名

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

void set_age1(struct Stu stu)
{
 stu.age = 18;
}
void set_age2(struct Stu* pStu)
{
 pStu->age = 18;//结构成员访问
}
int main()
{
 struct Stu stu;
 struct Stu* pStu = &stu;//结构成员访问
 
 stu.age = 20;//结构成员访问
 set_age1(stu);
 
 pStu->age = 20;//结构成员访问
 set_age2(pStu);
 return 0;
}

12.表达式求值

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

其中这里面包含三个规则 1.隐式类型转换 2. 算术转换 3. 操作符的属性。 影响着表达式的求值结果。

12.1 隐式类型转换

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

说人话:为了计算机方便计算,计算机计算的时候会将不满整形的变量如 char short 先转换成int 再进行计算。

那么如何进行整型提升的呢?

//负数的整形提升
char c1 = -1;
变量c1的二进制位(补码)中只有8个比特位:
1111111
因为 char 为有符号的 char
所以整形提升的时候,高位补充符号位,即为1
提升之后的结果是:
11111111111111111111111111111111
//正数的整形提升
char c2 = 1;
变量c2的二进制位(补码)中只有8个比特位:
00000001
因为 char 为有符号的 char
所以整形提升的时候,高位补充符号位,即为0
提升之后的结果是:
00000000000000000000000000000001
//无符号整形提升,高位补0

12.2 算数转换

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

说人话:不同类型值在计算的时候,会把低的转化为高的计算,但他本身的类型不会改变。

12.3 操作符的属性

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

1. 操作符的优先级

2. 操作符的结合性

3. 是否控制求值顺序。

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

   

       特别要注意:我们写出的表达式如果不能通过操作符的属性确定唯一的计算路径,那这个表达式就是存在问题的,尽量不要写出问题代码。

  如果觉得写的有什么问题内容理解不清晰,欢迎大家评论区或者私信练习我,如果喜欢请别忘记点赞收藏加关注。 

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值