OI Wiki C 语言基础分支语句if / else if / switch完全指南【免费下载链接】OI-wiki:star2: Wiki of OI / ICPC for everyone. 某大型游戏线上攻略内含炫酷算术魔法项目地址: https://gitcode.com/GitHub_Trending/oi/OI-wiki程序默认按照代码书写顺序从上到下依次执行但现实中往往需要“根据条件决定执行哪些语句、跳过哪些语句”这正是分支branch语句存在的意义。本文是 OI Wiki「语言基础」教程中分支一节的完整展开面向 OI / ICPC 参赛者系统讲解 C 中if、else if与switch三类分支语句的语法、执行语义、常见误区与底层原理并结合本仓库的变量、运算、循环等章节给出可运行的实战示例。读完本文你将能熟练用分支语句写出清晰、高效、不易出错的判分逻辑并理解switch与if链条在实现层面的本质差异。在 mkdocs.yml 的导航结构中分支与循环同属于「流程控制语句」模块位于「C 语法基础」C 语法基础之后是学习函数、数组、结构体等后续内容的前置知识。为什么需要分支程序的选择执行一个程序默认是按照代码的顺序执行下来的。但多数实际任务都包含“如果……否则……”这类选择逻辑例如读入一个数判断其奇偶性根据分数的范围给出不同的评级在搜索与动态规划中根据状态决定转移方向。这些场景都需要有选择性地执行某些语句这就是分支功能存在的意义。选择合适的分支语句如用switch代替冗长的if...else if链还能让代码逻辑更清晰、可读性更高。if 语句if语句是 C 中最基本的分支结构按写法由简到繁可分为三种形式。基本 if 语句if (条件) { 主体; }if语句的执行流程是先对括号内的条件表达式进行求值若结果为真即非 0执行主体语句否则跳过主体继续执行后面的代码。如果主体中只有单条语句花括号可以省略但为了可读性与后续扩展OI Wiki 推荐始终保留花括号if (x 0) cout positive endl; // 单条语句可省略花括号关于“真/假”的判定C 中bool类型取值只有true与false详见变量 - 布尔类型而在条件上下文中任何非 0 值都视为真0 视为假因此if (n)等价于if (n ! 0)。if...else 语句if (条件) { 主体1; } else { 主体2; }if...else与基本if的区别在于else不需要再写条件它捕获“条件不满足”这一剩余情况。条件为真时执行主体 1为假时执行主体 2二者必居其一。同样当某一分支只有一条语句时可以省略花括号。if (x % 2 0) { cout even endl; } else { cout odd endl; }else if 语句if (条件1) { 主体1; } else if (条件2) { 主体2; } else if (条件3) { 主体3; } else { 主体4; }else if是if与else的组合用于对多个条件依次判断并选择不同的执行分支。其执行规则是从上到下依次求值一旦某个条件为真就执行对应主体并结束整个判断链只有当条件 1、条件 2、条件 3 全部为假时才执行末尾else中的主体 4。末尾的else同样不需要写条件。从语法结构上看else if链本质上是“第一个if的else分句中只包含一个if语句并将花括号省略后并排书写”的结果。因此当多个条件相互之间是并列互斥关系时用else if链表达可以让逻辑更清晰且保证了最多只有一个分支被执行。在逻辑上else if链大约相当于下面这段“分段讨论”的叙述——以解一元二次方程时方程的根与判别式的关系为例如果$\Delta0$方程无解否则如果$\Delta0$方程有两个相同的实数解否则方程有两个不相同的实数解。对应的代码实现如下OI 中判定double时通常改用精度比较此处仅为演示结构if (delta 0) { cout 无解 endl; } else if (delta 0) { cout 两个相同的实数解 endl; } else { cout 两个不相同的实数解 endl; }注意delta 0使用的是比较运算符而非赋值运算符二者的区别详见下文“条件表达式的正确写法”。条件表达式的正确写法分支语句的判定质量取决于条件表达式的写法这里结合本仓库的运算章节归纳三个高频注意点。1. 区分与。等于运算符与赋值运算符在判断语句中尤其容易混淆if (op 1) // 错误对 op 赋值赋值为非 0 即为真条件恒成立 if (op 1) // 正确判断 op 的值是否等于 1第一条语句实际是在给op赋值只要赋出的值非 0条件就恒为真完全起不到判断作用第二条才是真正的比较。运算 - 比较运算符一节明确列出了、、、、、!六个比较运算符及其语义。2. 合理组合逻辑运算符。多个条件可以通过逻辑运算符组合逻辑与、||逻辑或、!逻辑非例如if (x 0 x 100)。位运算、|等的优先级低于比较运算符使用时务必用括号明确结合顺序见运算 - 位操作符。3. 三目运算符是if的简写。C 中唯一的三目运算符?:可以看作if语句的简写形式表达式a ? b : c中若a成立则整个表达式取b否则取c。它适合在赋值或返回值时做简单的二选一int mx (a b) ? a : b; // 等价于 if (a b) mx a; else mx b;switch 语句当分支数量较多、且判定条件是“某个整型表达式的取值”时switch语句往往比冗长的else if链更高效、更清晰。基本结构switch (选择句) { case 标签1: 主体1; case 标签2: 主体2; default: 主体3; }执行流程先求出选择句的值然后根据该值匹配对应的case标签从匹配到的标签处开始顺序向下执行。这里有两个硬性约束选择句必须是一个整数类型表达式所有标签都必须是整数类型的常量。int型变量天然满足要求int i 1; // i 的数据类型是整型满足整数类型的表达式的要求 switch (i) { case 1: cout OI WIKI endl; }char类型也属于整数类型因此同样可以作为选择句与标签变量章节提到由于历史原因C 中字符类型会被视作特殊的整型char i A; // i 的数据类型是字符型但 char 也属于整数类型满足整数类型的表达式的要求 switch (i) { case A: cout OI WIKI endl; }注意选择句不能是浮点型或字符串等非整数类型这是switch与if在使用范围上的关键差异。break 与穿透fall-throughswitch语句中必须根据需求加入break语句进行中断否则在对应的case被选择之后接下来的所有case和default中的语句都会被依次执行这一现象称为“穿透”。看下面的示例char i B; switch (i) { case A: cout OI endl; break; case B: cout WIKI endl; default: cout Hello World endl; }以上代码运行后输出的结果为WIKI和Hello World因为case B分支末尾没有break执行完cout WIKI后继续“穿透”到default分支。如果不想让下面分支的语句被运行就需要加breakchar i B; switch (i) { case A: cout OI endl; break; case B: cout WIKI endl; break; default: cout Hello World endl; }以上代码运行后输出的结果为WIKI因为break的存在后面的语句不再执行。最后一个分支如default不需要break因为其下方没有其他语句了不过加上也无害不少选手习惯统一加break以避免后续增删分支时漏写。case 标签的顺序可以任意颠倒各个case包括default的出现次序不影响匹配结果入口编号的顺序并不重要可以任意排列char i B; switch (i) { case B: cout WIKI endl; break; default: cout Hello World endl; break; case A: cout OI endl; }i的值是B因此仍然只会输出WIKI即使case A写在了最后也只有在i A时才会命中它。但需要注意的是case 标签不能重复同一个值不能出现两个case。case 分句中的花括号与变量定义switch的case分句中也可以选择性地加花括号。不过要注意如果需要在switch语句中定义变量花括号是必须要加的否则变量作用域会跨越多个case导致重复定义或初始化问题。例如char i B; switch (i) { case A: { int i 1, j 2; cout OI endl; ans i j; break; } case B: { int qwq 3; cout WIKI endl; ans qwq * qwq; break; } default: { cout Hello World endl; } }用花括号把每个case的主体包成独立的块既允许在分支内定义局部变量也避免了不同分支间变量名互相干扰。如何理解 switch底层是跳转表在原文档的扩展说明中特别指出上文反复使用的“case 分句”“case 子句”等用语本质上只是描述性的说法。在底层实现中switch相当于一组跳转语句——编译器通常会为switch生成一张跳转表jump table依据选择句的值直接跳转到对应分支而不是像else if链那样逐个比较条件。这也是switch在分支数较多、值域连续时通常更高效的原因。也正因为switch本质是跳转才会出现Duffs Device达夫设备这类利用“case 标签可以出现在循环体内部”的奇技淫巧——它将循环展开与 switch 的穿透特性结合在旧式编译器上用于优化数据传输。这类写法可读性差、依赖未定义行为OI 与工程实践中都不推荐使用感兴趣的读者可以自行查阅学习。分支与循环的配合分支语句极少单独出现它经常与循环语句配合完成“选择性执行”的任务。本仓库循环一节中的 3x1 猜想验证程序就是while循环内嵌if...else的典型例子while (x 1) { if (x % 2 1) { x 3 * x 1; } else { x x / 2; } }此外循环中的break与continue也承担了类似“分支”的控制职责break退出整个循环continue跳过本次循环体的剩余部分。二者与if组合使用可以让“提前终止”“跳过非法状态”等逻辑表达得更加清晰详见循环 - break 与 continue 语句。OI 实战分支语句的选型建议综合原文档与本仓库相关章节给出如下选型建议帮助你在 OI 代码中快速决策两个分支的简单判断优先用if...else若判断结果直接用于赋值可用三目运算符?:简写。多个互斥条件的依次判断用else if链保证“最多命中一个分支”如分数段判级、判别式分类讨论。依据单个整型表达式的取值分发用switch尤其是值域有限且集中如字符命令、枚举状态的场景其跳转表实现通常比等价的else if链更高效。浮点数比较OI 中尽量避免对浮点结果直接使用应改用“差的绝对值小于某个极小量”的精度比较。条件表达式中警惕与混用这是新手最常犯、也最难排查的逻辑错误。分支是 C 流程控制的三大基石顺序、分支、循环之一。熟练掌握if家族与switch的语法细节与实现差异是写出正确、高效 OI 代码的第一步。建议配合本仓库循环与运算两节一并阅读并在 OJ 上通过若干判断类习题巩固理解。【免费下载链接】OI-wiki:star2: Wiki of OI / ICPC for everyone. 某大型游戏线上攻略内含炫酷算术魔法项目地址: https://gitcode.com/GitHub_Trending/oi/OI-wiki创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
