操作符核心知识点梳理一、核心定位操作符是编程的 “基础工具”贯穿变量运算、逻辑判断、代码简化、内存访问的全过程本次复习重点是理清分类、吃透用法、掌握底层逻辑、规避常踩坑点。回顾编程知识点时发现自身对不少操作符的用法仍有混淆尤其是位操作、移位操作的底层逻辑掌握不扎实还有操作符优先级、表达式求值经常出错因此特意梳理这份复习笔记吃透二进制及位操作相关底层知识掌握操作符属性及表达式求值规则为后续编程实战表达式编写、bug 排查、底层优化筑牢基础也方便后续快速回顾。结合自身复习节奏全文按基础铺垫→分类梳理→重点突破→底层逻辑→属性与求值→坑点避坑→实战复盘展开覆盖 11 个核心要点兼顾基础与难点以复习视角记录梳理过程和易错点适合需要系统复习操作符的小伙伴参考。二、基础铺垫2.1 二进制和进制转换核心基础计算机底层是以二进制0、1存储数据的所有操作符对数据的运算本质都是对二进制位的操作 —— 这是理解移位、位操作符的前提需重点牢记。重点进制转换主要梳理十进制与二进制整数 小数简要梳理、二进制与十六进制的转换方法其中十六进制主要用于简化二进制书写在后续位操作场景中高频使用是重点记忆内容。复习技巧无需死记复杂推导重点牢记十进制转二进制除 2 取余、二进制转十进制按位加权求和结合 1-2 个简单示例辅助记忆比如将十进制 5 转为二进制反复练 2 遍即可熟练掌握。二进制转化成十进制二进制1 0 1 1 十进制1*2^3 0*2^2 1*2^1 1*2^0 11十进制转化为二进制十进制15 → 除 2 取余得二进制01111→ 简化为1111去除高位无意义 0。二进制转八进制二进制每三位对应一位八进制原因是八进制基数 8 是二进制基数 2 的 3 次方82³3 位二进制数的取值范围能完整覆盖 1 位八进制数的所有可能二者一一对应转换时直接按位映射即可。示例二进制101 010 111→ 按三位分组直接转换为八进制。二进制转十六进制与转八进制逻辑完全相同核心原因是十六进制基数 16 是二进制基数 2 的 4 次方162⁴。转换规则二进制每四位对应一位十六进制4 位二进制数的所有取值能完整覆盖 1 位十六进制数的全部可能二者一一对应转换时直接按位映射即可。2.2 原码、反码、补码核心用途解决计算机中负数的表示与运算问题移位、位操作符的运算均基于补码进行属于底层关键知识点必须吃透否则位运算易出错。三者定义以整数为例结合理解整理易懂定义方便回顾原码符号位0 正 1 负 数值的二进制绝对值简单直观但无法直接用于负数运算这是反码、补码出现的原因。反码正数反码 原码负数反码 符号位不变数值位按位取反。补码正数补码 原码负数补码 反码 1重点计算机实际存储和运算的是补码所有整数运算都要基于补码分析。易错点负数补码转原码易出错总结两种通用方法可交叉验证补码 - 1 得反码反码按位取反得原码补码直接按位取反 1 得原码。无符号数无符号位每一位都是数值位原码、反码、补码的二进制表示完全相同。三、操作符整体分类核心原则按功能用途分类每个类别明确「核心作用 典型代表 使用场景」拒绝孤立记忆衔接底层基础知识点确保知识串联而非零散记忆。3.1 移位操作符单独分类重点突破薄弱点核心定义操作二进制位将数据的二进制补码位向左 / 向右移动指定位数仅适用于整数浮点数使用会报错运算基于补码进行。核心代表及用法结合示例记忆避免混淆左移左边舍弃右边补 0等价于整数乘以 2 的 n 次方效率高于乘法无符号 / 有符号整数通用该规则。示例代码#include stdio.h int main() { int num 4; int n num 1; // 仅返回移位结果不修改num本身 printf(n %d\n, n); // 输出8 printf(num %d\n, num); // 输出4原值不变 // 若要修改原值写num num 1 或 num 1 return 0; }右移分两种实现主流编译器默认算术右移算术右移主流左边补符号位右边舍弃逻辑右移左边补 0右边舍弃。需注意编译器差异避免结果异常。易错点移位位数不能为负数C 语言标准未定义不同编译器行为不一致有符号数右移的符号位补位规则需牢记否则易出现运算结果异常。建议自行推导int a4二进制 100左移 1 位、int b-4右移 1 位的补码运算过程掌握移位底层逻辑。3.2 位操作符、|、^、~注操作数必须是整数运算基于补码进行。核心定义直接操作数据的二进制补码位仅适用于整数常用于底层优化、进制转换、状态判断等场景。核心代表及用法按位与对应位均为 1结果为 1否则为 0常用用途判断某一位是否为 1、清零指定位。|按位或对应位有一个为 1结果为 1否则为 0常用用途置 1 指定位。^按位异或重点复习操作符对应位不同为 1相同为 0核心特性a^a0、a^0a基于特性可实现交换两个数、翻转指定位。(结尾有重点补充)无临时变量交换两个整数代码#include stdio.h int main() { int a 10; int b 20; a a ^ b; b a ^ b; a a ^ b; printf(a %d b %d\n, a, b); // 输出a20 b10 return 0; }~按位非对应位按位取反0 变 11 变 0注意负数补码取反后符号位会变化运算时需关注符号位。关键区分易混淆位操作符、|与逻辑操作符、||前者操作二进制位后者操作逻辑值比如判断两个数是否都为非 0应使用而非。3.3 单目操作符核心定义只有一个操作数用于对单个数据进行运算易和双目操作符混淆需逐一梳理。核心代表及用法算术类前置 / 后置自增、--前置 / 后置自减、正号可省略、-负号对补码取反 1前置 / 后置自增自减为重点复习内容后续单独深度拆解。逻辑类!逻辑非规则将非 0 值转为 00 转为 1示例!50、!01。取值 / 取地址取地址获取变量内存地址、*取值通过地址获取变量值需结合指针基础理解避免误用。强制转换(类型)将一个数据强制转为指定类型注意浮点数转整数会舍弃小数部分存在精度丢失问题需谨慎使用。sizeof计算变量 / 类型所占内存大小单位字节易混点与strlen区分 ——sizeof计算内存大小strlen计算字符串长度不包含结束符\0。3.4 逗号表达式单独分类明确用法记录易错点核心定义用逗号,连接多个表达式从左到右依次执行整个表达式的结果是最后一个表达式的值。核心特性优先级最低常用于简化代码如 for 循环的初始化 / 更新部分。示例int a1, b2; int c (a, b, ab); // 执行顺序a2→b3→c5最终结果为5易错点易误将前面表达式的结果作为最终结果前面的表达式仅执行不影响最终结果最终结果仅由最后一个表达式决定。3.5 访问类操作符下标 函数调用 结构成员结合实战梳理3.5.1 下标访问[]用于访问数组元素格式数组名[下标]核心知识点本质等价于*(数组名下标)结合指针基础理解数组访问逻辑。易错点下标从 0 开始编译器不检查下标越界运行时易出现异常需注意判断下标范围。3.5.2 函数调用()用于调用函数格式函数名(参数列表)参数列表可为空无参函数但必须保留括号遗漏会导致编译报错。3.5.3 结构成员访问操作符两种形式两种形式易混淆结合示例记忆核心用于访问自定义结构体的成员属性先明确结构体的基础概念结构体基础核心作用把不同类型的变量打包成一个整体解决普通变量只能单独存储单一类型数据的问题比如描述学生学号 int、姓名 char []、成绩 float可将多个不同类型属性整合为 “学生类型”方便管理。定义原因实际编程中描述的事物均为多属性普通变量会让属性相互独立无法体现 “属于同一事物” 的关联结构体可解决该问题。核心定义关键字struct分两步先声明结构体类型告诉编译器自定义类型的结构再定义该类型的变量与int a定义格式一致。结构体完整示例代码#define _CRT_SECURE_NO_WARNINGS #include stdio.h #include string.h // 字符串赋值需用到strcpy函数 // 声明书本结构体用于嵌套 struct Book { // 书本属性 char bname[20]; // 书名 float price; // 价格 }B1; // 声明类型同时定义全局变量B1 // 声明学生结构体嵌套Book结构体 struct MyStruct { // 学生属性 char name[20]; // 名字 short age; // 年龄 char sex[10]; // 性别 char id[20]; // 学号 struct Book b; // 支持嵌套结构体 }A1; // 声明类型同时定义全局变量A1 int main() { // 定义局部结构体变量并整体初始化成员顺序需与声明一致 struct MyStruct A2 { zhangsan,19,男,2025345,{C语言,22.0}}; printf(学生A2的信息\n); printf(A2学生的书本名称%s\n, A2.b.bname); // 嵌套结构体成员访问变量.嵌套结构体.成员 // 给全局结构体变量A1赋值并读取 printf(请输入A1学生信息\n); printf(姓名); scanf(%s, A1.name); // 字符数组直接传名无需 printf(年龄); scanf(%hd, A1.age); // short类型用%hd格式符 printf(性别); scanf(%s, A1.sex); printf(A1的性别%s\n,A1.sex); return 0; }结构体使用关键注意点字符串成员必须用字符数组如char name[20]新手阶段暂不使用char *name涉及指针字符数组赋值不能直接用如A1.name 张三是错误的需用strcpy函数且必须包含头文件#include string.h。结构体成员访问操作符详解.点操作符用于结构体变量访问成员格式结构体变量.成员名示例stu.name、A2.b.price。-箭头操作符用于结构体指针访问成员格式结构体指针-成员名等价于(*结构体指针).成员名示例p-name等价于(*p).namep 为结构体指针。3.6 其他常用操作符补充完善避免遗漏赋值操作符基础赋值、、-、*、/、%、、|、^、、复合赋值等价规则复合赋值 运算 赋值如a b等价于a a b简化代码书写。关系操作符、、、、等于判断、!不等于作用判断大小 / 相等关系返回布尔值0 或非 0用于条件判断易混点判断相等与赋值后续重点梳理。逻辑操作符逻辑与、||逻辑或用于组合条件判断具有短路求值特性可简化代码、避免无效运算后续单独拆解。三元运算符condition ? expr1 : expr2用于简化简单的 if-else 语句规则condition 为真执行 expr1为假执行 expr2示例求两数最大值max a b ? a : b。四、操作符的核心属性重点补充优先级、结合性核心意义优先级和结合性直接决定表达式的运算顺序是表达式求值经常出错的核心原因复习重点是牢记高频优先级 结合性规则避免写错表达式。4.1 优先级定义多个操作符共存于一个表达式时优先级高的先运算类比数学中的 “先乘除后加减”。高频优先级梳理从高到低最高优先级()括号可强制改变运算顺序、[]、-、.访问类操作符技巧不确定运算顺序时加括号即可安全且清晰。核心顺序单目操作符 算术操作符 关系操作符 逻辑操作符 赋值操作符 逗号表达式最低。易错点单目操作符优先级高于算术操作符如!a b先算!a再算加法赋值操作符优先级低于关系操作符如a b c先算bc再将结果赋值给 a。4.2 结合性定义多个优先级相同的操作符共存时结合性决定运算方向从左到右 / 从右到左与优先级共同决定表达式运算顺序缺一不可。高频结合性规则从左到右左结合算术、关系、逻辑、逗号、访问类、大部分双目操作符示例a b c、a b c按从左到右运算。从右到左右结合单目操作符、赋值操作符、三元运算符示例a b c先算bc再算ab、a等价于(a)。实用技巧不确定运算顺序时直接加括号()优先级最高避免依赖优先级和结合性记忆出错这是写代码的通用规范。五、表达式求值核心基于操作符的优先级、结合性结合底层逻辑补码运算分析表达式的执行顺序和结果重点解决 “求值异常” 问题避免逻辑错误。5.1求值的三大依据操作符优先级操作符结合性操作数的求值顺序重点多数操作符未定义操作数求值顺序如a a不同编译器运算结果不同需避免写出此类代码。5.2重点梳理不同类型表达式求值含单目操作符的表达式结合优先级、结合性分析执行顺序示例a b先算a再算加法。含位操作、移位操作的表达式核心步骤 —— 先将操作数转为补码再按位 / 移位规则运算最后转回原码得到结果需结合补码知识分步推导。含逗号、赋值操作的表达式明确逗号表达式 “从左到右执行结果为最后一个表达式的值”牢记赋值操作的右结合特性示例a (b, c, bc)先执行逗号表达式再将结果赋值给 a。5.3关键易错点避免写出 “操作数求值顺序未定义” 的表达式如a a 1、a a此类代码可移植性差不同编译器运行结果不同极易出现 bug。六、重点操作符深度拆解原则聚焦移位、位、单目、访问类等薄弱、易出错的操作符结合底层基础和操作符属性搭配 “用法 示例 易错点”确保吃透核心逻辑。6.1 移位操作符 位操作符深度拆解移位操作符补充负数移位示例如int a-4a1的补码运算过程分步推导补码移位逻辑明确算术右移的符号位补位规则理解原理而非死记结果。位操作符重点拆解^按位异或梳理核心应用场景交换两个数无临时变量翻转指定位实战延伸位操作符的底层优化技巧示例判断奇数用a 1效率高于a % 2 1因位运算是 CPU 直接支持的底层运算速度更快。6.2 单目操作符深度拆解易混淆点突破自增自减/--核心区分 ——前置先运算再使用后置先使用再运算示例int a2; int ba a;不同编译器因操作数求值顺序未定义结果不同避免依赖固定结果写代码。sizeof 与 * 的区别示例int a[5];sizeof(a)为数组总大小5*420 字节int 占 4 字节sizeof(*a)为首元素大小4 字节明确二者计算对象的差异。强制转换演示风险点 —— 精度丢失int a3.14;结果为 3、指针强制转换风险(int*)100;将数值转为指针提醒自己谨慎使用。6.3 结构成员访问操作符拆解贴合实战解决混淆核心示例定义学生结构体分别用结构体变量和结构体指针访问成员验证等价关系p-name≡(*p).namep 为结构体指针。核心规则结构体变量用.结构体指针用 -牢记无混淆。易错点结构体指针访问成员时误用.如p.name会直接编译报错写代码时需反复检查。七、高频坑点 易错点总结核心梳理写代码、复习时经常用错、混淆的点每个坑点搭配 “错误示例 正确用法”结合底层逻辑和操作符属性加深记忆减少 bug。坑点 1混淆位操作符、|与逻辑操作符、||错误示例if(a b)本意判断 a、b 均非 0正确用法if(a b)核心区别前者操作二进制位后者操作逻辑值0 / 非 0。坑点 2移位操作符的误用错误行为移位位数为负数、忽略有符号数右移的符号位补位规则后果不同编译器行为不一致运算结果异常规避移位位数为非负整数有符号数右移牢记算术右移规则。坑点 3原码、反码、补码混淆错误行为用原码直接进行负数运算正确用法所有整数运算移位、位操作、算术运算均基于补码进行规避运算前先将操作数转为补码运算后再转回原码得到结果。坑点 4操作符优先级 / 结合性记忆错误错误示例a b c * d误先算bc解决方案不确定运算顺序时直接加括号安全且清晰。坑点 5单目操作符与双目操作符混用错误示例a b误先算ab再自增规避牢记单目操作符优先级高于算术等双目操作符。坑点 6结构成员访问操作符误用错误示例结构体指针用.p.name、结构体变量用 -stu-name核心规则指针用 -变量用.。坑点 7逗号表达式结果误用错误示例int c (a, b);误将a结果作为 c 的值核心规则逗号表达式结果为最后一个表达式的值此例为b。坑点 8写出操作数求值顺序未定义的表达式错误示例a a、a a 1后果不同编译器结果不同代码可移植性差规避坚决避开此类表达式拆解为多条语句书写。八、复习复盘 实战小练习8.1 核心知识点复盘底层基础二进制转换、原码 / 反码 / 补码是移位、位操作符的核心前提补码运算规则为底层运算基础需牢记。操作符分类掌握移位、位、单目、访问类、逗号表达式的用法能区分易混淆类别快速选择合适的操作符。核心属性优先级、结合性决定表达式运算顺序记住高频规则不确定时加括号。表达式求值掌握求值方法避开未定义求值顺序的陷阱结合底层逻辑分步分析。8.2 简单实战练习练习 1进制转换 补码运算将十进制 - 5 转为二进制补码计算补码左移 1 位、右移 1 位的结果再转回十进制检验补码和移位操作的掌握程度。练习 2位操作符应用用按位异或交换两个整数用按位与判断一个数是否为奇数手写代码检验用法熟悉底层优化技巧。练习 3单目操作符 表达式求值分析int a3; int ba a-- sizeof(a);的结果结合优先级、结合性分步推导。练习 4访问类操作符定义结构体指针用.和-两种方式访问其成员并赋值检验结构成员访问操作符的掌握。练习 5优先级 / 结合性修正表达式int a23*456;的写法明确运算顺序并计算结果。练习 6坑点排查手写一段包含位操作符、结构成员访问、表达式求值陷阱的错误代码找出错误并修正检验高频坑点的掌握。九、总结延伸思考操作符不仅是编程的基础工具其底层逻辑补码、位运算更是后续学习指针、内存优化、底层开发的核心本次复习到位能大幅提升后续编程效率和代码健壮性为更难的知识点学习筑牢基础。如果在操作符复习中也有混淆的知识点、常踩的坑欢迎补充交流分享位操作符、表达式求值的实用技巧互相巩固复习、查漏补缺、共同进步。补充按位异或交换两个数的底层逻辑解析要理解异或交换代码需先掌握异或运算的3 个核心特性交换逻辑的基础异或运算^的核心特性异或运算规则两个二进制位相同结果为 0两个二进制位不同结果为 1简单记同 0 异 1。基于规则推导的 3 个关键特性对任意整数 x、y 都成立自反性x ^ x 0一个数和自己异或结果一定是 0恒等性x ^ 0 x一个数和 0 异或结果还是它自己交换律 / 结合律x ^ y y ^ x、x ^ y ^ z x ^ (y ^ z)异或的运算顺序不影响结果。逐行拆解交换逻辑带变量值推导初始值a 10b 20用A表示初始 a (10)B表示初始 b (20)区分 “原始值” 和 “更新后的值”。第一步a a ^ b执行后a A ^ B10^20b 仍为原始值 B (20)未被修改第二步b a ^ b代入 a 的新值b (A^B) ^ B→ 结合结合律 自反性A ^ (B^B) A ^ 0 A本质将原始 a 的值 (10) 赋给了 b此时 b10Aa10^20A^B第三步a a ^ b代入当前 a 和 ba (A^B) ^ A→ 结合交换律 自反性B ^ (A^A) B ^ 0 B本质将原始 b 的值 (20) 赋给了 a此时 a20Bb10A交换完成。具体数值验证十进制已知10 ^ 20 30、30 ^ 20 10、30 ^ 10 20第一步a 10^20 30→ a30b20第二步b 30^20 10→ a30b10第三步a 30^10 20→ a20b10。异或交换的特点优点无临时变量不需要定义第三个变量如 temp节省少量内存空间运算效率高位运算是 CPU 直接支持的底层运算比普通临时变量交换法速度更快。注意点交换的两个变量必须是不同的内存地址如果 a 和 b 指向同一块内存如数组中交换同一个下标元素、a b执行后变量值会变为 0第一步aa^b就成了x^x0后续步骤均为 0。开发建议实际开发中临时变量交换法tempa;ab;btemp可读性更高无内存地址限制是更通用的方式异或交换法仅适用于追求极致性能的场景。拓展位操作符经典笔试应用n n (n - 1)是二进制位操作的经典技巧核心作用消除数字 n 的二进制补码中「最右侧的那个 1」每执行一次消去一个 1直到 n 变为 0。应用 1统计二进制中 1 的个数方法一基础版就像求一个十位数的方法一样通过不断/10的方法我们不断/2直到余数为0有局限适用于正数#include stdio.h int main() { int a 10; scanf(%d, a); int sum 0; while (a) { if (a % 2 1) { sum ; } a / 2; } printf(Sum: %d\n, sum); return 0; }输入一个正数5101原码等于补码结果为2是正确的如果输入-1呢原码1000 0000 0000 0000 0000 0000 0000 0001最高位 1 是负号其余是数值位反码1111 1111 1111 1111 1111 1111 1111 1110符号位不变数值位取反补码1111 1111 1111 1111 1111 1111 1111 1111反码 1代码在逻辑和实际运行显然都是错误的方法二改进局限版任何一个数1得到二进制最低位然后1是计算机中提取二进制每一位的经典方法核心是通过 1 取二进制最低位、1 右移舍弃最低位循环执行就能从低位到高位依次拿到一个数的所有二进制位不管正数还是负数按补码处理都适用。#define _CRT_SECURE_NO_WARNINGS #include stdio.h //方法二 int main() { int a 0; scanf(%d, a); int count 0; for (int i 0; i 32; i) //考虑负数的情况循环32次 { if (a 1) //if((a 1) 1) { count; } a 1; } printf(Sum: %d\n, count); return 0; }那么这样每次就要循环一遍效率低下方法三效率最高#define _CRT_SECURE_NO_WARNINGS #include stdio.h //方法三n n (n-1) 消去最右侧1循环次数1的个数 int main() { int a 0; scanf(%d, a); int count 0; while (a) { a a (a - 1); // 每次消去最低位的1 count; // 消去一次则计数1 } printf(Sum: %d\n, count); return 0; }应用 2判断一个数是否是 2 的次方数核心原理2 的次方数的二进制补码中仅有 1 个 1若 n 是 2 的次方数则n (n - 1) 0唯一的 1 被消去结果为 0。判断条件if ((n (n - 1)) 0)→ 成立则为 2 的次方数。拓展二进制位置 0 / 置 1 的实现需求将 13 的二进制序列的第 5 位修改为 1再改回 0位序从 0 开始计数。步骤分析13 的 32 位二进制原 / 反 / 补码0000 0000 ... 0000 1101第 5 位置 1需构造掩码B1416二进制0000 0000 ... 0001 0000通过a | B置 1按位或可保留原有位指定位置 1第 5 位改回 0构造掩码~B二进制1111 1111 ... 1110 1111通过a ~B置 0按位与可保留原有位指定位置 0。实现代码#define _CRT_SECURE_NO_WARNINGS #include stdio.h int main() { int a 13; printf(原数为%d\n, a); // 输出13 int b 1 4; // 构造第5位为1的掩码16 a | b; // 第5位置1 printf(第5位修改为1后为%d\n, a); // 输出29 a (~b); // 第5位改回0 printf(第5位改回0后为%d\n, a); // 输出13 return 0; }运行结果本文部分代码Luminous/Luminousbegin - Gitee.com我的代码仓库练习仓库Luminous/Luminousbegin - Gitee.com完......