操作符的知识内容比较多,十分广泛。但是每一个知识点的难度都不高,稍有了解很快就能掌握。话不多说让我们开始吧.
目录
1.算术操作符
2.移位操作符
2.1 左移操作符 <<
2.2 右移操作符 >>
3.位操作符
3.1 按位与 &
3.2 按位或 |
3.3 按位异或 ^
4.赋值操作符
5.单目操作符
5.1 !
5.2 ~
5.3 前置++、后置++
6.关系操作符
7. 逻辑操作符
8.条件操作符
9.逗号表达式
10.下标引用、函数调用和结构成员
10.1 [] 下标引用操作符
10.2 ( ) 函数调用操作符
10.3 访问结构体成员
11.表达式求值:隐式类型转换
11.1 整形提升
11.2 算数转化
11.3 操作符的属性
1.算术操作符
算术操作符有:+ - * / %
值得注意的是,%只能用于整数,/两边需要注意输出的类型
如果想要除法输出的是小数,那么/左右两边至少有一边需要输入的是带有小数点的数字。
2.移位操作符
首先我们必须知道,整数有三种二进制的表示形式:原码、反码和补码。
正整数:原码、反码和补码相同
负整数:原码、反码和补码不同,并且要进行计算
2.1 左移操作符 <<
其实计算的时候可以简单看成往左移1就是乘了2的1次方
2.2 右移操作符 >>
右移操作符分为算术右移和逻辑右移。
逻辑移位:左边用0填充,右边丢弃
算术移位:左边用原该值的符号位填充,右边丢弃。
但常见的编译器是算数右移
另外,需要补充的是移位运算符不要移动负数位,如<<-1不行。
3.位操作符
位操作符有:& 按位与 | 按位或 ^ 按位异或
3.1 按位与 &
二进制数都为1才为1
3.2 按位或 |
二进制数有1为1,没有1为0
3.3 按位异或 ^
二进制数相同为0,不同为1
4.赋值操作符
赋值 =;复合赋值符:+= -= *= /= %= >>= <<= &= |= ^=
特别注意:赋值是一个等于号!!!
a = a+10; a += 10; 意思是一样的
5.单目操作符
单目操作符,顾名思义是对一个数字进行操作
! 逻辑反操作
- 负值
+ 正值
& 取地址
sizeof 操作数的类型长度(以字节为单位)
~ 对一个数的二进制按位取反
-- 前置、后置--
++ 前置、后置++
* 间接访问操作符(解引用操作符)
(类型) 强制类型转换
5.1 !
! 逻辑反操作:把真(非零的数)变为假(0),假(0)变为真(1)
5.2 ~
~ 按位(位指的是补码的二进制)取反
首先搞懂 “反码”,“取反”,“按位取反(~)”,这3个概念是不一样的。
取反:0变1,1变0
反码:正数的反码是其本身,对于负数其符号位不变其它各位取反(0变1,1变0)
这里先以-3为例,-3的32bit取8位
原码为1000 0011
反码为1111 1100
补码为1111 1101(反码+1)
补码取反:0000 0010
新数字反码、补码、原码都一样,这个数字为2
1. 所有正整数的按位取反是其本身+1的负数
2. 所有负整数的按位取反是其本身+1的绝对值
3. 零的按位取反是 -1(0在数学界既不是正数也不是负数)
5.3 前置++、后置++
++a,代表a在使用前自加1,再使用
a++,代表a在使用后自加1
6.关系操作符
> >= < <= != ==
需要额外注意的是, = 和 == 一定要区分清楚!!!
我们可以这样写
int a = 5; if(5==a) { }
这样子在编译的时候就容易发现错误
7. 逻辑操作符
逻辑与 &&
逻辑或 ||
现在有一道题:
#include <stdio.h>
int main()
{
int i = 0,a=0,b=2,c=3,d=4;
i = a++ && ++b && d++;
printf("a = %d\n b = %d\n c = %d\nd = %d\n", a, b, c, d);
return 0; }
//程序输出的结果是什么?
a++时,因为a为0,所以所有的&&都不会再进行运算了。故打印出来只有a比初始化时加了1
我们把题目改一下:
#include <stdio.h>
int main()
{
int i = 1,a=0,b=2,c=3,d=4;
i = a++ || ++b || d++;
printf("a = %d\n b = %d\n c = %d\nd = %d\n", a, b, c, d);
return 0; }
//程序输出的结果是什么?
a++时,||左边为1,判定为真,所以右边的||都不算了
8.条件操作符
exp1 ? exp2 : exp3
问号前面的是真执行exp2,是假执行exp3
9.逗号表达式
exp1, exp2, exp3, …expN
用法如下:
int main() { int a = 3; int b = 4; int c = 5 int d = (a+=2,b=a-c,c=a+2*b); printf("%d",d); return 0; }
执行的是最后一个逗号之后的值
同时可以用逗号表达式简化一些表达:
//代码1
int a = 1;
int b = 2;
int c = (a>b, a=b+10, a, b=a+1);//逗号表达式
c是多少?
//代码2
if (a =b + 1, c=a / 2, d > 0)
//代码3 a = get_val();
count_val(a);
while (a > 0) {
//业务处理
a = get_val();
count_val(a);
}
如果使用逗号表达式,改写:
while (a = get_val(), count_val(a), a>0) {
//业务处理
}
10.下标引用、函数调用和结构成员
10.1 [] 下标引用操作符
int arr[10]; arr[9] = 10;//arr数组的第十个元素是10
[] 的两个操作数为 arr和9,arr和9可以互换位置,但不常见。
10.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; }
10.3 访问结构体成员
.结构体
后面我们还会详细的讲解这部分内容
11.表达式求值:隐式类型转换
11.1 整形提升
首先我们先看一段代码
结果为什么是-125呢?这里涉及到整形提升这个概念。
C 的整型算术运算总是至少以缺省整型类型的精度来进行的。
为了获得这个精度,表达式中的字符和短整型操作数在使用之前被转换为普通整型,这种转换称为 整型提升 。
简单来说,就是非int(unsigned int)的值应该先转化为int(unsigned int)进行储存,进行计算
具体怎么运算呢?
5在内存中有32个比特位,00000000000000000000000000000101
但是a是char类型的,只能存储8个比特位。所以5就被“截断”了。a中存储的只有0000 0101
同理,126在b中被截断为0111 1110
如何进行整形提升呢?
整形提升是按照变量的数据类型的符号位来提升的
(负数高位补1,整数或无符号数高位补0)
00000000000000000000000000000101 ---a
000000000000000000000000001111110 ---b
00000000000000000000000010000011 ---相加后
所以此时c就是 1000 0011 此时又因为c是char类型
再次整形提升:
11111111111111111111111110000011 ---补码
11111111111111111111111110000010 ---反码(补码-1)
10000000000000000000001111101 ---原码>> -125
这就是提升之后的结果。另外提一嘴:只有char和short类型的变量才会发生整形提升。
11.2 算数转化
大于4个字节的类型的转换不叫整形提升,而交做算数转化。
long double double float unsigned long int long int unsigned int int
如果某个操作数的类型在上面这个列表中排名较低,那么首先要转换为另外一个操作数的类型后执行运算。如10/3不进行算数转换算出来的是int类型。
补充:sizeof内部的表达式不进行计算
int main()
{
short s = 20;
int a = 5;
printf("%d\n",sizeof(s = a + 4));
printf("%d\n",s)
return 0;
}
最终的结果是2和20。
11.3 操作符的属性
复杂表达式的求值有三个影响的因素。
1. 操作符的优先级
2. 操作符的结合性
3. 是否控制求值顺序。
我们平时在写代码的时候一定要避免写出有歧义的代码。多种操作符夹杂在一起,有时会让不同编译器都出现不同的结果。
//代码3-非法表达式 int main() { int i = 10; i = i-- - --i * ( i = -3 ) * i++ + ++i; printf("i = %d\n", i); return 0; }
这个代码在不同的编译器里面出现了很多种不同的结果。这是非常糟糕的写法,一定要避免写出这样子的代码。
那么今天的内容就到这里了。操作符内容十分庞大,但其实都不难。自己多去理解理解就好啦~
这一期的内容真的鸽了很久很久,如果觉得还不错的话把你们的赞留下吧!感谢!