当前位置: 首页 > java >正文

[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

二、移位操作符(操作数必须为整数)

移位操作直接对二进制补码进行操作:

  1. 左移<<

    • 二进制位整体向左移动指定位数
    • 右侧补0
    • 相当于乘以2^n(无溢出时)
  2. 右移>>

    • 分为逻辑右移和算术右移
    • 逻辑右移:右边向右移一位,左边补0
    • 算术右移(常用):右边向右移一位,左边补原符号位(符号位即是最高位,0表正数,1表负数)
    • 相当于除以2^n(向下取整)

注意

  • 移位操作不改变原变量值,只影响表达式结果
  • 避免移动负数位,这是未定义行为
  • 负数移位后需要将补码转换回原码才能得到正确结果

补充:原反补的转化

  • 原码:直接写出二进制序列
  • 反码:符号位不变,其他位按位取反
  • 补码:反码+1(整数在内存中存放的是补码,注意这种原反补的计算只使用于负数,即如果写出的原码最高位是1,则要进行这种计算,而最高位如果是0,则原反补码都相同,左移,右移都是对补码进行操作,但最后如果是负数要转化为原码才是正确的结果)

三、位操作符(操作数必须为整数,类比逻辑操作符)

位操作符直接对二进制补码进行操作:

  1. 按位与&
    -位是二进制位,对应二进制位按位与,规则是对应位只要有0,结果为0,对应位都是1,结果才为1

    • 应用:清零特定位、取指定位
  2. 按位或|

    • 对应位,如果有1,结果为1,两个同时为0,则为0
    • 应用:将特定位设为1
  3. 按位异或^

    • 对应位相同为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位来判断,如果结果是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按位与,左移到那一位,就可以改回来,但是如果这个数字很多1,我们就很难计算这个数是多少,于是我们就可以运用逆向思维,把这个数除符号位不变外,其他位按位取反,记为a,则~a就表示这个数,我们就用这个数来和1进行按位与

四、赋值操作符

  1. 简单赋值=

    • 支持连续赋值:a = b = c(从右向左计算,先把c赋给b,再把b赋给a)
    • 但不推荐这种写法,可读性较差
  2. 复合赋值+=, -=, *=, /=, %=, &=, |=, ^=, <<=, >>=

五、单目操作符

  1. sizeof

    • 计算变量/类型所占字节数
    • 返回无符号整型,用%u打印
    • 特点:内部表达式不参与运算
      • 若变量s是short类型,a是int类型,计算sizeof(s=a+2),结果还是为2,因为sizeof()内部的表达式不参与运算,不会因为有个int就改变类型,算的还是是s类型的大小
      short s; int a;
      sizeof(s = a + 2); // 结果为2(short类型大小)
      
  2. ~

    • 二进制序列按位取反(包括符号位,0变成1,1变成0)
    • 应用:在上面讲过的配合位操作修改特定位
  3. ++/--

    • 前置:先增减,后使用
    • 后置:先使用,后增减
  4. &*

    • &:取地址操作符
    • *:解引用操作符
    • 指针大小:32位系统4字节,64位系统8字节
  5. 强制类型转换(类型)

六、关系与逻辑操作符

  1. 关系操作符>, <, >=, <=, ==, !=

    • 注意:字符串比较不能用==,需用strcmp()
  2. 逻辑操作符

    • &&:逻辑与(短路特性:左假则右不算)
    • ||:逻辑或(短路特性:左真则右不算)
  3. 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为假时,不计算b
    • a || b:当a为真时,不计算b

七、其他操作符

  1. 条件操作符(三目)表达式1 ? 表达式2 : 表达式3

  2. 逗号操作符

    • 从左到右依次计算表达式
    • 整个表达式结果为最后一个表达式的结果
    int a = (b=1, c=2, b+c); // a=3
    
  3. 下标引用,函数调用,结构成员访问

  • 下标引用:下标引用[]:如arr[4],操作数是两个,arr和4
  • 函数调用: ()
  • 结构体成员访问
    • .:直接访问成员
    • ->:通过指针访问成员,如果创建了结构体指针,则访问可以用->,如结构体指针pb,pb->name表示的是它指向的对象的name

八、表达式求值注意事项

  1. 隐式类型转换

    • 整型提升:char/short运算时先提升为int
    • 算术转换:不同类型运算时向高精度转换
  2. 操作符优先级

    • 不确定时使用括号明确优先级
    • 常见优先级:() > 单目 > 算术 > 移位 > 关系 > > 逻辑 > 条件 > 赋值 > 逗号

在这里插入图片描述

掌握C语言操作符是编写高效代码的基础。通过本文的学习,相信您已经对C语言操作符有了全面了解。在后续编程实践中,我们可以灵活运用这些操作符解决各种问题。下一篇,我们将介绍指针初阶,敬请期待!

作者其他文章链接:
[C语言初阶]扫雷小游戏
[C语言初阶]三子棋小游戏
Gitee详细使用教程

http://www.xdnf.cn/news/14931.html

相关文章:

  • HTML + CSS + JavaScript
  • uniapp+vue3+ts项目:实现小程序文件下载、预览、进度监听(含项目、案例、插件)
  • 奇异值分解(singular value decomposition,SVD)
  • RNN及其变体的概念和案例
  • 【UE5】虚幻引擎的运行逻辑
  • 【数据结构】二叉树
  • 广度优先与深度优先遍历核心逻辑理解及实践
  • qt-C++笔记之setCentralWidget的使用
  • IoTDB:专为物联网场景设计的高性能时序数据库
  • EfficientVMamba: Atrous Selective Scan for Light Weight Visual Mamba论文精读(逐段解析)
  • 跨境ERP系统
  • Java常用加密算法详解与实战代码 - 附可直接运行的测试示例
  • Swift 解 LeetCode 321:拼接两个数组中的最大数,贪心 + 合并全解析
  • 【适合 Java 工程师的 AI 转型方向】
  • 17-C#的socket通信TCP-1
  • 【论文阅读】CogVideoX: Text-to-Video Diffusion Models with An Expert Transformer
  • 2. 两数相加
  • 恒创科技:香港站群服务器做seo站群优化效果如何
  • maven 发布到中央仓库之持续集成-03
  • 解决GitHub仓库推送子文件夹后打不开的问题
  • SpringBoot项目的创建
  • 【ZYNQ Linux开发】BRAM的几种驱动方式
  • 使用协程简化异步资源获取操作
  • 【c++八股文】Day4:右值,右值引用,移动语义
  • 【时时三省】(C语言基础)指针变量作为函数参数
  • Oracle 存储过程、函数与触发器
  • 【牛客刷题】相遇
  • 暑假读书笔记第四天
  • 关于 scrapy框架 详解
  • 二分查找篇——搜索插入位置【LeetCode】三种写法,python2/python3