ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

C语言关系运算符详解:六个比较符号、优先级与避坑指南

C语言关系运算符详解:六个比较符号、优先级与避坑指南 C语言零基础入门阶段关系运算符是绕不过去的一个知识点。它们就是用来做比较的、、、!、、这六个符号。很多零基础同学刚写条件判断时最容易翻车的往往不是变量和函数而是这些比较符号有人把写成有人把多个比较连在一起写还有人拿浮点数直接比较。这篇文章不整虚的就围绕“关系运算符是什么、怎么用、怎么避坑”展开用最小示例和排查顺序帮你把手写熟。1. 先明确关系运算符在程序里充当什么角色1.1 关系运算符解决的是“比较”问题关系运算符的官方说法是比较两个值的大小关系或相等关系然后给一个判断结果。这个结果只有两种情况成立或者不成立。C语言里成立的结果是整数1不成立的结果是整数0。这一点和很多高级语言里的true、false不太一样理解它是最重要的一步。举个例子score 60。当score是 75 时这个表达式的结果是1当score是 50 时结果是0。你不用先把它写进if可以直接打印出来验证int score 75; printf(%d\n, score 60); printf(%d\n, score 60);第一行输出 1第二行输出 0。很多零基础同学一开始会奇怪为什么不是输出true或false因为C语言早期没有专门的布尔类型而是用整数 0 表示“假”非 0 表示“真”关系运算符最终返回的是 1 或 0。这个设计到现在还在影响很多C语言代码的写法。1.2 程序里没有关系运算符就没有分支和循环判断成绩是否及格要用if (score 60)。循环从 1 加到 100也要用i 100作为循环继续条件。关系运算符是程序逻辑的“开关”。如果只会printf程序只能从上到下逐行执行完全没有判断能力。但真实程序几乎都有“满足某个条件就做 A否则做 B”的需求或者“只要满足某个条件就重复执行”的需求。这两种结构都离不开关系运算符。所以不建议零基础同学为了学关系运算符而抄定义。真正要掌握的是两件事第一它返回什么值第二它怎么和if、while、for配合控制流程。这两个问题掌握之后你写出来的代码才不是“死代码”。另一个常见误区是把关系运算符当成“一句数学判断”。比如写if (x 0)时脑子里想的是“x 大于 0 这句话是否成立”但程序实际执行时会先把x 0计算成一个整数结果再拿这个结果去做分支判断。简化一点理解关系运算符就像一个小函数输入两个值输出 0 或 1。int r1 5 3; // r1 1 int r2 5 3; // r2 0 int r3 5 ! 3; // r3 1后面看到if (flag)和if (5 3)执行效果一样因为比较结果都是先被计算出来的。这个角度能解释很多后续语法尤其是赋值表达式和条件判断混在一起的情况。2. 六个关系运算符速查与优先级2.1 一张表先把六个符号记牢运算符含义示例条件成立时的结果大于5 31小于5 30大于等于5 51小于等于5 40等于5 51!不等于5 ! 50注意是两个等号不能写成一个。!是一个感叹号加一个等号。记忆方法前四个是大小比较后两个是相等性比较。相等性比较的优先级比大小比较低这个后面会遇到。2.2 优先级和结合性决定表达式怎么算关系运算符不会单独出现它经常和算术运算、赋值运算混在一起。这时候必须知道顺序先算括号。再算算术运算符比如、-、*、/、%。然后算关系运算符。最后算赋值运算符比如、、-。所以a b c * d会先算出a b和c * d再比较大小。flag a b会先算a b再把结果赋给flag相当于flag (a b)。同类关系运算符也有优先级差异。、、、的优先级比、!高。例如a b c实际会被解析成a (b c)而不是(a b) c。这种写法不常见但一旦出现结果会很难猜。结合性方面关系运算符都是从左到右结合。也就是说a b c先算a b得到 0 或 1再拿这个 0 或 1 和c比较。来看一个容易翻车的例子int a 100; int b 10; int c 50; printf(%d\n, a b c);按数学理解100 10 50不成立应该输出 0。但在C语言里a b先得到 0然后执行0 c因为0 50成立所以最终输出 1。这就和直觉完全反了。所以零基础阶段不要写这种“连续比较”。要表达“a 小于 b 且 b 小于 c”应该拆成(a b) (b c)。最好的验证方式是自己多跑几个表达式printf(%d\n, 1 2 3); // 先算 23再比较 15输出0 printf(%d\n, 3 1 1); // 先算 11再比较 32输出1 printf(%d\n, 1 1 0); // 先算 10再判断 11输出1多花五分钟做这种测试比死记优先级表格有效得多。3. if 分支里的关系运算符先跑通最小判断3.1 最小判断程序及格线先看一个最简单的例子#include stdio.h int main() { int score 75; if (score 60) { printf(及格\n); } else { printf(不及格\n); } return 0; }这段代码没有任何输入score固定为 75所以结果一定是“及格”。零基础同学最好先从固定值开始跑跑通之后再改成动态输入int score; printf(请输入成绩); scanf(%d, score); if (score 60) { printf(及格\n); } else { printf(不及格\n); }这里提醒一句scanf里的是取地址符号零基础阶段先照着写后面学到指针就会明白为什么需要它。跑这个例子时可以重点观察边界条件。60 分本身算及格还是不及格如果条件写成if (score 60)60 分算及格如果写成if (score 60)60 分就不及格。这个细节就是“边界”写代码时必须想清楚。3.2 if 条件怎么判断真假C语言的if会检查括号里表达式的结果。结果是非 0 值就执行后面的分支结果是 0就跳过分支。因为关系运算符返回的是 0 或 1所以if (score 60)本质上是在检查score 60这个表达式的结果。成立结果 1进入if分支不成立结果 0走else。我建议在if旁边加一行打印方便观察printf(判断结果%d\n, score 60); if (score 60) { printf(及格\n); } else { printf(不及格\n); }如果判断结果输出 0但你认为应该成立那问题一定在输入、比较符号或变量类型上而不是if语法有问题。还有一点如果if后面没有花括号它默认只控制后面一条语句。新手阶段建议一律写花括号哪怕只有一句。这样后加代码时不容易出错。4. while、do-while、for 里的关系运算符4.1 while 和 do-while 的差别关系运算符在循环里最常见的用法是控制“什么时候继续执行”。int i 1; while (i 5) { printf(%d , i); i; }这段代码输出1 2 3 4 5。循环条件是i 5当i变成 66 5结果为 0循环结束。do-while 版本int i 1; do { printf(%d , i); i; } while (i 5);如果i初始值是 1输出结果一样。但如果i初始值是 6差别就出来了while会先判断6 5结果是 0一次都不执行。do-while会先执行一次循环体再判断条件所以会输出一个 6。这就是while和do-while的核心区别do-while 至少会执行一次。很多课程反复强调这个区别根本原因就在于关系运算符判断的位置不一样。4.2 for 循环里的边界参数for 循环同样依赖关系运算符for (int i 1; i 5; i) { printf(%d , i); }如果条件写成i 5输出就是1 2 3 4少一次。这里有一个非常常见的错误和混用。写循环之前先把次数算清楚从 1 开始i n执行 n 次。从 0 开始i n执行 n 次。从 0 开始i n执行 n1 次。数组下标从 0 开始所以遍历数组时通常用i n。打印从 1 到 n 的编号时通常用i n。不要死记要根据实际下标范围推算。例如声明一个长度为 5 的数组int arr[5] {10, 20, 30, 40, 50}; for (int i 0; i 5; i) { printf(%d , arr[i]); }如果这里写成i 5就会越界访问arr[5]。这个位置不属于数组读出来的值是不可预测的。零基础阶段可能不报错但到后续做文件、指针、项目时会变成很难查的 bug。4.3 循环里应对“关系运算符不生效”的情况我遇到不少同学问明明写了while (i 10)为什么程序死循环了先别怀疑循环语句按这个顺序查查i是否在循环体里被更新。查i的初始值是否比最大值还大。查i的类型是否合适。比如i是整数循环体里却用/或%产生小数最后i一直没变化。查循环条件里是不是误用了。比如int i 1; while (i 10) { printf(%d , i); }这个循环没有ii永远是 1条件永远成立就会死循环。解决方法是循环体里对i做修改。判断关系运算符有没有生效最直接的办法是在循环里打印i和条件结果int i 1; while (i 5) { printf(i%d, 条件结果%d\n, i, i 5); i; }这样你能看见条件从 1 变成 0 的过程。排查这类问题核心是先看变量值而不是改循环结构。5. 零基础最容易踩的 5 个关系运算符的坑5.1写成if (score 60) { printf(及格\n); }这段代码能编译但不会判断score是否等于 60。它做的是把 60 赋值给score然后判断score是不是非 0。因为 60 非 0条件永远成立而且score被改成了 60。正确写法是if (score 60)。如果担心把两个等号写成一个可以把常量放左边if (60 score) { printf(及格\n); }这样如果漏写等号变成if (60 score)编译器会报错因为不能给常量赋值。这种写法可读性稍差但能防止低级错误。5.2 浮点数不要直接用比较double x 0.1 0.2; if (x 0.3) { printf(相等\n); } else { printf(不相等\n); }在某些环境下这段代码会输出“不相等”。原因在于十进制小数转二进制后存在误差0.1 0.2算出来可能是0.30000000000000004和0.3不完全一样。所以浮点数之间很少用或!判断精确相等而是比较两个数相差是否足够小#include math.h double x 0.1 0.2; if (fabs(x - 0.3) 1e-6) { printf(近似相等\n); }1e-6是允许的误差范围具体多大要根据问题精度来定。比较价格、坐标、分数等浮点数时一般都用这种“近似比较”。5.3 字符串不能用直接比较char name[] tom; if (name tom) { printf(相等\n); }看起来像比较内容但name在这里会转换成数组首元素的地址而tom是字符串常量地址。两个地址不一定相同所以条件往往不成立。C语言里比较字符串内容要用strcmp#include string.h char name[] tom; if (strcmp(name, tom) 0) { printf(相等\n); }strcmp返回 0 表示两个字符串相等。零基础阶段先记住这个结论后面学到字符串和指针时再深入理解。5.4 连续比较的坑我前面反复提过a b c的问题。这里再强调一次C语言不支持数学上的连续区间写法。想表达“成绩在 60 到 90 之间”不能写60 score 90要写成if (score 60 score 90) { printf(正常区间\n); }如果用连续写法条件很可能永远为真或判断错误。尤其区间下限和上限离得比较远时结果会非常迷惑。所以看到“A 在某个范围内”这种需求第一反应就该是拆成两个条件再用连接。5.5 多个逻辑运算符混在一起时不加括号条件一多零基础同学容易写if (a 0 b 0 || c 0) { ... }这行代码实际等价于(a 0 b 0) || c 0。你可能本来希望a 0 (b 0 || c 0)两种语义完全不同。零基础阶段不要依赖默认优先级。建议把每个分组都用括号包起来if ((a 0) ((b 0) || (c 0))) { ... }这样写虽然看起来长一点但不会因为优先级记错导致 bug。5.6 如果判断结果不对按这个顺序排查如果程序输出和预期不一致不要急着问别人按下面的链路查一遍先打印变量值确认输入是否被正确读取。再打印关系表达式结果例如printf(%d\n, score 60);。检查比较符号是否写错、、、。检查数据类型整数、浮点数、字符、字符串是否匹配。检查逻辑运算符、||、!用的地方是否加括号。检查边界小于等于和小于的范围是否差一次。这个顺序适合大多数入门阶段的问题。不要一报错就怀疑环境先怀疑条件本身。6. 练习路径怎么把关系运算符练熟6.1 先跑通最小示例再上项目零基础学习C语言最容易出现的情况就是收藏了很多教程但不动手。关系运算符不需要很深的理论哪怕今天只学一个if加也能练习。先准备一个编译环境然后创建test.c把这段代码完整跑一遍#include stdio.h int main() { int a 3; int b 5; printf(a b: %d\n, a b); printf(a b: %d\n, a b); printf(a b: %d\n, a b); printf(a ! b: %d\n, a ! b); printf(a b: %d\n, a b); printf(a b: %d\n, a b); return 0; }输出结果可以自己在纸上先写一遍再和电脑对照。这个练习能快速暴露你是不是真的理解了 0 和 1 的返回规则。6.2 推荐的练手题从小到大逐步来输入两个整数输出较大的那个。输入一个整数判断正数、负数还是零。输入成绩输出优秀90、及格60、不及格60。打印 1 到 100 之间能被 3 整除的数要组合使用%和。猜数字小程序用while循环加关系运算符。冒泡排序用和控制交换。字符串反转、文件读写等工作级语法学完再练。这些题目都离不开关系运算符。练到后面你会发现难点不再是符号怎么写而是边界判断清不清楚。比如“能被 3 整除”是num % 3 0不是num % 3 0打印奇数时i % 2 ! 0比i % 2 1更稳妥因为负数取余时结果可能不是 1。6.3 别把关系运算符和后面的难点混在一起学很多零基础同学会焦虑数组、指针、文件、字符串函数、冒泡排序还没学现在学关系运算符会不会少点什么其实不会。关系运算符属于控制流语法只需要放在变量、输入输出、分支、循环这一层来练。指针里虽然也会出现比较但那是后话。建议的学习顺序是变量类型和printf/scanf。if/else和关系运算符。while、do-while、for。函数、数组。指针、字符串、结构体、文件。在第 2 步把关系运算符练稳第 3 步会轻松很多。循环里最容易出现的死循环、少一次、多一次本质上都是关系运算符边界没控制好。6.4 每周做一次小总结零基础入门阶段不建议追求一天学会所有语法。可以把每类运算符当成一次小实验比如这周只做关系运算符实验下周再并入if再下周并入循环。每做完一个小实验记录一个“我错得最多的地方”。等你积累到十个问题再回头看很多问题其实是同一个原因没有先搞清楚表达式的返回值就开始写分支。关系运算符本身很简单但它和赋值、浮点误差、字符串比较、逻辑组合混在一起时才容易出错。实际写代码时养成一个习惯先把变量值打印出来再把比较结果打印出来最后确认分支走哪边。这个习惯能陪你走完整个C语言学习周期。
返回列表