1.操作符的分类
•
算术操作符:
+
、
-
、
*
、
/
、
%
•
移位操作符:
<< >>
•
位操作符:
& | ^
`
•
赋值操作符:
=
、
+=
、
-=
、
*=
、
/=
、
%=
、
<<=
、
>>=
、
&=
、
|=
、
^=
•
单⽬操作符: !、
++
、
--
、
&
、
*
、
+
、
-
、
~
、
sizeof
、
(
类型
)
•
关系操作符:
>
、
>=
、
<
、
<=
、
==
、
!=
•
逻辑操作符:
&&
、
||
•
条件操作符:
? :
•
逗号表达式:
,
•
下标引⽤:
[]
•
函数调⽤:
()
•
结构成员访问:
.
、
->
2.二进制和进制转换
2进制、8进制、10进制、16进制是数值的不同表⽰形式,它们之间可以互相转化。
比如:数值15的各种进制的表示形式
15 的 2 进制: 111115 的 8 进制: 1715 的 10 进制: 1515 的 16 进制: F
重点介绍一下二进制:
⾸先我们还是得从10进制讲起,其实10进制是我们⽣活中经常使⽤的,我们已经形成了很多尝试:
•
10进制中满10进1
•
10进制的数字每⼀位都是0~9的数字组成
其实⼆进制也是⼀样的
•
2进制中满2进1
•
2进制的数字每⼀位都是0~1的数字组成
那么
1101
就是⼆进制的数字了。
2.1 2进制转10进制
以2进制数1101为例,2进制的每一位权重,从右向左依次是:
最终1101转换为10进制的值为13。
2.1.1 10进制转2进制
以125为例,如下图所示:
最终转化为2进制1111101
2.2 2进制转8进制和16进制
2.2.1 2进制转8进制
如:2进制的01101011,换成8进制:0153,0开头的数字,会被当做8进制。
2.2.2 2进制转16进制
如:2进制的01101011,换成16进制:0x6b,16进制表⽰的时候前⾯加0x
3.原码,反码,补码
整数的二进制有三种表示方法,分别是原码,反码,补码。
有符号整数的三种表⽰⽅法均有符号位和数值位两部分,2进制序列中,最⾼位的1位是被当做符 号位,剩余的都是数值位。
符号位都是⽤0表⽰“正”,⽤1表⽰“负”。
正整数的原、反、补码都相同。
负整数的三种表⽰⽅法各不相同。
原码:直接将数值按照正负数的形式翻译成⼆进制得到的就是原码。
反码:将原码的符号位不变,其他位依次按位取反就可以得到反码。
补码:反码+1就得到补码。
反码得到原码也是可以使⽤:取反,+1的操作。
注意
:对于整形来说,数据存放内存中其实放的是补码
4.移位操作符
<< 左移操作符
>> 右移操作符
注意
:移位操作符的操作数只能是整数
4.1左移操作符
移位规则:左边抛弃、右边补0
4.2右移操作符
移位规则:⾸先右移运算分两种:
1. 逻辑右移:左边⽤0填充,右边丢弃
2. 算术右移:左边⽤原该值的符号位填充,右边丢弃
以下为逻辑右移:
以下为算术右移:
警告⚠️
:
对于移位运算符,不要移动负数位,这个是标准未定义的。
5.位操作符:&、|、^、~
位操作符有:
& // 按位与 对应二进制数之间有0则0,无0则1| // 按位或 对应二进制数之间有1则1^ // 按位异或 对应二进制数相同为0,相异为1~ // 按位取反 各个二进制数都取反,包括符号位
注意: 操作数必须为整数。
以下为操作示例:
# include <stdio.h>int main (){int num1 = -3 ;int num2 = 5 ;printf ( "%d\n" , num1 & num2);printf ( "%d\n" , num1 | num2);printf ( "%d\n" , num1 ^ num2);printf ( "%d\n" , ~ 0 );return 0 ;}
同时也可以利用位操作符解决问题,如: 不能创建临时变量(第三个变量),实现两个数的交换。
# 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 ;}
6.单目操作符
单⽬操作符有这些:
!、
++
、
--
、
&
、
*
、
+
、
-
、
~
、
sizeof
、
(
类型
)
单⽬操作符的特点是只有⼀个操作数,在单⽬操作符中只有&和*没有介绍,这2个操作符,我们放在学习指针的时候学习。
7.逗号表达式
exp1, exp2, exp3, …expN
逗号表达式,从左向右依次执⾏。
整个表达式的结果是最后⼀个表达式的结果。
8.下标访问[],函数调用()
8.1[ ]下标引用操作符
操作数:⼀个数组名 + ⼀个索引值 ,如下:
int arr[ 10 ]; // 创建数组arr[ 9 ] = 10 ; // 实⽤下标引⽤操作符。[ ] 的两个操作数是 arr 和 9 。
8.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 ;}
9.结构成员访问操作符
9.1结构体成员的直接访问
结构体成员的直接访问是通过点操作符(.)访问的。点操作符接受两个操作数。如下所⽰:
# include <stdio.h>struct Point{int x;int y;}p = { 1 , 2 };int main (){printf ( "x: %d y: %d\n" , p.x, p.y);return 0 ;}
使⽤⽅式:结构体变量.成员名
9.2结构体成员的间接访问
有时候我们得到的不是⼀个结构体变量,⽽是得到了⼀个指向结构体的指针。如下所⽰:
# include <stdio.h>struct Point{int x;int y;};int main (){struct Point p = { 3 , 4 };struct Point * ptr = &p;ptr->x = 10 ;ptr->y = 20 ;printf ( "x = %d y = %d\n" , ptr->x, ptr->y);return 0 ;}
使⽤⽅式:结构体指针->成员名
10.操作付的属性:优先性和结合性
10.1优先级
优先级指的是,如果⼀个表达式包含多个运算符,哪个运算符应该优先执⾏。各种运算符的优先级是不⼀样的。
10.2结合性
如果两个运算符优先级相同,优先级没办法确定先计算哪个了,这时候就看结合性了,则根据运算符是左结合,还是右结合,决定执⾏顺序。
以下为优先性和结和性的表格:
11.表达式求值
11.1整型提升
表达式中的字符和短整型操作数在使⽤之前被转换为普通整型,这种转换称为整
型升。
// 实例 1char a,b,c;...a = b + c;
上述的b和c的值被提升为普通整形,然后再执行加法算法
整型提升的方法:
1.
有符号整数提升是按照变量的数据类型的符号位来提升的
2.
⽆符号整数提升,⾼位补0
11.2算术转化
如果某个操作符的各个操作数属于不同的类型,那么除⾮其中⼀个操作数的转换为另⼀个操作数的类型,否则操作就⽆法进⾏。下⾯的层次体系称为寻常算术转换。
long doubledoublefloatunsigned long intlong intunsigned intint
如果某个操作数的类型在上⾯这个列表中排名靠后,那么⾸先要转换为另外⼀个操作数的类型后执⾏运算。