一、算术操作符 + - * / %
1.除法/
(1).整数除法
int a = 5 / 2;
printf("a = %d", a);
a = 2 //除出来的结果只取整数
(2).小数除法
double a = 5.0 / 2;
double b = 5 / 2.0;
printf("a = %lf", a);
printf("b = %lf", a);
a = 2.500000
b = 2.500000 //除号两边至少有一个是浮点数
2.取模%
int a = 5 % 2;
printf("a = %d", a);
a = 1 //两边操作数只能是整型
二、移位操作符
1.右移操作符>>,移动的是二进制位
(1).算术移位:先把整数转换成二进制数(计算时负数应该是补码形式,反码+1),整体向右移动,丢弃最后一位,前面补符号位
(2).逻辑位移:先把整数转换成二进制数,整体向右移动,丢弃最后一位,前面补0
2.左移操作符<<,整体向左移动,丢弃第一位(符号位不会丢弃),直接最后一位补0
三、位操作符,两边操作数都是整数
1.按位与&:先把整数转换为二进制数(负数为补码形式),同为0为0,同为1为1,不同为0,真真才真
2.按位或|,同为0为0,同为1为1,不同为1,假假才假
3.按位异或^,相同为0,不同为1
四、赋值操作符 =
a = x = y + 2;
相当于
x = y + 2;
a = x;
五、复合赋值符 += -= *= /= %= >>= <<= &= |= ^=
a += 2;
相当于
a = a + 2;
六、单目操作符(只有一个操作数)
1. ! - +
2. & 取地址
3. sizeof 计算所占内存空间大小
sizeof a 计算变量可以去掉括号,sizeof(int)计算类型不能省略括号
注意数组计算所占内存空间大小int arr[10];------>sizeof(int [10])或者sizeof(arr)
例1
short a = 0;
int b = 2;
printf("%d\n", sizeof(a = b + 1));
printf("%d\n", a);
结果是2 0
第一个因为a是short型,short型占2个字节,不管赋值多少都是short型
第二个因为sizeof里的表达式不计算在真实计算中,所以a还是0
例2
void test(int arr[])
{
printf("%d\n", sizeof(arr));
}
int main()
{
int arr[10] = {0};
test(arr);
}
结果是4或8
因为数组作为参数传进去需要指针来接收,此时test函数里的arr就是指针,而指针所占内存空间大小在32位平台上是4个字节,64位平台上是8个字节,所以结果是4或8
4. ~ 二进制按位取反
注意电脑里存储的是补码,所以按位取反(符号位也取反)后需计算其原码
5. -- ++ 分为前置和后置
前置:先++,再使用
后置:先使用,再++
int a = 2;
printf("%d\n", ++a); //结果为3
printf("%d\n", a++); //结果为2
printf("%d\n", a); //结果为3
6. * 间接访问操作符(解引用操作符)
7. (类型) 强制类型转换
七、关系操作符 > >= < <= != ==
八、逻辑操作符(只看真假)
&& 逻辑与 真真才真
例1
int i = 0, a = 0, b = 1, c = 2, d = 3;
i = a++ && b++ && ++c;
printf("%d, %d, %d, %d", a, b, c, d);
结果为1, 1, 2, 3
首先a++是先使用再加,所以第一个逻辑与的左边为0,此时第一个逻辑与就已经得出计算结果为0,所以不用计算后面的b++,而后面也是逻辑与所以后面的++c也不用计算,所以电脑不会计算b++和++c,b还是1,c还是2
逻辑与左边结果为假时,右边不管真假也不会计算
|| 逻辑或 假假才假
逻辑或左边结果为真时,右边就不会再计算
九、条件操作符
表达式1 ? 表达式2 : 表达式3
如果表达式1为真,计算表达式2,;否则计算表达式3
a > 5 ? b = 1 : b = 2;
或者
b = (a > 5 ? 1 : 2);
十、逗号表达式
用逗号隔开的多个表达式,从左向右依次执行。整个表达式的结果是最后一个表达式的结果。
d = (a = a + 2, a > 0, b > a, c = a + b);
或者
if(a > 0, a++, b > a)
或者
while(a = fun1(), b = fun2(), b > 0)
十一、下标引用操作符 [ ] (有两个操作数)
a[4] = 2; a和4就是操作数
十二、函数调用操作符( ) (一个或多个操作数)
函数名和多个参数就是操作数
十三、结构体成员访问操作符 . ->
//创建一个结构体类型
struct Stu
{
char name[20];
int age;
char id[20];
}
//创建一个struct Stu类型的对象
//结构体的初始化用花括号
struct Stu s1 = {"张三", 20, "10001"};
//使用.访问结构体成员
//结构体变量.成员名
s1.name;
s1.age;
s1.id;
//使用->访问结构体成员
//先用一个指针变量存放s1的地址
struct Stu* ps = &s1;
ps->name;
(*ps).name;
十三、隐式类型转换
1.整型提升
只要是char或短整型等位数比int小的,参与运算时都会整型提升
char a = 3;
char b = 127;
char c = a + b;c输出为:-126
这是因为整型有32位,为了转换为字符型,只取后八位:
然后当两个char类型相加时(a+b时),需要整型提升,对于有符号的类型,如果第一位是0,补的24位数都是0,反之亦然:
再将加后的结果赋给c,也是取后八位:
c只要参与表达式运算就会整型提升,所以将c整型提升,第一位是1,前面补1:
char c = 3;
sizeof(c); //输出1
sizeof(+c); //正c,输出4
sizeof(!c); //输出1
只要c参与运算就会整型提升,但是为啥!c是1,没搞懂
2. 算术转换
位数大于或等于int类型的类型,会将位数小的类型转换为位数大的类型
比如int和float,要先将int转换为float类型再计算
c+--c;
//这个表达式有歧义。就是说如果c为1,那么可以看作1+--c,然后--c得0,表达式得1。也可以看作c+--c,--c得0,那么c = 0,表达式就是0+0得0。所以并不能判断第一个c的值到底是多少
这个代码也有问题,不能判断先调用哪个fun()函数,虽然*优先级大于+
int i = 0;
int ret = (++i) + (++i) + (++i);
这个代码在不同的操作系统下会得出不同的答案,所以这个代码也是有问题的