[C语言初阶]操作符
目录
- 一、算术操作符
- 二、移位操作符(操作数必须为整数)
- 三、位操作符(操作数必须为整数,类比逻辑操作符)
- 3.1 经典面试题:不借助临时变量交换两个值
- 3.2 位操作应用实例
- 四、赋值操作符
- 五、单目操作符
- 六、关系与逻辑操作符
- 七、其他操作符
- 八、表达式求值注意事项
在C语言中,操作符是构成表达式的基本元素,用于对变量和常量进行各种运算操作。掌握操作符的使用对于编写高效、正确的C程序至关重要。下面我们将全面介绍C语言中的各类操作符及其应用场景。
一、算术操作符
算术操作符用于基本的数学运算:
/
:除法操作符- 两端都是整数时,结果为整数(截断小数部分)
- 至少一端为浮点数时,结果为浮点数
%
:取模操作符- 两端必须为整数,返回除法后的余数
int a = 5 / 2; // 结果为2
float b = 5.0 / 2; // 结果为2.5
int c = 5 % 2; // 结果为1
二、移位操作符(操作数必须为整数)
移位操作直接对二进制补码进行操作:
-
左移
<<
:- 二进制位整体向左移动指定位数
- 右侧补0
- 相当于乘以2^n(无溢出时)
-
右移
>>
:- 分为逻辑右移和算术右移
- 逻辑右移:右边向右移一位,左边补0
- 算术右移(常用):右边向右移一位,左边补原符号位(符号位即是最高位,0表正数,1表负数)
- 相当于除以2^n(向下取整)
注意:
- 移位操作不改变原变量值,只影响表达式结果
- 避免移动负数位,这是未定义行为
- 负数移位后需要将补码转换回原码才能得到正确结果
补充:原反补的转化
- 原码:直接写出二进制序列
- 反码:符号位不变,其他位按位取反
- 补码:反码+1(整数在内存中存放的是补码,注意这种原反补的计算只使用于负数,即如果写出的原码最高位是1,则要进行这种计算,而最高位如果是0,则原反补码都相同,左移,右移都是对补码进行操作,但最后如果是负数要转化为原码才是正确的结果)
三、位操作符(操作数必须为整数,类比逻辑操作符)
位操作符直接对二进制补码进行操作:
-
按位与
&
:
-位是二进制位,对应二进制位按位与,规则是对应位只要有0,结果为0,对应位都是1,结果才为1- 应用:清零特定位、取指定位
-
按位或
|
:- 对应位,如果有1,结果为1,两个同时为0,则为0
- 应用:将特定位设为1
-
按位异或
^
:- 对应位相同为0,不同为1
- 特性:
- a ^ a = 0
- a ^ 0 = a
- 应用:交换变量值、加密解密
3.1 经典面试题:不借助临时变量交换两个值
解法一(有溢出风险):
a = a + b;
b = a - b;
a = a - b;
//这种解法好,但有缺陷,如果数字太大,相加会超出上限溢出
解法二(推荐,无溢出风险):
a = a ^ b;
b = a ^ b; // 相当于a^b^b = a
a = a ^ b; // 相当于a^b^a = b
//原理分析:任何两个相同数异或,结果为0,而0与任何数异或,结果还是那个数
//a=a^b,b=a^b,相当于a^b^b,先算b^b,结果为0,所以a^0结果为a,于是就完成了交换
3.2 位操作应用实例
- 统计二进制中1的个数:
解法:按位与+右移操作符
分析:用1来按位与,同时为1时,结果才为1,然后用右移操作符讲要判断的二进制序列向右移1位,1位1位来判断,如果结果是1则自增,从最高位到最低位只用移动31次,用循环来实现
int count_ones(int num) {int count = 0;for(int i=0; i<32; i++) {if(num & (1 << i)) count++;}return count;
}
- 把整数二进制序列中的某一位改为1:
- 解法:按位或+左移操作符
- 分析:用1来按位或,只要有1个为1,就为1,用左移操作符把1移动到要改的那个数的二进制序列的那一位,即可
- 衍生:现在把那一位改为1了,如何改回来呢?
- 解法:按位与+左移操作符+ ~
- 分析:用这个数来和1按位与,左移到那一位,就可以改回来,但是如果这个数字很多1,我们就很难计算这个数是多少,于是我们就可以运用逆向思维,把这个数除符号位不变外,其他位按位取反,记为a,则~a就表示这个数,我们就用这个数来和1进行按位与
四、赋值操作符
-
简单赋值:
=
- 支持连续赋值:
a = b = c
(从右向左计算,先把c赋给b,再把b赋给a) - 但不推荐这种写法,可读性较差
- 支持连续赋值:
-
复合赋值:
+=
,-=
,*=
,/=
,%=
,&=
,|=
,^=
,<<=
,>>=
五、单目操作符
-
sizeof
:- 计算变量/类型所占字节数
- 返回无符号整型,用
%u
打印 - 特点:内部表达式不参与运算
- 若变量s是short类型,a是int类型,计算sizeof(s=a+2),结果还是为2,因为sizeof()内部的表达式不参与运算,不会因为有个int就改变类型,算的还是是s类型的大小
short s; int a; sizeof(s = a + 2); // 结果为2(short类型大小)
-
~
:- 二进制序列按位取反(包括符号位,0变成1,1变成0)
- 应用:在上面讲过的配合位操作修改特定位
-
++
/--
:- 前置:先增减,后使用
- 后置:先使用,后增减
-
&
和*
:&
:取地址操作符*
:解引用操作符- 指针大小:32位系统4字节,64位系统8字节
-
强制类型转换:
(类型)
六、关系与逻辑操作符
-
关系操作符:
>
,<
,>=
,<=
,==
,!=
- 注意:字符串比较不能用
==
,需用strcmp()
- 注意:字符串比较不能用
-
逻辑操作符:
&&
:逻辑与(短路特性:左假则右不算)||
:逻辑或(短路特性:左真则右不算)
-
360笔试题
#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;
}
//程序输出的结果是什么?
- 360笔试题总结:
a && b
:当a为假时,不计算ba || b
:当a为真时,不计算b
七、其他操作符
-
条件操作符(三目):
表达式1 ? 表达式2 : 表达式3
-
逗号操作符:
- 从左到右依次计算表达式
- 整个表达式结果为最后一个表达式的结果
int a = (b=1, c=2, b+c); // a=3
-
下标引用,函数调用,结构成员访问:
- 下标引用:下标引用[]:如arr[4],操作数是两个,arr和4
- 函数调用: ()
- 结构体成员访问
.
:直接访问成员->
:通过指针访问成员,如果创建了结构体指针,则访问可以用->,如结构体指针pb,pb->name表示的是它指向的对象的name
八、表达式求值注意事项
-
隐式类型转换:
- 整型提升:char/short运算时先提升为int
- 算术转换:不同类型运算时向高精度转换
-
操作符优先级:
- 不确定时使用括号明确优先级
- 常见优先级:
()
>单目
>算术
>移位
>关系
>位
>逻辑
>条件
>赋值
>逗号
掌握C语言操作符是编写高效代码的基础。通过本文的学习,相信您已经对C语言操作符有了全面了解。在后续编程实践中,我们可以灵活运用这些操作符解决各种问题。下一篇,我们将介绍指针初阶,敬请期待!
作者其他文章链接:
[C语言初阶]扫雷小游戏
[C语言初阶]三子棋小游戏
Gitee详细使用教程