认识C语言 Day_8 > 操作符

目录

1.操作符分类

2.算数操作符

3.移位操作符

3.1铺垫知识

二进制序列

原码、反码、补码

3.2左移操作符

3.3右移操作符

4.位操作符

4.1按位与

4.2按位或

4.3按位异或

5.赋值操作符

5.1赋值操作符

5.2复合赋值符

6.单目操作符

6.1逻辑反操作符 !

6.2取地址符 &

6.3解引用操作符 *

6.4sizeof 操作符

6.5按位取反操作符 ~

6.6自增自减操作符 -- ++

7.关系操作符

8.逻辑操作符

逻辑与 &&

逻辑或 ||

9.条件操作符

10.逗号表达式

例1

例2

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

11.1下标引用操作符

11.2函数调用操作符

11.3访问结构成员

12.表达式求值

12.1隐式类型转换

12.2算术转换

12.3操作符的属性

操作符优先级和结合性

13.结束


1.操作符分类

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

2.算数操作符

  +       -        *        /       %

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

我们可以在VS中运算一下 

认识C语言 Day_8 > 操作符_第1张图片

3.移位操作符

 << 左移操作符

 >> 右移操作符

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

可以这样写代码

int x = 7 >> 1;

3.1铺垫知识

移位操作符移动的是二进制位

二进制序列

对于一个整数是4个字节,一个字节是8个bit位,那么一个整数就是32个bit位

一个整数写出二进制序列的时候,就是32个bit位

  • 对于有符号整数来说,最高位是符号位:符号位是1表示负数,符号位是0表示正数
  • 对于无符号整数来说,所有位都是有效位,没有符号位

所以,负数写成二进制序列的话,最高位一定是1;正数写成二进制序列,最高位一定是0;

认识C语言 Day_8 > 操作符_第2张图片

原码、反码、补码

整数的二进制表示形式有三种:原码、反码、补码

对于正整数来说,原码、反码、补码相同

对于负数来说

原码:按照数值的正负,直接写出的二进制序列

反码:原码的符号位不变,其他位按位取反(0变成1,1变成0)

补码:反码的二进制+1

0当作无符号数看待 

整数在内存中存的都是补码 

举个例子:

10:

原码:00000000 00000000 00000000 00001010

反码:00000000 00000000 00000000 00001010

补码:00000000 00000000 00000000 00001010

-10:

原码:10000000 00000000 00000000 00001010

反码: 11111111  11111111   11111111  1111 0101

补码: 11111111  11111111   11111111  1111 0110

3.2左移操作符

我们用图来解释

认识C语言 Day_8 > 操作符_第3张图片

左移一位即是,二进制序列向左移动一位,在末尾补一个0,形成新的二进制序列 

移位的时候移动的是补码

左移n位效果相当于,乘上2的n次方 

认识C语言 Day_8 > 操作符_第4张图片

认识C语言 Day_8 > 操作符_第5张图片

m只参与运算,m的值不变,这里m移位的结果其实是n的值

所以我们总结下来,向左移位的规则就是:左边丢弃,右边补0 

负数同样的道理

认识C语言 Day_8 > 操作符_第6张图片

认识C语言 Day_8 > 操作符_第7张图片

3.3右移操作符

移位规则:

首先右移运算分为两种:

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

逻辑右移还是算数右移,取决于编译器 ;绝大部分编译器采取的是算数右移

认识C语言 Day_8 > 操作符_第8张图片

认识C语言 Day_8 > 操作符_第9张图片

认识C语言 Day_8 > 操作符_第10张图片 

右移n位的效果相当于,除以n的k次方

注意:不管是左移还是右移,不要移动负数位,比如:>>-1,<<-1

4.位操作符

位操作符有:

      //按位与

 |        //按位或

^        //按位异或

注意:操作数必须是整数

这里我们所说的按位,都是按二进制位 

都是按照补码进行运算的

4.1按位与

举个例子

认识C语言 Day_8 > 操作符_第11张图片

所以,按位与 & 的运算规则是

  1. 只要有0则为0
  2. 两个都是1才为1
  3. 结果是补码,需要还原成原码到十进制数

认识C语言 Day_8 > 操作符_第12张图片

按位与的使用,可以得到想得到的位:先移位,再按位与

比如,我想得到3的最低位,那么我就按位与1

如果想得到第n位,那么可以把第n位移到最低位,再按位与1

4.2按位或

举个例子

认识C语言 Day_8 > 操作符_第13张图片

所以,按位或 | 的运算规则是

  1. 有1则为1
  2. 全0才为0
  3. 结果是补码,需要还原成原码到十进制数

4.3按位异或

举个例子

认识C语言 Day_8 > 操作符_第14张图片

异或运算的特点:

  1. 相同为0,相异为1
  2. 结果是补码,需要还原成原码到十进制数

按位异或的使用,根据相同为0,相异为1;比如

a^a=0 

0^a=a

我们可以利用异或运算的特点,用不创建临时变量的方法交换两个数的值;看代码

int main()
{
	int a, b;
	scanf("%d %d", &a, &b);
	a = a ^ b;
	b = a ^ b;//即 a ^ b ^ b = a ^ 0 = a;
	a = a ^ b;//即 a ^ b ^ a = 0 ^ b = b;
	printf("%d %d", a, b);
	return 0;
}

认识C语言 Day_8 > 操作符_第15张图片

5.赋值操作符

5.1赋值操作符

赋值操作符是一个非常棒的操作符,他可以让你得到一个你之前不满意的值,也就是可以重新赋值

int weight = 120;//体重
weight = 89;//不满意就赋值
double salary = 10000.0;
salary = 20000.0;//使用赋值操作符赋值

赋值操作符可以连续使用,比如:

	int a = 10;
	int x = 0;
	int y = 20;
	a = x = y + 1;//连续赋值

这样的写法更加清晰而且易于调试 

5.2复合赋值符

+=   -=    *=    /=    %=    >>=    <<=    &=    |=     ^=

这些运算符都可以写成复合的效果,比如:

	int x = 10;
	x = x + 10;
	x += 10;//复合赋值

 同样的道理,这样写更加简洁

6.单目操作符

!             逻辑反操作

-               负值

+              正值

&              取地址

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

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

--              前置、后置  --

++             前置、后置  ++

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

(类型)        强制类型转换

6.1逻辑反操作符 !

想要把假变成真,把真变成假的时候

如果 a 为真,则!a为假 

6.2取地址符 &

	int a = 10;
	&a;//a变量的地址
	int arr[10];
	&arr;//这是数组的地址
    int*p = &a;//可以用指针变量接收地址

6.3解引用操作符 *

解引用操作符 * 和取地址符 & 通常是搭配使用的 

*p;//对p进行解引用操作,*p是通过p中存放的地址找到p指向的对象

6.4sizeof 操作符

sizeof 是操作符而不是函数

  • sizeof 是在计算类型创建变量或者变量的大小,单位是字节
  • sizeof 计算的结果是size_t 类型的
  • size_t 是无符号整型
  • 对 size_t 类型的数据进行打印,可以使用 %zd 

6.5按位取反操作符 ~

~的作用是全部取反,无论是符号位还是其他位,比如:

认识C语言 Day_8 > 操作符_第16张图片

认识C语言 Day_8 > 操作符_第17张图片

6.6自增自减操作符 -- ++

++是一种自增1的操作

自增分为:

前置++:即++a,先+1,后使用

后置++:即a++,先使用,后+1

--是一种自减1的操作

自减分为:

前置 --:即--a,先-1,后使用

后置 --:即a--,先使用,后-1

7.关系操作符

    大于

>=    大于等于

    小于

<=    小于等于

!=     不等于                    用于测试“不相等”

==    等于(表判断)      用于测试“相等”

在编程的过程中,注意不要把 == 和 = 写错了 

  • ==表判断
  • =表赋值

8.逻辑操作符

&&     逻辑与

 ||       逻辑或

区分逻辑与按位与

区分逻辑或按位或 

1&2     ------>0

1&&2  ------>1    //逻辑与

1|2      ------>3

1||2     ------>1    //逻辑或

逻辑与 &&

逻辑与&&表示并且的意思:同时为真才为真

举个例子:a&&b&&d++   

//这个时候如果a为,则&&后面不再执行;如果a为,则判断b,b如果为假,则&&后面的d++不再执行

逻辑或 ||

逻辑或 || 表示或者的意思:一个为真就为真

举个例子:a||b||d++   

//这个时候如果a为,则判断b,b如果为,则||后面的d++不再执行;如果a为,则||后面不再执行

9.条件操作符

条件操作符也称为三目操作符

exp1 ? exp2 : exp3

条件操作符的作用是:

  • 如果exp1为,则执行exp2
  • 如果exp1为,则执行exp3 

10.逗号表达式

exp1 , exp2 , exp3 , ... expN

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

逗号表达式,从左向右依次执行,整个表达式的结果是最后一个表达式的结果

例1

int main() {
	int a = 1;
	int b = 2;
	int c = (a > b, a = b + 10, a, b = a + 1);
	printf("%d", c);
	return 0;
}

认识C语言 Day_8 > 操作符_第18张图片

例2

a = get_val();
count_val(a);
while (a > 0) {
	//业务处理
	a = get_val();
	count_val(a);
}

 如果用逗号表达式改写:

while (a = get_val(), count_val(a), a > 0) {
	//业务处理
}

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

11.1下标引用操作符

"[ ]"就是下标引用操作符,用在数组中

操作数:一个数组名+一个索引值

int arr[10];//创建数组
arr[9] = 10;//使用下标引用操作符
[ ]的两个操作数是arr和9 

[ ]的操作数有两个

11.2函数调用操作符

"( )"就是函数调用操作符

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

void test(int a, int b) {
	return a + b;
}
int main() {
	int a, b;
	test(a, b);
	return 0;
}
函数名和参数都是()的操作数

11.3访问结构成员

.      结构体.成员名

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

结构体.成员名

struct Book {
	char name[20];
	int price;
};
int main() {
	struct Book b = { "C语言指南",55 };
	printf("%s %d", b.name, b.price);
	return 0;
}

认识C语言 Day_8 > 操作符_第19张图片 

结构体指针->成员名

struct Book {
	char name[20];
	int price;
};
void Print(struct Book* pb)
{
	printf("%s %d", pb->name, pb->price);
}
int main() {
	struct Book b = { "C语言指南",55 };
	Print(&b);
	return 0;
}

认识C语言 Day_8 > 操作符_第20张图片

这两句代码是等价的

printf("%s %d", (*pb).name, (*pb).price);
printf("%s %d", pb->name, pb->price);

认识C语言 Day_8 > 操作符_第21张图片

12.表达式求值

表达式求值的顺序一部分是由操作符的优先级结合性决定

同样,有些表达式的操作数在求值的过程中可能需要转换为其他类型

12.1隐式类型转换

C的整型算数运算总是至少以缺省型类型的精度来进行的

为了获得这个精度,表达式中的字符短整型操作数在使用之前被转换为普通整型,这种转换称为整型提升

整型提升的意义

表达式的整型运算要在CPU的相应运算器件内执行,CPU内整型运算器(ALU)的操作数的字节长度一般就是int的字节长度,同时也是CPU的通用寄存器的长度

因此,即使两个char类型的相加,在CPU执行时实际上也要先转换位CPU内整型操作数的标准长度

通用CPU是难以直接实现两个8bit字节直接相加运算,所以,表达式中各种长度可能小于int长度的整型值,都必须先转换为int或unsigned int,然后才能送入CPU去执行运算

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

认识C语言 Day_8 > 操作符_第22张图片

整型提升针对的是自身大小 小于整型大小的操作数 

12.2算术转换

如果某个操作符的各个操作数属于不同的类型,那么除非其中以一个操作数转换为另一个操作数的类型,否则操作就无法进行

下面的层次体系称为寻常算术转换

long double

double

float

unsigned long int

long int 

unsigned int

int 

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

比如,int 和 float 运算,会把 int 转换成 float(向上转换

但是算术转换要合理,要不然会有一些潜在的问题 

12.3操作符的属性

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

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

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

操作符优先级和结合性

优先级

运算符

名称或含义

使用形式

结合方向

说明

1

[]

数组下标

数组名[常量表达式]

左到右

-----

()

圆括号

(表达式)/函数名(形参表)

-----

.

成员选择(对象)

对象.成员名

-----

->

成员选择(指针)

对象指针->成员名

-----

2

-

负号运算符

-表达式

右到左

单目运算符

(类型)

强制类型转换

(数据类型)表达式

-----

++

前置自增运算符

++变量名

单目运算符

++

后置自增运算符

变量名++

单目运算符

--

前置自减运算符

--变量名

单目运算符

--

后置自减运算符

变量名--

单目运算符 [4] 

*

取值运算符

*指针变量

单目运算符

&

取地址运算符

&变量名

单目运算符

!

逻辑非运算符

!表达式

单目运算符

~

按位取反运算符

~表达式

单目运算符

sizeof

长度运算符

sizeof(表达式)

-----

3

/

表达式/表达式

左到右

双目运算符

*

表达式*表达式

双目运算符

%

余数(取模)

整型表达式/整型表达式

双目运算符

4

+

表达式+表达式

左到右

双目运算符

-

表达式-表达式

双目运算符

5

<<

左移

变量

左到右

双目运算符

>>

右移

变量>>表达式

双目运算符

6

>

大于

表达式>表达式

左到右

双目运算符

>=

大于等于

表达式>=表达式

双目运算符

<

小于

表达式

双目运算符

<=

小于等于

表达式

双目运算符

7

==

等于

表达式==表达式

左到右

双目运算符

!=

不等于

表达式!= 表达式

双目运算符

8

&

按位与

表达式&表达式

左到右

双目运算符

9

^

按位异或

表达式^表达式

左到右

双目运算符

10

|

按位或

表达式|表达式

左到右

双目运算符

11

&&

逻辑与

表达式&&表达式

左到右

双目运算符

12

||

逻辑或

表达式||表达式

左到右

双目运算符

13

?:

条件运算符

表达式1? 表达式2: 表达式3

右到左

三目运算符

14

=

赋值运算符

变量=表达式

右到左

-----

/=

除后赋值

变量/=表达式

-----

*=

乘后赋值

变量*=表达式

-----

%=

取模后赋值

变量%=表达式

-----

+=

加后赋值

变量+=表达式

-----

-=

减后赋值

变量-=表达式

-----

<<=

左移后赋值

变量

-----

>>=

右移后赋值

变量>>=表达式

-----

&=

按位与后赋值

变量&=表达式

-----

^=

按位异或后赋值

变量^=表达式

-----

|=

按位或后赋值

变量|=表达式

-----

15

,

逗号运算符

表达式,表达式,…

左到右

从左向右顺序运算

  1. 优先级与求值顺序无关。如a+b && b*c,虽然*优先级最高,但这个表达式求值顺序是从左到右
  2. 优先级从上到下依次递减,最上面具有最高的优先级,逗号操作符具有最低的优先级
  3. 相同优先级中,按结合性进行结合。大多数运算符结合性是从左到右,只有三个优先级是从右至左结合的,它们是单目运算符、、条件运算符、赋值运算符 

13.结束

那么今天的学习就到这里咯,今天我们学习了操作符的知识

小杜跟各位小伙伴在一起成长,祝我们都能成为大牛!

                                                                                                                                //小杜的成长之路

你可能感兴趣的:(#,初始C语言,c语言,开发语言)