1、操作符分类
操作符分类:算术操作符、移位操作符、位操作符、赋值操作符、单目操作符、关系操作符、逻辑操作符、条件操作符、逗号表达式、下标引用、函数调用和结构成员。
2、算术操作符
算术操作符包括:+(加) -(减) *(乘) /(除) %(取模),均含有两个操作数。
int main()
{
int a = 9;
int b = 3;
int c = a * b;
int d = a / b;
int e = a + b;
int i = a - b;
int j = a % b;
return 0;
}
算术操作符 + - * / 的操作数既可以是整数,也可以是浮点数;
如果两个操作数都为整数,执行整数除法,而只要有浮点数执行的就是浮点数除法。
int main()
{
float a = 9.3;
int b = 3;
float c = a * b;
float d = a / b;
int e = a + b; //强制类型转换,将float类型转换为int类型
float i = a - b;
float j = a % b; //err
return 0;
}
算术操作符%的操作数必须是整数,计算得到的是整除后的余数
编译器报错
3、移位操作符
移位操作符包括左移操作符(<<)和右移操作符(>>)。移位操作符的操作数只能是整数。
移位操作符移动的是内存中的值,也就是移动的是在内存中补码的二进制序列。
3.1左移操作符
左移操作符的规则:左侧丢弃,右侧补0。
int main()
{
int k = 7;
//二进制
//00000000 00000000 00000000 00000111 正数的原码、反码、补码相同
int i = k << 2;
//左移
//00000000 00000000 00000000 00011100 正数的原码、反码、补码相同
printf("%d\n", i);//28
int m = -7;
//二进制
//原码
//10000000 00000000 00000000 00000111
//反码
//11111111 11111111 11111111 11111000
//补码
//11111111 11111111 11111111 11111001
int j = m << 2;
//左移
//11111111 11111111 11111111 11100100 补码
//11111111 11111111 11111111 11100011 反码
//10000000 00000000 00000000 00011100 原码
printf("%d\n", j);//-28
return 0;
}
3.2右移操作符
右移操作符分为算术移位和逻辑右移。
(1)算术移位:右边丢弃,左边补原符号位。
(2)逻辑移位:右边丢弃,左边补0。
对于正数,逻辑移位和算术移位的效果是一样的。
int main()
{
int k = 7;
//二进制
//00000000 00000000 00000000 00000111 正数的原码、反码、补码相同
int i = k >> 2;
//右移
//00000000 00000000 00000000 00000001 正数的原码、反码、补码相同
printf("%d\n", i);//1
int m = -7;
//二进制
//原码
//10000000 00000000 00000000 00000111
//反码
//11111111 11111111 11111111 11111000
//补码
//11111111 11111111 11111111 11111001
int j = m >> 2;
printf("%d\n", j);//-2,大部分编译器均采用算术右移
//算术右移
//11111111 11111111 11111111 11111110 补码
//11111111 11111111 11111111 11111101 反码
//10000000 00000000 00000000 00000010 原码
//逻辑右移
//00111111 11111111 11111111 11111110 补码,符号位为0,原码、反码、补码均相同
//00111111 11111111 11111111 11111110 反码
//00111111 11111111 11111111 11111110 原码
return 0;
}
4、位操作符
位操作符:&(按位与) |(按位或) ^(按位异或)
位操作符均是按二进制位进行操作。
&(按位与):同时为1则为1。
|(按位或):同时为0则为0.
^(按位异或) :相同为0,相异为1。
int main()
{
int a = 7;
//00000000 00000000 00000000 00000111 正数的原码、反码、补码相同
int b = -19;
//10000000 00000000 00000000 00010011 原码
//11111111 11111111 11111111 11101100 反码
//11111111 11111111 11111111 11101101 补码
int k = a & b;
printf("%d\n", k);//5
//00000000 00000000 00000000 00000101 符号位为0,表示正数,原反补码相同
int m = a | b;
//11111111 11111111 11111111 11101111 符号位为1,表示负数,需计算反码,原码
//11111111 11111111 11111111 11101110
//10000000 00000000 00000000 00010001
printf("%d\n", m);//-17
int n = a ^ b;
//11111111 11111111 11111111 11101010 符号位为1,表示负数,需计算反码,原码
//11111111 11111111 11111111 11101001
//10000000 00000000 00000000 00010110
printf("%d\n", n);//-22
return 0;
}
5、赋值操作符
在C语言中,=并不意味着“相等”,而是一个赋值运算符。
复合赋值符:+= -= *= /= %= >>= <<= &= |= ^=
6、单目操作符
单目操作符只有一个操作数。
操作符 | 含义 |
! | 逻辑反操作 |
- | 负 |
+ | 正 |
& | 取地址 |
sizeof | 操作数的类型长度,以字节为单位 |
~ | 取反,对二进制 |
++ | 前置++,后置++ |
-- | 前置--,后置11 |
* | 解引用操作符 |
(1) !逻辑反操作:把真的变为假,把假的变为真
int main()
{
int n = 0;
scanf("%d", &n);
if (!n) //当n为假时,打印hello world,当n为真时,打印world hello
{
printf("hello world\n");
}
else
{
printf("world hello\n");
}
return 0;
}
(2)~按位取反:对一个数的二进制按位取反
7、关系操作符
关系操作符:> < >= <= != ==
注意==和=的区别:==测试是否相等;=是赋值。
字符串比较是否相等,用库函数strcmp,引用头文件<string.h>。
int main()
{
char s1[] = "abc";
char s2[] = "abcdef";
if (s1 == s2)//这里进行比较的只是2个字符串首元素的地址是否相等,而不是比较字符串是否相等
{
printf("hello world\n");
}
else
{
printf("world hello\n");
}
return 0;
}
#include <string.h>
int main()
{
char s1[] = "abc";
char s2[] = "abcdef";
int k = strcmp(s1, s2);
printf("%d\n", k);
if (k == 0)
{
printf("s1和s2相等\n");
}
else if(k > 0)
{
printf("s1比s2长\n");
}
else
{
printf("s1比s2短\n");
}
}
8、逻辑操作符
逻辑操作符:&&(逻辑与) ||(逻辑或)
注意区分逻辑操作符(&&、||)和位操作符(&、|、^)。
逻辑操作符计算结果为1或者0。
int main()
{
int a = 3;
int b = 5;
int m = a && b;//结果为真,m=1
int k = a || b;//结果为真,k=1
printf("m=%d\n", m);
printf("k=%d\n", k);
int c = 0;
int n = a && c;//结果为假,n=0
int p = a || c;//结果为真,p=1
printf("n=%d\n", n);
printf("p=%d\n", p);
return 0;
}
逻辑与表达式:左侧计算只要为假,右边不用计算,整个表达式结果为假。
逻辑或表达式:左侧为真,右边不用计算,整个表达式为真。
int main()
{
int a = 0;
int b = 3;
int c = 5;
int m = a && b && c;
int n = a || b || c;
printf("m=%d n=%d\n", m, n);
return 0;
}
int main()
{
//int i = 0, a = 0, b = 2, c = 3, d = 4;
//i = a++ && ++b && d++;
//printf("a = %d b = %d c = %d d = %d\n", a, b, c, d);
//printf("i=%d\n", i);
int i = 0, a = 1, b = 2, c = 3, d = 4;
i = a++ && ++b && d++;
printf("a = %d b = %d c = %d d = %d\n", a, b, c, d);
printf("i=%d\n", i);
//int i = 0, a = 0, b = 2, c = 3, d = 4;
//i = a++||++b||d++;
//printf("a = %d b = %d c = %d d = %d\n", a, b, c, d);
//printf("i=%d\n", i);
//int i = 0, a = 1, b = 2, c = 3, d = 4;
//i = a++ || ++b || d++;
//printf("a = %d b = %d c = %d d = %d\n", a, b, c, d);
//printf("i=%d\n", i);
return 0;
}
9、条件操作符
条件操作符也称为三目操作符。
表达式1?表达式2:表达式3
exp1 ? exp2 : exp3
从左到右依次计算。
表达式1 | ? | 表达式2 | : | 表达式3 |
真 | √ | |||
假 | √ |
表达式1为真,结果为表达式2;表达式1为假,结果为表达式3。
条件操作符可转换为if else语句。
int main()
{
int a = 3;
int b = 5;
int max = a > b ? a : b;
printf("%d\n", max);
return 0;
}
10、逗号表达式
逗号表达式,就是用逗号隔开的多个表达式。 逗号表达式,从左向右依次执行。整个表达式的结果是最后一个表达式的结果。
int main()
{
int a = 0, b = 0, c = 0, d = 0;
if (a = b + 1, c = a / 2, d = a + b - c, d > 0) //进入if语句的条件由最后一个表达式控制
//但前面的表达式可能会影响最后一个表达式
{
printf("hello world\n");
}
return 0;
}
11、下标引用、函数调用、结构成员
下标引用操作符[]。
[]的操作数为arr和2
arr是数组首元素地址
arr+2是指跳过2个元素指向第3个元素
*(arr+2)就是第3个元素
*(arr+2)=*(2+arr)=2[arr]
int main()
{
int arr[10] = { 0 };
arr[2] = 3; //可改为2[arr]=3;
//[]的操作数为arr和2
//arr是数组首元素地址
//arr+2是指跳过2个元素指向第3个元素
//*(arr+2)就是第3个元素
//*(arr+2)=*(2+arr)=2[arr]
return 0;
}
结构成员:.(点操作符) ->(箭头操作符)
(1) 结构体变量.结构体成员
(2)结构体指针->结构体成员
12、操作符的优先级
复杂表达式的求值有三个影响的因素。
1. 操作符的优先级
2. 操作符的结合性
3. 是否控制求值顺序。
两个相邻的操作符先执行哪个?取决于他们的优先级。如果两者的优先级相同,取决于他们的结合性。