目录
1.操作符分类
移位操作符,位操作符,赋值操作符,单目操作符,关系操作符,逻辑操作符,条件操作符,逗号表达式,下标引用、函数调用和结构成员
2.算术操作符
+ - * / %
商:3/2=1
余数:9%2=1 //9%2=4...1
1)除了 % 操作符之外,其他的几个操作符可以作用于整数和浮点数。
2)对于 / 操作符如果两个操作数都为整数,执行整数除法。而只要有浮点数执行的就是浮点数除法。
3)% 操作符的两个操作数必须为整数。返回的是整除之后的余数。
3.移位操作符
移动的是二进制位
<< 左移操作符
>> 右移操作符
3.1 <<左移操作符
规则:左边抛弃,右边补0.
3.2 >>右移操作符
规则:
1)逻辑移位:右边抛弃,左边补0.
2)算术移位:右边抛弃,左边用原该值的符号位填充
注:移位操作符的操作数只能是整数
警告:对于移位操作符,不要移动负数位,这个标准是未定义的
eg:
int num=10;
num>>-1;//error
4.位操作符
& //按位与
| //按位或
^ //按位异或
注:它们的操作数必须是整数 (2进制位)
int a=3;
int b=-5;
int c=a&b;
printf("%d",c);//3
int c=a|b; //c=-5
int c=a^b; //c=-8;
分析此代码:
3的补码:000...0011
-5的补码:111...11011
需注意:^异或对应的二进制位:相同为0,相异为1.(a^a=0,a^0=0,单身狗问题)
再举个例子:求一个整数存储在内存中的二进制中1的个数
int main()
{
int n = 0;
scanf("%d", &n);
int count = 0;
// int i = 0;
for (int i = 0; i < 32; i++)
{
if (1 == ((n >> i) & 1))
{
count++;
}
}
printf("%d", count);
return 0;
}
5. 赋值操作符
=
复合赋值符
+= -= *= /= %= >>= <<= &= |= ^=
int x = 10;
x = x+10;
x += 10;//复合赋值
//其他运算符一样的道理。这样写更加简洁
6.单目操作符
6.1单目操作符介绍
! 逻辑反操作
- 负值
+ 正值
& 取地址
sizeof 操作数的类型长度(以字节为单位)
~ 对一个数的二进制按位取反
-- 前置、后置--
++ 前置、后置++
* 间接访问操作符(解引用操作符)
(类型) 强制类型转换
&取地址
int arr[10]={0};
&arr; //取出数组的地址,数组的地址应该放到[数组指针]中去。
* 间接访问操作符(解引用操作符)
int a=10;
int *pa=&a;
*pa=20;
printf("%d",a); //20
*&a==>a
sizeof 操作数的类型长度(以字节为单位)是一个操作符,不是函数。
计算类型创建的变量所占内存的大小,单位是字节
int a=10;
printf("%d",sizeof a); //侧面说明sizeof是一个操作符,非函数
printf("%d",sizeof(a));
printf("%d",sizeof(int));
~ 对一个数的二进制按位取反 包括符号位
scanf()读取失败时,返回EOF
EOF本质--->-1 ~(-1)的反码全为0
故 while( ~scanf("%d",&n) )可以终止循环
++/--(--同++)
int a=3;
printf("%d",++a);//4 //前置++ 先++,后使用
int b=++a;//a=a+1,b=a;
int b=a++;//后置++,先使用,后++,b=a,a=a+1;
(类型)强制类型转换
int a=(int)3.14;
printf("%d",a);//3
7.关系操作符
>
>=
<
<=
!= 用于测试“不相等”
== 用于测试“相等”
注意:在编程的过程中==和= 一个是判断,一个是赋值。
8.逻辑操作符
&& 逻辑与(并且)
|| 逻辑或(或者)
只关心真假
9.条件操作符
exp1 ? exp2 : exp3
if (a > 5)
b = 3;
else
b = -3;
相当于
int b=a>5?3:-3;
10.逗号表达式
exp1, exp2, exp3, …expN
逗号表达式,从左向依次执行,整个表达式的结果是最后一个表达式的结果
int a=1;
int b=2;
int c=(a>b,a=b+10,a,b=a+1); //c=13
a=12 12 b=13
11. 下标引用、函数调用和结构成员
1.[ ] 下标引用操作符
操作数:一个数组名+一个索引值
//arr[4]<===>4[arr]
2.()函数调用操作符 至少1个操作数
接受一个或者多个操作数:第一个操作数是函数名,剩余的操作数就是传递给函数的参数
3. 访问一个结构的成员
. 结构体.成员名
-> 结构体指针->成员名
struct Stu
{
char name[20] ;
int age;
float score;
};
void print1(struct Stu ss)
{
printf("%s %d %f", ss.name,ss.age,ss.score);
}
void print2(struct Stu* ps)
{
printf("%s %d %f", ps->name, ps->age, ps->score);
}
int main()
{
struct Stu s = {"张三", 18, 98.8f};
print1(s);
printf("\n");
print2(&s);
return 0;
}
12.表达式求值
12.1隐式类型转换
C的整型算术运算总是至少以缺省整型类型的精度来进行的
为了获得这个精度,表达式中的字符和短整型操作数在使用之前被转换为普通整型,这种转换称为整型提升
12.2算术转换
寻常算术转换
long double
double
float
unsigned long int
long int
unsigned int
int
如果某个操作数的类型在上面这个列表中排名较低,那么首先要转换为另外一个操作数的类型后执行运算。
12.3 操作符的属性
复杂表达式的求值有三个影响的因素。
1. 操作符的优先级
2. 操作符的结合性
3. 是否控制求值顺序