C++基础(四)——流程控制语句(超详细)

news2026/4/27 3:29:58
家人们好呀前几篇文章里我们先让计算机喊出了“Hello World”又教会了它“记事情”变量和数据类型最后让它学会了“算算术”运算符和表达式。但到目前为止我们写的程序都像一个死板的机器人从上到下一行一行老老实实地执行从不问“为什么”也从来不会“再来一遍”。然而真正的程序远没有这么听话。比如你要写一个登录系统得判断用户输入的密码是否正确——对了就放行错了就提示重试。比如你要计算全班同学的平均分得把每个同学的成绩挨个加一遍——这就是重复做同一件事。再比如你要在一个数组里找一个特定的数字——找到了就停下来别傻乎乎地继续找。这些“根据条件做出选择”、“反复执行某段代码”、“中途跳出循环”的能力在编程里统称为流程控制。如果说变量和运算符是C的“词汇”那么流程控制语句就是C的“语法”——它们决定了程序的执行顺序让计算机真正有了“智能”。这篇文章我们就来系统地学习C的流程控制语句条件判断、循环结构、跳转语句以及一些现代C带来的新玩法。坐稳了我们要让程序开始“思考”了一、流程控制是什么在没有流程控制的情况下程序只会一条路走到黑——从main函数的第一行开始一行一行往下执行直到最后一行然后结束。这种执行方式被称为顺序结构它是最基本的程序执行方式就像你顺着一条笔直的马路走没有任何岔路口也没有回头路。但现实世界的程序需求远比这复杂。你需要· 根据不同的条件走不同的分支“如果密码正确就登录否则提示错误”· 让某段代码反复执行“把全班50个人的成绩累加起来”· 在特定情况下提前跳出“找到了目标数字不用继续找了”于是C提供了三大类流程控制语句1. 选择结构条件判断 if-else、switch2. 循环结构for、while、do-while3. 跳转语句break、continue、goto、return这三种结构组合起来就能让程序像有了大脑一样根据不同的情况做出不同的反应。二、选择结构选择结构的核心作用就是如果某个条件成立就做A否则就做B。这是程序产生“智能感”的第一步。2.1 if-else语句最灵活的条件判断if-else是C中最常用的条件判断结构支持单分支、双分支和多分支嵌套可以实现从简单到复杂的各种条件决策。2.1.1 单分支if最简单的if语句条件成立就执行不成立就跳过。int score 85; if (score 60) { cout 恭喜你及格了 endl; } // 如果score小于60上面那行根本不会执行关键点· 条件表达式的结果只要非0就认为是“真”会执行if后面的代码。· if和else后面不能加分号加了分号意味着语句结束了if就变成了一个空操作。· 如果要执行多条语句必须用花括号{}包起来。2.1.2 if-else双分支int age 17; if (age 18) { cout 成年了可以去网吧了 endl; } else { cout 未成年回家写作业吧 endl; }2.1.3 if-else if-else多分支当需要判断多个条件时可以用else if串联int score 85; if (score 90) { cout 优秀 endl; } else if (score 80) { cout 良好 endl; } else if (score 60) { cout 及格 endl; } else { cout 不及格 endl; }这种结构就像你妈问你考了多少分——90分以上是“我儿子真棒”80分以上是“还行下次努力”60分以上是“你给老子滚过来”60分以下是“”因为二话不说直接拿衣架开始暴揍了。2.1.4 经典陷阱1和傻傻分不清这是新手最高频的错误而且编译器不会报错最多给个警告int a 3; if (a 5) { // 本意是比较却写成了赋值 cout a等于5 endl; // 这句话永远会执行 }为什么永远执行因为a 5是一个赋值表达式它的值是5非0即为真。于是条件永远成立而且a还被意外改成了5。正确写法是if (a 5) { // 两个等号才是比较 cout a等于5 endl; }一个防御性编程技巧把常量写在左边——if (5 a)。如果你不小心写成5 a编译器会直接报错帮你发现问题。2.1.5 经典陷阱2悬垂elseif (a 1) if (b 2) cout hehe; else cout haha; // 这个else匹配的是哪个ifC规定else匹配离它最近的、尚未匹配的if。所以上面的else属于内层的if (b 2)而不是外层的if (a 1)。当a ! 1时整个内层if包括else都不会执行什么也不输出。解决办法用花括号明确作用域if (a 1) { if (b 2) { cout hehe; } } else { cout haha; // 现在明确属于外层if }别依赖缩进缩进只是给人看的编译器根本不理你。花括号才是逻辑清晰的“第一道防线”。2.1.6 C17新特性带初始化的if语句C17允许在if语句中直接声明并初始化一个变量这个变量的作用域仅限于if语句内部// 传统写法 int result compute(); if (result 0) { // 使用result } // C17写法 if (int result compute(); result 0) { // result只在这个if块内有效 }这个特性可以限制临时变量的作用域让代码更干净。2.2 switch语句高效的多分支选择当你需要根据一个整型变量或能转成整型的变量的多个可能值执行不同操作时switch语句会比一串else if更清晰、更高效。int day 3; switch (day) { case 1: cout 星期一痛苦的开始 endl; break; case 2: cout 星期二继续煎熬 endl; break; case 3: cout 星期三看到希望了 endl; break; case 4: cout 星期四再忍忍 endl; break; case 5: cout 星期五准备解放 endl; break; case 6: case 7: cout 周末睡到自然醒 endl; break; default: cout 一周只有7天你输入的是啥 endl; }switch的要点1. switch后面的表达式必须是整型、字符型或枚举类型不能是浮点数或字符串。2. case后面必须是常量表达式。3. 每个case结尾一般都要加break否则会发生“穿透”——继续执行下一个case的代码。4. default是可选的用来处理所有未匹配到的情况。2.2.1 穿透fall-through的妙用虽然大多数时候break是必须的但有时“故意不写break”可以实现多个case共享同一段代码switch (month) { case 1: case 3: case 5: case 7: case 8: case 10: case 12: cout 这个月有31天 endl; break; case 4: case 6: case 9: case 11: cout 这个月有30天 endl; break; case 2: cout 这个月有28或29天 endl; break; }如果刻意使用穿透建议加上注释说明免得别人或三个月后的你自己以为你忘了写break而“好心”帮你加上结果逻辑全乱。2.2.2 switch vs if-else什么时候用哪个判断一个变量是否等于几个离散的常量switch更清晰、可读性更好判断范围条件如大于、小于if-else条件复杂涉及多个变量if-else性能敏感的场景分支很多时switch某些编译器会生成跳转表更快switch语句在底层实现中编译器可能会生成一张“跳转表”jump table使得无论有多少个case查找时间复杂度都是O(1)而if-else链的最坏情况是O(n)。三、循环结构让程序学会“重复劳动”计算机最擅长的事情就是不厌其烦地重复做同一件事。人类算100个数的和会觉得无聊但计算机会毫不犹豫地帮你算完——这就是循环的价值。C提供了三种循环结构for、while和do-while。三者的核心区别在于循环条件的初始化方式和判断时机。3.1 for循环已知次数的重复当你明确知道要循环多少次时for是最佳选择。比如“遍历数组的前10个元素”、“计算1到100的和”。for (初始化; 条件; 更新) { // 循环体 }执行流程初始化只做一次→ 判断条件 → 条件为真则执行循环体 → 执行更新 → 判断条件 → … → 条件为假则退出。经典示例计算1到100的和int sum 0; for (int i 1; i 100; i) { sum i; } cout 1到100的和是 sum endl; // 输出5050灵活用法· 三个表达式都可以省略但分号必须保留int i 0; for (; i 10; i) { /* 省略初始化 */ } for (int i 0; i 10;) { i; /* 省略更新在循环体内做 */ } for (;;) { /* 无限循环需用break退出 */ } // 传说中的“死循环”· 可以同时控制多个变量for (int i 1, j 5; i 5; i, --j) { cout i j i j endl; }3.1.1 C11范围for循环遍历容器的神器C11引入的范围for循环range-based for loop让遍历数组、vector等容器变得极其简洁int arr[] {10, 20, 30, 40, 50}; for (int x : arr) { cout x ; } // 输出10 20 30 40 50如果你需要修改容器中的元素可以使用引用vectorint nums {1, 2, 3, 4, 5}; for (int x : nums) { x * 2; // 每个元素翻倍 }能用范围for的地方尽量用范围for。它不仅代码更短还能避免“下标越界”这种经典Bug。3.2 while循环依赖条件的重复当你不知道要循环多少次只知道“只要某个条件成立就一直循环”时用while最合适。while (条件) { // 循环体 }执行流程先判断条件 → 条件为真则执行循环体 → 执行完再判断条件 → … → 条件为假则退出。如果条件一开始就是假循环体一次都不会执行。经典示例猜数字游戏int secret 42; int guess 0; while (guess ! secret) { cout 猜一个数字; //输入一个数并保存在guess中下一章会讲到 cin guess; if (guess secret) { cout 太大了 endl; } else if (guess secret) { cout 太小了 endl; } } cout 恭喜你猜对了 endl;3.3 do-while循环至少做一次再说do-while和while几乎一样只有一个关键区别它先执行循环体再判断条件。这意味着无论条件是否成立循环体至少会执行一次。do { // 循环体 } while (条件); // 注意这里有分号典型场景菜单选择界面int choice; do { cout 菜单 endl; cout 1. 开始游戏 endl; cout 2. 设置 endl; cout 3. 退出 endl; cout 请选择; cin choice; switch (choice) { case 1: cout 游戏开始 endl; break; case 2: cout 进入设置... endl; break; case 3: cout 再见 endl; break; default: cout 无效选择请重新输入 endl; } } while (choice ! 3);3.4 三种循环怎么选知道具体要循环多少次for或范围for循环次数未知依赖条件可能一次都不执行while循环次数未知但至少需要执行一次do-while遍历数组/容器范围for最推荐3.5 循环的嵌套循环里面还可以套循环这叫做嵌套循环。最经典的例子就是打印乘法口诀表for (int i 1; i 9; i) { for (int j 1; j i; j) { cout j × i i * j \t; } cout endl; }注意事项· 内层循环的变量名不要和外层循环的变量名冲突比如都用i。· 嵌套层数不宜过多一般不超过3层否则代码可读性会急剧下降。四、跳转语句不走寻常路有时候正常循环流程无法满足需求——比如你想在找到目标后立即退出循环或者想跳过某次循环的剩余部分直接开始下一次。这时候跳转语句就派上用场了。C提供了四种跳转语句break、continue、goto和return。4.1 break立即退出break用于立即退出所在的循环或switch语句继续执行循环/switch之后的代码。// 在一个数组中查找目标值找到就退出 vectorint nums {4, 7, 2, 9, 5, 1}; int target 9; int index -1; for (size_t i 0; i nums.size(); i) { if (nums[i] target) { index i; break; // 找到了不用继续找了 } }注意break只能跳出最内层的循环或switch。如果有多层嵌套需要逐层判断或者用其他方法。4.2 continue跳过本次继续下一次continue用于跳过当前循环迭代的剩余部分立即开始下一次迭代。// 只输出奇数 for (int i 1; i 10; i) { if (i % 2 0) { continue; // 偶数就跳过不输出 } cout i ; } // 输出1 3 5 7 9注意continue不能直接用在switch中除非switch在循环内部。4.3 goto禁忌之术goto可以无条件跳转到同一函数内的带标签位置。它的名声很差被很多编程教材列为“禁止使用”的语句因为它会破坏结构化编程让代码变成一团乱麻——“意大利面条式代码”。但goto并非完全没有用武之地。在跳出多重嵌套循环时goto有时是最简洁的解决方案for (int i 0; i 10; i) { for (int j 0; j 10; j) { if (i * j 50) { goto end; // 直接跳出两层循环 } } } end: cout 跳出循环 endl;goto就像“核武器”——威力巨大但大多数时候你最好假装它不存在。除非你确定没有更好的办法并且准备好在代码审查时接受同事的“灵魂拷问”。重要提醒goto不能跳过变量的初始化否则会编译错误goto label; int x 10; // 错误跳过了x的初始化 label: cout x;4.4 return函数到此为止return用于从当前函数返回并将控制权交还给调用者。· 在void函数中return可以不带值或者省略函数末尾会自动返回。· 在非void函数中必须返回一个与函数返回类型兼容的值。int max(int a, int b) { if (a b) { return a; } else { return b; } // 这里永远不会执行到 }在main函数中return 0表示程序正常退出。如果你忘记写C会自动帮你加上但养成写的习惯更好。五、现代C流程控制新特性C17到C26C并不是一门故步自封的语言它的流程控制机制也在不断进化。以下几个新特性虽然新手暂时不一定用得上但了解它们能让你对C的未来充满期待。5.1 C17if constexpr——编译期if普通if的条件在运行时判断而if constexpr的条件在编译期判断。这意味着不满足条件的分支根本不会被编译从而避免了模板编程中的很多编译错误。templatetypename T void print_value(T t) { if constexpr (std::is_pointer_vT) { // 如果T是指针类型才编译这个分支 std::cout *t \n; } else { // 如果T不是指针只编译这个分支 std::cout t \n; } }if constexpr让模板元编程从“魔法”变成了正常的代码逻辑是C17最受欢迎的特性之一。5.2 C20概念ConceptsC20引入的概念Concepts虽然不是直接的流程控制语句但它配合if constexpr可以实现更强大的编译期条件判断。5.3 C26契约编程ContractsC26引入了pre前置条件、post后置条件和contract_assert让函数的前置和后置条件检查成为语言的一部分。虽然在调试模式下影响控制流但它们是保证代码正确性的重要工具。六、最佳实践总结1. if/else/for/while后面永远加花括号{}——即使只有一条语句。这能避免无数低级Bug。2. 比较时把常量放左边——if (5 a)防赋值。3. 能用范围for就别用普通for——更简洁更安全。4. switch的default不要省略——处理意外情况。5. 尽量避免goto——除非跳出多重嵌套循环且没有更好的办法。6. 循环变量不要在循环体内修改——除了正常的更新表达式不要在循环体内随意修改循环变量否则容易导致逻辑混乱。七、动手实践打开你的Visual Studio把下面的代码复制进去运行看看输出是什么#include iostream #include vector using namespace std; int main() { cout 条件判断演示 endl; int score 85; if (score 90) { cout 优秀 endl; } else if (score 80) { cout 良好 endl; } else { cout 继续努力 endl; } cout \n switch演示 endl; int day 3; switch (day) { case 1: cout 星期一 endl; break; case 2: cout 星期二 endl; break; case 3: cout 星期三 endl; break; default: cout 其他 endl; } cout \n for循环演示 endl; int sum 0; for (int i 1; i 10; i) { sum i; } cout 1到10的和 sum endl; cout \n 范围for演示 endl; vectorint nums {10, 20, 30, 40}; for (int x : nums) { cout x ; } cout endl; cout \n while循环演示 endl; int count 0; while (count 5) { cout count ; count; } cout endl; cout \n break演示 endl; for (int i 1; i 10; i) { if (i 5) break; cout i ; } cout (在5处停止了) endl; cout \n continue演示 endl; for (int i 1; i 10; i) { if (i % 2 0) continue; cout i ; } cout (只输出奇数) endl; system(pause); return 0; }改改里面的数字和条件试试不同的组合观察输出变化。编程这件事光看不练是永远学不会的。八、总结恭喜你现在你已经掌握了让C思考的核心技能。快速回顾· 选择结构if-else最灵活、switch多分支整型判断· 循环结构for已知次数、while依赖条件、do-while至少一次、范围for遍历容器· 跳转语句break退出循环/switch、continue跳过本次、goto少用为妙、return返回函数· 现代特性if constexprC17编译期if、if带初始化C17思考题看看你学会了没1. 以下代码会输出什么int x 10; if (x 5) { cout A; } else { cout B; }2. switch语句中的break有什么作用如果忘记写会发生什么3. while循环和do-while循环的根本区别是什么4. 什么时候应该用continue而不是break下一篇文章我们将系统地学习C的输入输出。谢谢大家—— 一个曾因为少写一个break而debug到凌晨三点的C学习者

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2547943.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

SpringBoot-17-MyBatis动态SQL标签之常用标签

文章目录 1 代码1.1 实体User.java1.2 接口UserMapper.java1.3 映射UserMapper.xml1.3.1 标签if1.3.2 标签if和where1.3.3 标签choose和when和otherwise1.4 UserController.java2 常用动态SQL标签2.1 标签set2.1.1 UserMapper.java2.1.2 UserMapper.xml2.1.3 UserController.ja…

wordpress后台更新后 前端没变化的解决方法

使用siteground主机的wordpress网站,会出现更新了网站内容和修改了php模板文件、js文件、css文件、图片文件后,网站没有变化的情况。 不熟悉siteground主机的新手,遇到这个问题,就很抓狂,明明是哪都没操作错误&#x…

网络编程(Modbus进阶)

思维导图 Modbus RTU(先学一点理论) 概念 Modbus RTU 是工业自动化领域 最广泛应用的串行通信协议,由 Modicon 公司(现施耐德电气)于 1979 年推出。它以 高效率、强健性、易实现的特点成为工业控制系统的通信标准。 包…

UE5 学习系列(二)用户操作界面及介绍

这篇博客是 UE5 学习系列博客的第二篇,在第一篇的基础上展开这篇内容。博客参考的 B 站视频资料和第一篇的链接如下: 【Note】:如果你已经完成安装等操作,可以只执行第一篇博客中 2. 新建一个空白游戏项目 章节操作,重…

IDEA运行Tomcat出现乱码问题解决汇总

最近正值期末周,有很多同学在写期末Java web作业时,运行tomcat出现乱码问题,经过多次解决与研究,我做了如下整理: 原因: IDEA本身编码与tomcat的编码与Windows编码不同导致,Windows 系统控制台…

利用最小二乘法找圆心和半径

#include <iostream> #include <vector> #include <cmath> #include <Eigen/Dense> // 需安装Eigen库用于矩阵运算 // 定义点结构 struct Point { double x, y; Point(double x_, double y_) : x(x_), y(y_) {} }; // 最小二乘法求圆心和半径 …

使用docker在3台服务器上搭建基于redis 6.x的一主两从三台均是哨兵模式

一、环境及版本说明 如果服务器已经安装了docker,则忽略此步骤,如果没有安装,则可以按照一下方式安装: 1. 在线安装(有互联网环境): 请看我这篇文章 传送阵>> 点我查看 2. 离线安装(内网环境):请看我这篇文章 传送阵>> 点我查看 说明&#xff1a;假设每台服务器已…

XML Group端口详解

在XML数据映射过程中&#xff0c;经常需要对数据进行分组聚合操作。例如&#xff0c;当处理包含多个物料明细的XML文件时&#xff0c;可能需要将相同物料号的明细归为一组&#xff0c;或对相同物料号的数量进行求和计算。传统实现方式通常需要编写脚本代码&#xff0c;增加了开…

LBE-LEX系列工业语音播放器|预警播报器|喇叭蜂鸣器的上位机配置操作说明

LBE-LEX系列工业语音播放器|预警播报器|喇叭蜂鸣器专为工业环境精心打造&#xff0c;完美适配AGV和无人叉车。同时&#xff0c;集成以太网与语音合成技术&#xff0c;为各类高级系统&#xff08;如MES、调度系统、库位管理、立库等&#xff09;提供高效便捷的语音交互体验。 L…

(LeetCode 每日一题) 3442. 奇偶频次间的最大差值 I (哈希、字符串)

题目&#xff1a;3442. 奇偶频次间的最大差值 I 思路 &#xff1a;哈希&#xff0c;时间复杂度0(n)。 用哈希表来记录每个字符串中字符的分布情况&#xff0c;哈希表这里用数组即可实现。 C版本&#xff1a; class Solution { public:int maxDifference(string s) {int a[26]…

【大模型RAG】拍照搜题技术架构速览:三层管道、两级检索、兜底大模型

摘要 拍照搜题系统采用“三层管道&#xff08;多模态 OCR → 语义检索 → 答案渲染&#xff09;、两级检索&#xff08;倒排 BM25 向量 HNSW&#xff09;并以大语言模型兜底”的整体框架&#xff1a; 多模态 OCR 层 将题目图片经过超分、去噪、倾斜校正后&#xff0c;分别用…

【Axure高保真原型】引导弹窗

今天和大家中分享引导弹窗的原型模板&#xff0c;载入页面后&#xff0c;会显示引导弹窗&#xff0c;适用于引导用户使用页面&#xff0c;点击完成后&#xff0c;会显示下一个引导弹窗&#xff0c;直至最后一个引导弹窗完成后进入首页。具体效果可以点击下方视频观看或打开下方…

接口测试中缓存处理策略

在接口测试中&#xff0c;缓存处理策略是一个关键环节&#xff0c;直接影响测试结果的准确性和可靠性。合理的缓存处理策略能够确保测试环境的一致性&#xff0c;避免因缓存数据导致的测试偏差。以下是接口测试中常见的缓存处理策略及其详细说明&#xff1a; 一、缓存处理的核…

龙虎榜——20250610

上证指数放量收阴线&#xff0c;个股多数下跌&#xff0c;盘中受消息影响大幅波动。 深证指数放量收阴线形成顶分型&#xff0c;指数短线有调整的需求&#xff0c;大概需要一两天。 2025年6月10日龙虎榜行业方向分析 1. 金融科技 代表标的&#xff1a;御银股份、雄帝科技 驱动…

观成科技:隐蔽隧道工具Ligolo-ng加密流量分析

1.工具介绍 Ligolo-ng是一款由go编写的高效隧道工具&#xff0c;该工具基于TUN接口实现其功能&#xff0c;利用反向TCP/TLS连接建立一条隐蔽的通信信道&#xff0c;支持使用Let’s Encrypt自动生成证书。Ligolo-ng的通信隐蔽性体现在其支持多种连接方式&#xff0c;适应复杂网…

铭豹扩展坞 USB转网口 突然无法识别解决方法

当 USB 转网口扩展坞在一台笔记本上无法识别,但在其他电脑上正常工作时,问题通常出在笔记本自身或其与扩展坞的兼容性上。以下是系统化的定位思路和排查步骤,帮助你快速找到故障原因: 背景: 一个M-pard(铭豹)扩展坞的网卡突然无法识别了,扩展出来的三个USB接口正常。…

未来机器人的大脑:如何用神经网络模拟器实现更智能的决策?

编辑&#xff1a;陈萍萍的公主一点人工一点智能 未来机器人的大脑&#xff1a;如何用神经网络模拟器实现更智能的决策&#xff1f;RWM通过双自回归机制有效解决了复合误差、部分可观测性和随机动力学等关键挑战&#xff0c;在不依赖领域特定归纳偏见的条件下实现了卓越的预测准…

Linux应用开发之网络套接字编程(实例篇)

服务端与客户端单连接 服务端代码 #include <sys/socket.h> #include <sys/types.h> #include <netinet/in.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <arpa/inet.h> #include <pthread.h> …

华为云AI开发平台ModelArts

华为云ModelArts&#xff1a;重塑AI开发流程的“智能引擎”与“创新加速器”&#xff01; 在人工智能浪潮席卷全球的2025年&#xff0c;企业拥抱AI的意愿空前高涨&#xff0c;但技术门槛高、流程复杂、资源投入巨大的现实&#xff0c;却让许多创新构想止步于实验室。数据科学家…

深度学习在微纳光子学中的应用

深度学习在微纳光子学中的主要应用方向 深度学习与微纳光子学的结合主要集中在以下几个方向&#xff1a; 逆向设计 通过神经网络快速预测微纳结构的光学响应&#xff0c;替代传统耗时的数值模拟方法。例如设计超表面、光子晶体等结构。 特征提取与优化 从复杂的光学数据中自…