C 语言运算符收尾:条件运算符 ?: 与逗号表达式,以及它们的实战组合
简介以下内容是我学习关于运算符中最刁钻的 ? : 与逗号表达式的内容使用AI agent 包括进阶的实战应用条件表达式与三目运算符把 if 压成一行以及它最阴的那个坑逗号表达式值取最后、其余全丢for 双计数器和变量交换都靠它综合实战登录校验、成绩等级、闰年判断——?: 与 || 的真实写法01 | 条件表达式与三目运算符把 if 压成一行以及它最阴的那个坑/* * * 条件运算符 ?: 与 条件表达式 * 编译: gcc 01_conditional_op.c -o 01_conditional_op.exe * 运行: ./01_conditional_op.exe * */#includestdio.hintmain(void){/* --------------------------------------------------------- * 【1】条件表达式所有条件判断最后都变成一个数字 * * C 语言里没有真正的 true / false它只有 int。 * 关系运算符( !)算出来的结果只有两个值 * 条件成立 - 1 真 * 条件不成立 - 0 假 * 注意结果不是 YES/NO也不是真的字符串。 * --------------------------------------------------------- */printf(5 3 的结果是: %d\n,53);/* 1 */printf(5 3 的结果是: %d\n,53);/* 0 */printf(A B 的结果是: %d\n,AB);/* 0 *//* --------------------------------------------------------- * 【2】真值的规则非 0 即真 * * 这条规则决定了 C 里几乎所有 if 的写法。 * -3 是真-1 是真1 是真0.5 是真浮点数也可以当条件 * 0 是假只有 0 是假 * --------------------------------------------------------- */intscore-10;if(score){printf(score %d, 非 0 - 进入 if 分支\n,score);}else{printf(进入 else 分支\n);}/* --------------------------------------------------------- * 【2.5】条件表达式最经典的坑把 写成了 * * 赋值表达式本身也是一个条件表达式它的值 被赋进去的那个数。 * 所以下面这个代码能正常编译、正常跑只是永远走 if 分支 —— * 而且会把 x 冲成 3。这就是 C 里最著名的一类 bug。 * --------------------------------------------------------- */intcx3,cy7;if(cxcy){/* 危险这是赋值不是比较 */printf(BUG 复现: cx 被改成了 %d\n,cx);/* 永远会打印 */}cx3;/* 复位 */if(cxcy){/* 正确 才是比较 */printf(cx cy 成立\n);}else{printf(cx cy 不成立 (cx%d, cy%d)\n,cx,cy);/* 走这里 */}/* 防御写法把常量写在前面不反直觉编译器也更容易帮你抓到手滑 * 上面那行 if (cx cy) 用 gcc -Wall 编译时编译器会直接给你 * warning: suggest parentheses around assignment used as truth value * 看到这种 warning 请当成 error 处理这是工程上的好习惯 */cx3;if(0(cxcy)){/* cxcy 为 000 成立所以进 if */printf(常量在前: cx cy\n);}else{printf(常量在前: cx ! cy\n);}/* --------------------------------------------------------- * 【3】条件运算符 ?: 是 C 语言【唯一】的三目运算符 * * 语法: 条件 ? 值A : 值B * 读作: 如果条件成立就取 值A否则取 值B * * 它是一个【表达式】不是语句 —— 所以整个三元结构本身有值 * 可以直接赋值、可以参与运算、可以放进参数里。 * --------------------------------------------------------- */inta15;intb8;/* 用法一取两数最大值不用 if 一行搞定 */intmax_ab(ab)?a:b;printf(a %d, b %d, max %d\n,a,b,max_ab);/* 15 *//* 用法二取两数最小值 */intmin_ab(ab)?a:b;printf(min %d\n,min_ab);/* 8 *//* 用法三判断奇偶得到一个字符串 */intn7;printf(%d 是 %s\n,n,(n%20)?偶数:奇数);/* 用法四把条件结果转成 1 / -1这是真实项目里的常见写法 * 比如网络攻防里探测服务返回什么标志位 */intflag(n0)?1:-1;printf(flag %d\n,flag);/* 1 *//* 用法五三元运算符可以【嵌套】但可读性会下降 * 下面这句若 x0 取 -x若 x10 取 10否则取 x */intx-5;intabs_like(x0)?-x:((x10)?10:x);printf(x %d, 嵌套三元结果 %d\n,x,abs_like);/* 5 *//* --------------------------------------------------------- * 【4】【重点】?: 的优先级很低比赋值高但比几乎所有运算都低 * * 下面是新手最常踩的坑。编译器不会报错程序也不会崩 * 只会算出来不是你要的东西 —— 这种 bug 最难查。 * --------------------------------------------------------- */intp10,q20;intr1,r2;/* 先说规则从高到低排 * () [] - . 最高 * ! ~ -- * * / % * - * * * ! * * ^ * * || - 到这里为止都比 ?: 高 * ?: - 条件运算符在这里 * - ... - 赋值比 ?: 低 * , - 逗号最低 * * 也就是说?: 优先级【高于赋值低于一切其他运算】。 *//* 错误示范?: 左边夹了一个赋值 * 编译器怎么理解既然 比 ?: 低 就抓到右边的整个三元 * r1 (q ((p q) ? 1 : 2)); * 执行pq 为假 - 取 2 - q 被赋成 2 - r1 再被赋成 2 * 结果r1 2, q 2 - q 被偷偷改掉了 */r1qpq?1:2;printf(错误示范 r1 %d, 而 q 被改成了 %d\n,r1,q);/* r12, q2 *//* 正确写法加括号让意图一眼可见 * r2 ((q (p q)) ? 1 : 2); * 执行pq 为假 - q 被赋成 0 - 0 为假 - r2 取 2 * 结果r2 2, q 0 * * 【这才是这个坑真正阴的地方】 * 两种写法 r1 和 r2 都等于 2表面上结果一样、程序也没崩 * 差别只在 q 上一个把 q 变成 2一个让 q 变成 0。 * 你要是后面还用 q 做别的事这个 bug 会在几十行之外冒出来。 */p10;q20;/* 复位方便对比 */r2(qpq)?1:2;printf(正确写法 r2 %d, q %d\n,r2,q);/* r22, q0 *//* 【口诀】 * 只要 ?: 的左边或右边夹着赋值先用键盘敲出一对小括号。 * 括号在 C 里不花钱但在 debug 时能省你半天。 *//* --------------------------------------------------------- * 【5】if-else 与 ?: 的区别面试常问实用层面也常问 * --------------------------------------------------------- */intv13,v27;/* 写法 Aif-else值要先声明再赋值。适合逻辑复杂、要分支多的情况 */intres_if;if(v1v2){res_ifv1;}else{res_ifv2;}/* 写法 B三元一行且天然是一个值。适合二选一 */intres_ter(v1v2)?v1:v2;printf(if 版 %d, 三目版 %d\n,res_if,res_ter);/* 都是 7 *//* 结论 * 二选一 - 用 ?:短、就是一个值 * 多分支 / 逻辑复杂 / 每支要做很多事 - 用 if-else if */return0;}**02 | 逗号表达式值取最后、其余全丢for 双计数器和变量交换都靠它**/* * * 逗号表达式 ( , ) * 编译: gcc 02_comma_op.c -o 02_comma_op.exe * 运行: ./02_comma_op.exe * */#includestdio.hintmain(void){/* --------------------------------------------------------- * 【1】逗号表达式的规则 * * 语法: 表达式1 , 表达式2 , 表达式3 * 规则: 从左往右【依次】求值整个表达式的值 最后一个表达式的值 * * 生活类比 * 先做 A再做 B最后交付 C 的结果 —— 整件事的价值取决于 C * A 和 B 只是路上的动作它们的值会被丢掉。 * --------------------------------------------------------- */inti0;intj10;intresult(i,j,ij);/* 拆解 * 1) i - i 变成 1这个值 1 被丢掉 * 2) j - j 变成 11这个值 11 被丢掉 * 3) i j 1 11 12 - 整体的值是 12 */printf(逗号表达式 result %d, 此时 i %d, j %d\n,result,i,j);/* 注意上面这行如果只写 printf(..., i, j, ij) * 参数里的逗号是【分隔符】不是逗号运算符 * printf 会收到 3 个参数而不是 1 个 —— 这是另一个坑见第 5 节。 *//* --------------------------------------------------------- * 【2】经典用途①for 循环里的逗号 * * 你以后一定会见到这种写法 * for (i 0, j 10; i j; i, j--) * 初始化位置和每轮执行的位置都可以是逗号表达式 * 因为 for 的括号里只要求是表达式逗号表达式正好是表达式。 * --------------------------------------------------------- */intk,m;printf(for 逗号用法: );for(k0,m5;km;k,m--){printf([k%d,m%d] ,k,m);}printf(\n);/* 输出: [k0,m5] [k1,m4] [k2,m3] *//* --------------------------------------------------------- * 【3】经典用途②交换两个变量 * * 逗号表达式整体是一个表达式所以它能出现在赋值号右边。 * 约定俗成的写法是: (临时a, ab, b临时) * 整体的值是最后一个 b 的值旧 b此处不用返回值只看副作用。 * --------------------------------------------------------- */ints5,u9,t;(ts,su,ut);printf(逗号式交换: s %d, u %d\n,s,u);/* 9, 5 *//* 【反面教材务必知道】 * 网上偶尔能看到这种炫技写法 * (x, y) (y, x); // 直接编译报错 * 报的是: error: lvalue required as left operand of assignment * 原因逗号表达式的结果不是左值不能被赋值。 * 而且它连 x 和 y 的值都没换纯粹是骗人的写法。 * 结论交换变量老老实实用临时变量 t那 3 行才是标准 C。 *//* 顺便验证逗号表达式可以有可写的最终结果 —— u 确实换成了 5 */printf(交换用到的临时变量 t %d\n,t);/* 5 *//* --------------------------------------------------------- * 【4】经典用途③宏里的技巧性写法 * * 写多了会看到这种宏它把多条语句塞进了一个表达式 * 从而让宏看起来像函数一样有值。注意反斜杠 \ 不能漏。 * * 实际项目里我会警告你能不用就别用。 * 因为宏只是文本替换参数里的 i 会被展开成两次 i是经典 bug。 * --------------------------------------------------------- */#defineSET_AND_RETURN(i,val)(i(val),(val))intq0;intgotSET_AND_RETURN(q,42);printf(宏返回值 %d, q %d\n,got,q);/* 42, 42 *//* --------------------------------------------------------- * 【5】【重点】逗号 vs 分号 vs 函数参数逗号 —— 三个别搞混 * --------------------------------------------------------- *//* (A) 分号语句结束符 * 写 a 1; 表示这条语句结束了整体不是一个值 */intz0;(z1);/* 加括号后它整体是一个表达式值为 1 */z(z2,z3);/* 括号里逗号表达式 23 5分号是语句结束 */printf(z %d\n,z);/* 5 *//* (B) 函数调用里的逗号是【分隔符】不是逗号运算符 */printf(%d 和 %d\n,1,2);/* printf 的原型里逗号在分隔不同的实参 * 只有写成 printf(%d\n, (1, 2)) 时括号里那个才轮到逗号运算符上场 * 整体的值是 2。 */intcomma_val(1,2);/* 先算 1 丢掉再算 2整体 2 */printf(括号里的逗号: %d\n,comma_val);/* 2 *//* (C) 赋值号优先级高于逗号 * b1 1, b2 2 等价于 (b1 1), (b2 2)即两个独立赋值 */intb1,b2;b11,b22;printf(b1 %d, b2 %d\n,b1,b2);/* 1, 2 */return0;}03 | 综合实战登录校验、成绩等级、闰年判断——?: 与 || 的真实写法/* * * 条件运算符 / 条件表达式 / 逗号表达式 —— 实战演练 * 编译: gcc 03_practice.c -o 03_practice.exe * 运行: ./03_practice.exe * * 本文件只用到你已经学过的东西: int/float 变量、常量、 * 算术与关系与逻辑运算符、if、for、printf。 * 没有指针、没有数组、没有自定义函数。 * */#includestdio.hintmain(void){/* * 【实战1】模拟登录校验 —— 逻辑运算符 条件表达式 * * 这是最常见的组合 表示并且|| 表示或者。 * 短路特性 左边为假右边【根本不执行】。 * 这点在安全领域很关键比如校验前先确认指针非空。 * */intinput_flag1337;/* 模拟用户提交的 flag */intis_admin1;/* 模拟账号状态 *//* 判断条件本身就是一个值成立为 1不成立为 0 */intpassed(input_flag1337)is_admin;printf([1] flag 校验: %s (passed %d)\n,passed?通过:拒绝,passed);/* 三元运算符直接生成一句人类可读的提示语 —— 这就是它最大的用处 */printf([1] %s\n,passed?欢迎回来flag 正确:flag 错误请再试一次);/* 实战里常见多个条件失败时先报最严重的那个。 * 注意这里 比 || 优先所以 被绑得更紧 * 括号加上更保险加上括号时永远不要偷懒。 */intexpired0;intwrong1;constchar*msg;/* 指向字符串的指针你还没学到先看用法 *//* 它就是存一句话的那种变量%s 负责打印 */msg(expired1wrong1)?账号已冻结且密码错误:(expired1)?账号已过期:(wrong1)?密码错误:全部正常;printf([1] 状态: %s\n,msg);/* * 【实战2】不写 if三行代码求出三个数的最大值、最小值、中间值 * * 思路abc 减去最大值和最小值剩下的就是中间值。 * */inta37,b12,c68;intmax3,min3,mid3;max3(ab)?((ac)?a:c):((bc)?b:c);min3(ab)?((ac)?a:c):((bc)?b:c);mid3abc-max3-min3;printf([2] a%d b%d c%d - max%d mid%d min%d\n,a,b,c,max3,mid3,min3);/* 68, 37, 12 *//* * 【实战3】成绩等级 —— 嵌套三目的经典写法 * * 从高分往低分依次判断命中即返回。 * 超过 3 层嵌套就该换成 if-else if 了可读性会明显变差。 * */intscore83;constchar*grade(score90)?A:(score80)?B:(score70)?C:(score60)?D:F;printf([3] 成绩 %d - 等级 %s\n,score,grade);/* B *//* * 【实战4】闰年判断 —— 和 || 的标准搭配 * * 规则能被 400 整除 - 是否则能被 4 整除且不能被 100 整除 - 是。 * */intyear2024;intis_leap(year%4000)||(year%40year%100!0);printf([4] %d 年是闰年吗? %s\n,year,is_leap?是:否);/* * 【实战5】逗号表达式实战①for 里的双计数器 * * 两个变量同时向前跑这在后面做双指针、模拟队列时会经常遇到。 * */inti,j;printf([5] );for(i0,j10;ij;i,j--){printf((%d,%d) ,i,j);}printf(\n);/* 输出: (0,10) (1,9) (2,8) (3,7) (4,6) *//* * 【实战6】逗号表达式实战②一次算出和与个数 * * 典型场景遍历过程中要同时累计总数和最大值的场景 * 都可以靠逗号表达式把几件事塞进一个表达式。 * */intp4,q9,sum0;/* 两个操作数 累加器 */sum(ppq,pq);/* p13 被丢掉整体值 139 22 */printf([6] p%d q%d, sum%d\n,p,q,sum);/* * 【实战7】三目 逗号把校验并取值写成一行的实战写法 * * 前提值合法就取合法值否则给一个兜底值。 * 这种入口先兜底的写法在解析函数里非常常见。 * */intraw-1;/* -1 表示非法/没读到 */intval(raw0)?raw:-1;printf([7] raw%d - val%d (兜底成功)\n,raw,val);return0;}

相关新闻

开源打字学英语工具实测:单词拼写与文章练习双模式

开源打字学英语工具实测:单词拼写与文章练习双模式

我一直在找一种能真正把单词"用起来"的英语学习方式,而不是对着App一遍遍滑卡片、眼睛看懂了手指却拼不出来。直到我试了这个开源的打字学英语工具,把单词和文章练习结合到一起,用敲键盘的方式逼自己完成拼写和句子的完整输出。这个…

2026/10/12 8:38:54 阅读更多 →
c++草案7.6.2.9 Delete [expr.delete]:基类指针删除派生类对象,基类需要有虚析构函数

c++草案7.6.2.9 Delete [expr.delete]:基类指针删除派生类对象,基类需要有虚析构函数

如果基类没有虚析构函数,则是未定义行为(UB),标准依据是 [expr.delete]/3: 当 delete 的对象的静态类型与其动态类型不同时,静态类型必须是动态类型的基类,且静态类型必须有虚析构函数&#xff…

2026/10/12 8:38:58 阅读更多 →
开车去佘山去爬佘山攻略

开车去佘山去爬佘山攻略

佘山自驾爬山一日攻略(明天出行版)佘山分西佘山(人文看点多:天主教堂、天文台)、东佘山(竹林纯徒步);两座山大门票全部免费,无需预约,上海海拔不到100米&…

2026/10/12 8:39:02 阅读更多 →

最新新闻

软件需求分析报告模板:从需求到验收的文档体系与避坑指南

软件需求分析报告模板:从需求到验收的文档体系与避坑指南

简介:这是一份可直接套用的软件需求分析报告模板PDF,适用于软件工程课程设计、项目文档编写以及开发团队规范需求阶段输出。文档覆盖范围、总体要求、需求分析、概要设计和详细设计等核心章节,并明确各环节的编制者、评审流程与格式要求&…

2026/10/12 9:57:46 阅读更多 →
AI日报制作全流程:从信息筛选到知识库沉淀的实战指南

AI日报制作全流程:从信息筛选到知识库沉淀的实战指南

1. 一份“AI日报”到底在记录什么每天早上打开信息流,满屏都是“某模型又刷新了榜单”“某工具又上线了新功能”“某团队用AI把效率提升了多少倍”。信息量大到让人麻木,但真正能沉淀下来、对实际工作有指导意义的内容少之又少。我做了三年多的AI领域内容…

2026/10/12 9:57:46 阅读更多 →
用LM Studio与Firefox扩展打造本地大模型聊天助手

用LM Studio与Firefox扩展打造本地大模型聊天助手

本地跑大模型这事儿,最尴尬的从来不是模型跑不起来,而是它跟日常操作隔着一层。模型在独立的对话框里开聊了,你想让它看看当前网页某段话,得先把文字复制出去、切窗口、粘贴、问完再切回来,来回几次耐心就没了。我最近…

2026/10/12 9:57:46 阅读更多 →
Spring AI Alibaba停更?Java AI应用开发实战指南

Spring AI Alibaba停更?Java AI应用开发实战指南

1. 一个框架停更引发的技术选型焦虑前几天在一个技术交流群里,有位做Java后端的兄弟抛出一个问题:“Spring AI Alibaba是不是停更了?那Java搞AI是不是没戏了?”群里瞬间热闹起来,有人附和说Java在AI领域确实不行&#…

2026/10/12 9:57:46 阅读更多 →
Fork Git GUI 实战:仓库克隆、分支管理与合并冲突全解析

Fork Git GUI 实战:仓库克隆、分支管理与合并冲突全解析

简介:这份PDF教程面向Git初学者与需要可视化版本控制的开发者,系统讲解Fork这款Git GUI工具的核心操作。内容围绕仓库克隆、文件提交、文件修改与分支合并四大模块展开,从File菜单克隆远程仓库、粘贴GitLab URL并设置本地路径,到在…

2026/10/12 9:57:46 阅读更多 →
AI日报自动化工作流:从信息筛选到分发的完整实践指南

AI日报自动化工作流:从信息筛选到分发的完整实践指南

1. 一份“AI 日报”到底在记录什么 每天早上九点,我的工作流里第一件事不是打开邮箱,而是把过去二十四小时里散落在各个信息源里的AI动态过一遍。这件事我从两年前开始做,最初只是给自己看,后来团队里几个人也要,再后来…

2026/10/12 9:56:45 阅读更多 →

日新闻

复古胶片颗粒感噪点合成器:Canvas ImageData 像素高斯杂色注入算法

复古胶片颗粒感噪点合成器:Canvas ImageData 像素高斯杂色注入算法

在数码相机、高清显示屏与现代矢量图形技术高度发达的今天,画面可以做到绝对的锐利、平滑与无瑕。然而,当一张秋日手账插画或拍立得照片过于“平整无瑕”时,往往会散发出一种冰冷生硬的“数码塑料感(Digital Plasticity&#xff0…

2026/10/12 0:00:59 阅读更多 →
活字印刷古籍线装排版:Canvas 竖排文字与栏线自适应算法

活字印刷古籍线装排版:Canvas 竖排文字与栏线自适应算法

在现代网页与移动端设计中,横排(Horizontal Layout)早已经成为了绝对的主流。然而,当我们翻开泛黄的线装古籍、宋版木刻诗集,或是欣赏一张茶道雅集的手写便签时,那种**自上而下纵向书写、自右向左逐列铺展&…

2026/10/12 0:00:59 阅读更多 →
周日晚间的“精神松绑减震器”:无压力情绪倾倒箱与温和轻声陪伴

周日晚间的“精神松绑减震器”:无压力情绪倾倒箱与温和轻声陪伴

每到周日的晚上八点到十点,很多人心里都会悄悄亮起一盏警示灯。 在心理学上,这种现象有一个专门的称谓——“周日夜晚焦虑症(Sunday Scaries)”。明天又是周一,闹钟又要重新在七点响彻卧房;脑海里仿佛有一个…

2026/10/12 0:00:59 阅读更多 →

周新闻

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

简介:基于 ARIMA、LSTM、Transformer 等模型的流感时间序列预测 Python 源码,面向计算机相关专业课程设计与期末大作业学生,以及项目实战学习者。内容覆盖预处理、平稳性检验、定阶、残差分析、多模型对比预测的完整时序建模流程,…

2026/10/12 0:16:30 阅读更多 →
影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别 做影刀RPA自动化,十个新手有八个栽在"往输入框里填东西"这件事上:要么填不进去,要么填了一半,要么直接把原来内容追加在后面。这背后的根因&…

2026/10/12 0:16:38 阅读更多 →
影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容 1. 认识影刀:什么场景该用RPA采小说数据 起点中文网的页面结构相对稳定——分类榜单、书籍详情、章节内容三块独立页面,跳转链路清晰。这种场景非常适合影刀自动化&#x…

2026/10/12 0:16:43 阅读更多 →

月新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/11 10:45:37 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/11 14:36:53 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/11 14:36:54 阅读更多 →