1.算术操作符
算术操作符十分简单也十分常用有:+ - * / %
+:指的就是两个数的相加,我觉得没有什么好说的
-:指的是两个数的相减
*:指的就是两个数的乘法运算
/:指的如果是两个整数的除法,但是是向下取整,比如说5/2是2.5,但是在C语言来说是2,
%:指的是余数 比如5%2=1;
1. 除了 % 操作符之外,其他的几个操作符可以作用于整数和浮点数。
2. 对于 / 操作符如果两个操作数都为整数,执行整数除法。而只要有浮点数执行的就是浮点数除法。
3. % 操作符的两个操作数必须为整数。返回的是整除之后的余数。
2.移位操作符
有<<:左移操作符
>>:右移操作符
注意:移位操作符的操作数只能是整数
2.1左移操作符
移动规则:左边抛弃,右边补0
int num = 10;//整形有四个字节,有32个bit位
000000000000000000000000000001010
int a = num<<1;
000000000000000000000000000010100

如果不给num<<1赋值给一个新的变量的话,是不会改变num的值的
2.2右移操作符

一般都是第一种,但是在这里还是给大家一一介绍了
不过在这里要给大家介绍原码和补码以及反码了
原码,补码,反码
int num = 0;
num = -1;//当num是负数的时候
//10000000000000000000000000000001;(原码)
//11111111111111111111111111111110;(反码)
//11111111111111111111111111111111;(补码)
//11111111111111111111111111111111;(用右移操作符的算术规则)
//01111111111111111111111111111111;(逻辑右移规则)
原码就是我们在计算这个数的时候看到的,反码就是符号位不变(首元素),其余的全部取反
补码就是在反码的基础上的末位+1,内存中储存数是以补码的形式储存的
既然在内存中储存的是他的补码,因为对于正数来说原码补码反码都是一样的,但是一旦遇到负数就要特别小心了,在使用右移操作符的时候要用负数的补码


3.位操作符
&//按位与操作符
|//按位或操作符
^//按位异或操作符
int num1 = 1;
int num2 = 2;
num1&num2
001
010
000//只有对应位置上的都是1才能1
num1|num2
001
010
011//只要对应位置上有1就是1
num1^num2
001
010
011//对应位置上相同是0,不相同就是1
练习1

这是一道很变态的面试题目,面试官为了考察你的思维能力,但是这个代码的运行速度慢,可读性很差,不建议平常使用,但是一定要知道这个方法,当然对于交换两个数的变量也有其他的方法

这个也是符合要求的一种方法,但是这个会出现一种问题,当a和b足够大的时候,可能会出现位栈出的问题。

练习2
方法一

方法二


练习3

4.赋值操作符
赋值操作符使用起来非常简单,例如:
int num = 0;
num = 1;//这个就是其中一个赋值操作符的使用
//另外,还有一些复合赋值操作符
//比如a+=1
int a =0;
a = a+1;
a+=1;//这两种是一样的效果

5.单目操作符

int a = 10;
printf("%d",sizeof(a));//4
printf("%d",sizeof(int));//4
//使用单目操作符sizeof()的时候,引用int的时候一定要加括号,引用变量a的时候可以加也可以不加



6.关系操作符

7.逻辑操作符

逻辑与&&相当于Python中的and(只有前面是真才会计算后面的)
逻辑或||相当于Python中的or(只有前面是假才会计算后面的)
#include <stdio.h>
int main()
{
int i = 0,a=0,b=2,c =3,d=4;
i = a++ && ++b && d++;
//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,所以结果就是1 2 3 4
#include <stdio.h>
int main()
{
int i = 0,a=0,b=2,c =3,d=4;
//i = a++ && ++b && d++;
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 为假 则后面就要运行了,++b那一步b是3,所以后面不会再运行了 ,所以结果是 1 3 3 4
8.条件操作符


//如果用条件操作符的话
max = (a>b?a:b);//a>b吗?,如果是真的,那么就是第一个表达式,如果是假的,就是下一个
9.逗号表达式

10.下标引用操作符

11.函数调用操作符
()函数调用操作符
接受一个或者多个操作数,第一个操作数是函数名,剩余的操作数就是传递给函数的参数(实参)
#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;
}
12.结构成员访问

13.表达式求值
表达式求值的顺序的一部分是有操作符的优先级还有结合性来决定的,同样,有些表达式的操作数在求值的过程中可能需要转换为其他类型
13.1隐式类型转换
C的整型算术运算总是至少以缺省整型类型的精度来进行的。
为了获得这个精度,表达式中的字符和短整型操作数在使用之前被转换为普通整型,这种转换称为整型
提升。
整型提升的意义:
表达式的整型运算要在CPU的相应运算器件内执行,CPU内整型运算器(ALU)的操作数的字节长度
一般就是int的字节长度,同时也是CPU的通用寄存器的长度。
因此,即使两个char类型的相加,在CPU执行时实际上也要先转换为CPU内整型操作数的标准长
度。
通用CPU(general-purpose CPU)是难以直接实现两个8比特字节直接相加运算(虽然机器指令
中可能有这种字节相加指令)。所以,表达式中各种长度可能小于int长度的整型值,都必须先转
换为int或unsigned int,然后才能送入CPU去执行运算。
char a = 1;
char b = 2;
char c=a+b;//低于32位bit运算的时候就会整形提升
a 00000001->000000000000000000000000000000001
b 00000010->000000000000000000000000000000010
c 二进制相加->000000000000000000000000000000011
根据最后是用char储存进行截断,从最低位开始00000011

int main()
{
char c = 1;//%u(unsigned int)
printf("%u\n", sizeof(c));// 1//%u的意思就是没有符号的整形
printf("%u\n", sizeof(+c));// 4//进行了运算+变成4个字节
printf("%u\n", sizeof(-c));// 4 //进行了运算-变成4个字节
return 0;
}
13.2算术转换
如果某个操作符的各个操作数属于不同的类型,那么除非其中一个操作数的转换为另一个操作数的类
型,否则操作就无法进行。下面的层次体系称为寻常算术转换

如果某个操作数的类型在上面这个列表中排名较低,那么首先要转换为另外一个操作数的类型后执行运
算。
13.3操作符的属性
复杂表达式的求值有三个影响的因素。
1. 操作符的优先级
2. 操作符的结合性
3. 是否控制求值顺序。
两个相邻的操作符先执行哪个?取决于他们的优先级。如果两者的优先级相同,取决于他们的结合性。
操作符优先级




上表中可以总结出如下规律:
结合方向只有三个是从右往左,其余都是从左往右。
所有双目运算符中只有赋值运算符的结合方向是从右往左。
另外两个从右往左结合的运算符也很好记,因为它们很特殊:一个是单目运算符,一个是三目运算符。
C语言中有且只有一个三目运算符。
逗号运算符的优先级最低,要记住。
此外要记住,对于优先级:算术运算符 > 关系运算符 > 逻辑运算符 > 赋值运算符。逻辑运算符中“逻辑非 !”除外
