文章目录
前言
本文介绍循环,分支,跳转相关内容。
(【由浅入深】是一个系列文章,它记录了我个人作为一个小白,在学习c++技术开发方向计相关知识过程中的笔记,欢迎各位彭于晏刘亦菲从中指出我的错误并且与我共同学习进步,作为该系列的第一部曲-c语言,大部分知识会根据本人所学和我的助手——通义,DeepSeek,腾讯元宝等以及合并网络上所找到的相关资料进行核实誊抄,每一篇文章都可能会因为一些错误在后续时间增删改查,因为该系列按照我的网络课程学习笔记形式编写,我会使用绝大多数人使用的讲解顺序编写,所以基础框架和大部分内容案例会与他人一样,基础知识不会过于详细讲述)
一.while循环
-
基本概念:C语言中的
while循环是一种前测试循环结构,用于在特定条件满足时重复执行一段代码。它的工作原理是:先判断条件表达式,如果为真(非0),则执行循环体;执行完循环体后,再次判断条件,直到条件为假(0)时退出循环。 -
语法结构
while (条件表达式) { // 循环体语句 } 条件表达式:可以是任何表达式,C语言中非0值被视为真,0值被视为假。 循环体:可以是单个语句,也可以是用花括号`{}`括起来的语句块。 -
工作原理
- 条件判断:程序首先评估条件表达式
- 条件为真:如果条件为真(非0),执行循环体
- 条件为假:如果条件为假(0),跳过循环体,执行循环后的代码
- 重复判断:执行完循环体后,再次回到条件判断,重复步骤1-3
-
使用示例
- 简单计数示例
#include <stdio.h>
int main() {
int i = 1;
while (i <= 10) {
printf("%d ", i);
i++;
}
return 0;
}
输出:1 2 3 4 5 6 7 8 9 10
- 计算1-100的和
#include <stdio.h>
int main() {
int i = 1;
int sum = 0;
while (i <= 100) {
sum += i;
i++;
}
printf("1到100的和是:%d\n", sum);
return 0;
}
- 无限循环(需谨慎使用)
#include <stdio.h>
int main() {
while (1) { // 条件永远为真
printf("无限循环中...\n");
// 通常需要添加退出条件,否则程序将一直运行
}
return 0;
}
-
关键注意事项
-
避免无限循环:
- 必须在循环体内包含修改条件的语句
- 例如:
i++、i--等,确保条件最终会变为假
-
条件表达式优化:
- 推荐使用布尔表达式,避免复杂计算
- 例如:
while (i < 100)比while (i <= 100 - 1)更清晰
-
变量初始化:
- 循环条件中使用的变量必须在循环前初始化
- 例如:
int i = 1;在while循环前
-
循环控制语句:
break:立即终止循环,跳到循环之后的代码continue:跳过本次循环剩余部分,直接进入下一次循环
-
-
常见应用场景
-
未知次数的重复操作:
- 从文件中读取数据直到文件结束
- 等待用户输入特定字符
- 处理网络请求直到成功
-
遍历数据结构:
- 遍历数组或链表
- 处理树形结构
-
条件满足时的重复操作:
- 计算直到达到特定精度
- 检查条件直到满足
-
-
死循环的处理:如果条件永远为真,程序会陷入无限循环。在实际开发中,应避免这种情况,或者添加退出条件:
#include <stdio.h>
int main() {
int count = 0;
while (1) {
printf("循环中: %d\n", count);
count++;
if (count > 10) {
break; // 当计数达到10时退出循环
}
}
return 0;
}
二.do-while循环
-
基本概念:do-while循环是C语言中的一种后测试循环结构,它的特点是先执行循环体,再检查条件。这意味着无论条件是否满足,循环体至少会执行一次。
-
语法结构
do { // 循环体语句 } while (条件表达式); -
重要注意:
while后的条件表达式后面必须加上分号(;),这是do-while循环的语法要求- 条件表达式可以是任何C语言表达式,非0值为真,0值为假
-
工作原理
- 首先执行循环体:程序先执行do和while之间的代码块
- 然后检查条件:执行完循环体后,检查while后的条件表达式
- 决定是否继续:如果条件为真(非0),则再次执行循环体;如果条件为假(0),则退出循环
-
与while循环的区别
特性 while循环 do-while循环 执行顺序 先判断条件,再执行循环体 先执行循环体,再判断条件 执行次数 条件为假时,循环体可能不执行 至少执行一次循环体 语法 while(条件) {循环体}do {循环体} while(条件); -
与while循环的对比示例
// while循环示例 int i = 5; while (i < 5) { printf("%d ", i); i++; } // 这个循环体不会执行,因为条件一开始就不满足 // do-while循环示例 int i = 5; do { printf("%d ", i); i++; } while (i < 5); // 这个循环体执行一次,输出5,然后条件不满足,退出循环 -
代码示例
示例1:打印1-10的数字
#include <stdio.h> int main() { int i = 1; do { printf("%d ", i); i++; } while (i <= 10); return 0; } //输出:1 2 3 4 5 6 7 8 9 10示例2:计算输入数字的位数
特别说明:如果输入为0,do-while循环能正确输出1(因为0是一位数),而while循环需要额外处理。#include <stdio.h> int main() { int n; int count = 0; scanf("%d", &n); do { n /= 10; // 去掉个位 count++; } while (n); printf("%d", count); return 0; }示例3:输入验证(必须至少输入一次)
#include <stdio.h> int main() { int number; do { printf("请输入一个正整数: "); scanf("%d", &number); if (number <= 0) { printf("输入错误,请重新输入!\n"); } } while (number <= 0); printf("你输入的正整数是: %d\n", number); return 0; } -
为什么需要do-while循环?
do-while循环的主要价值在于保证至少执行一次。在以下场景中特别有用:- 输入验证:确保用户至少输入一次数据
- 计算数字位数:如示例2所示
- 菜单驱动程序:确保用户至少看到一次菜单
- 游戏循环:先执行游戏逻辑再判断是否继续
-
常见错误
- 忘记分号:
while(条件表达式)后面必须加分号,这是语法要求
// 错误示例 do { printf("Hello"); } while (i < 5) // 缺少分号- 无限循环:如果条件表达式始终为真,会导致无限循环
// 错误示例 do { printf("Infinite loop"); } while (1); // 条件永远为真 - 忘记分号:
三.for循环
-
基本概念
for循环是C语言中最常用的循环结构之一,它将初始化、条件判断和更新操作集中在一个语句中,使代码更加简洁、可读性更强。for循环特别适合于已知迭代次数的场景,如遍历数组、执行固定次数的操作等。 -
语法结构
for (初始化表达式; 条件表达式; 更新表达式) { // 循环体 }- 初始化表达式:在循环开始前执行一次,通常用于声明和初始化循环变量。
- 条件表达式:每次迭代前都会进行判断,如果为真(非0),则执行循环体;如果为假(0),则终止循环。
- 更新表达式:每次循环迭代结束后执行,用于更新循环变量。
-
工作原理
- 执行初始化表达式:只在循环开始前执行一次
- 检查条件表达式:如果为真,执行循环体;如果为假,跳过循环体,执行循环后的代码
- 执行循环体:执行循环体中的代码
- 执行更新表达式:更新循环变量
- 返回步骤2:重新检查条件表达式,重复步骤2-4,直到条件为假
-
详细示例
- 简单计数示例
#include <stdio.h> int main() { for (int i = 1; i <= 10; i++) { printf("%d ", i); } return 0; } //输出:1 2 3 4 5 6 7 8 9 10- 计算1-100的和
#include <stdio.h> int main() { int sum = 0; for (int i = 1; i <= 100; i++) { sum += i; } printf("1到100的和是:%d\n", sum); return 0; }- 遍历数组
#include <stdio.h> int main() { int arr[] = {1, 2, 3, 4, 5}; int size = sizeof(arr) / sizeof(int); for (int i = 0; i < size; i++) { printf("数组元素 %d: %d\n", i, arr[i]); } return 0; } -
for循环的高级用法
1. 省略部分表达式:for`循环的三个部分都可以省略,但需要谨慎处理:
// 省略初始化表达式(需在循环前声明变量)
int i = 0;
for (; i < 10; i++) {
printf("%d ", i);
}
// 省略条件表达式(相当于while(1),需要在循环体内使用break)
for (int i = 0; ; i++) {
if (i >= 10) break;
printf("%d ", i);
}
// 省略更新表达式(需在循环体内更新变量)
for (int i = 0; i < 10;) {
printf("%d ", i);
i++;
}
- 无限循环
// 无限循环(需在循环体内使用break)
for (;;) {
// 循环体
if (some_condition) {
break;
}
}
-
与while循环的比较
特点 while循环 for循环 适用场景 条件未知或循环次数不确定 已知循环次数 代码结构 仅需条件判断 包含初始化、条件判断、更新 可读性 有时较难理解循环控制 通常更清晰 适用性 适用于更复杂的条件判断 适用于简单计数循环 -
C99/C11标准问题
错误:'for' loop initial declarations are only allowed in C99 or C11 mode
原因:在C89/C90标准下,不允许在for循环初始化部分声明变量。
解决方案:
// 方案一:在循环前声明变量
int i;
for (i = 0; i < 10; i++) {
printf("%d ", i);
}
// 方案二:使用C99或C11标准编译
// 例如:gcc -std=c99 filename.c
- for循环与while循环的等价转换
// for循环
for (int i = 0; i < 10; i++) {
// 循环体
}
// 等价的while循环
int i = 0;
while (i < 10) {
// 循环体
i++;
}
- 与C99/C11标准相关
在C99及以后的标准中,可以在for循环的初始化部分声明变量,这使代码更加简洁:
// C99/C11标准支持
for (int i = 0; i < 10; i++) {
printf("%d ", i);
}
在C89/C90标准中,需要在循环前声明变量:
// C89/C90标准
int i;
for (i = 0; i < 10; i++) {
printf("%d ", i);
}
四.if语句
-
基本概念:
if语句是C语言中最基本的条件控制结构,用于根据特定条件判断执行不同的代码路径。在C语言中,条件表达式的值为非零(true)时,执行相应的代码块;值为0(false)时,跳过该代码块。 -
语法结构
if语句有两种基本形式:-
基本形式
if (expression)
statement; -
if-else形式
if (expression)
statement1;
else
statement2; -
if-else if-else多分支形式
if (expression1)
statement1;
else if (expression2)
statement2;
else
statement3;
-
-
工作原理
- 条件表达式:计算括号内的表达式,如果结果为非零(true),则执行
if后的语句;如果为0(false),则执行else后的语句(如果有)。 - 语句执行:如果
if后只有一条语句,可以不加花括号;如果有多条语句,必须使用花括号{}将它们括起来。 - C语言特性:在C语言中,0表示false,非0表示true。例如:
- 条件表达式:计算括号内的表达式,如果结果为非零(true),则执行
if (3) { // 3是非0,条件为true
printf("yes");
} else {
printf("no");
}
// 输出:yes
- 嵌套if语句
if (condition1) {
if (condition2) {
// 条件1和条件2都满足时执行
} else {
// 条件1满足但条件2不满足时执行
}
} else {
// 条件1不满足时执行
}
-
最佳实践
- 使用大括号:即使只有一条语句,也建议使用大括号,提高代码可读性和可维护性。
// 推荐 if (condition) { statement; } // 不推荐(容易出错) if (condition) statement;-
保持条件清晰:避免过于复杂的条件表达式,可以将复杂条件分解为多个简单条件。
-
注意条件顺序:在多条件判断中,条件应按优先级从高到低排列。
-
处理边界情况:确保所有可能的条件都被覆盖,避免遗漏导致逻辑错误。
-
避免过度嵌套:如果嵌套过深,考虑重构代码,使用函数或更简洁的逻辑。
悬空else问题
-
悬空Else(问题是C/C++等编程语言中常见的语法问题,指的是当有多个嵌套的if语句时,else子句会与最近的if语句匹配,而不是与我们期望的if匹配。这通常是因为代码中省略了花括号({})导致的。
-
核心规则: 在C语言中,else总是与最近的、没有else的if匹配,而不是与对齐的if匹配。
五.switch语句
-
基本概念:
switch语句是C语言中用于多分支条件判断的控制结构,它根据表达式的值选择执行不同的代码块。与if-else语句相比,当需要处理多个固定值的条件判断时,switch语句通常更为简洁、清晰。 -
基本语法结构:
switch (expression) {//switch语句中的expression必须是整型(int、char等)、枚举类型或可以隐式转换为整型的表达式,不能是浮点数、字符串等类型。
case constant1:
// 执行内容
break;
case constant2:
// 执行内容
break;
// 可以有多个case
default:
// 默认执行内容
break;
}
-
关键要素解析
- 表达式类型限制
- 必须是整型(int/char):在C语言中,
switch表达式必须是整型(包括字符型,因为字符本质上是小整数) - 不支持浮点型:
float、double等浮点类型不能用作switch表达式 - 不支持字符串:不能直接用字符串进行比较
- 必须是整型(int/char):在C语言中,
- 表达式类型限制
在C和C++语言中,switch语句里case后面的常量表达式必须是整型(包括字符型),不能是浮点型或者其他复杂类型。
-
case语句
- 必须是常量表达式:case后必须接一个常量或宏定义,不能是变量
int num = 1; switch(num) { case 1: // 正确,1是字面常量 break; case num: // 错误,num是变量 break; }- 常量必须唯一:case后的值不能重复
case 5: // 正确 case 5: // 错误,重复的值- 支持多个case匹配同一执行块:
case 10: case 9: // 10和9都执行同一个代码块 printf("A"); break; -
break语句
- 作用:终止switch语句的执行,防止"贯穿"到下一个case
- 重要性:不使用break会导致程序继续执行后续case,这通常不是我们期望的行为
- 特殊情况:有时有意要实现贯穿,可以不加break
case 1:
printf("1");
case 2:
printf("2"); // 没有break,会输出"12"
-
default子句
- 可选:不是必须的,但建议保留以处理意外情况
- 位置:可以放在任意位置,但通常放在最后
- 作用:当所有case都不匹配时执行
如果case或default标签后有多条语句,使用{}以避免逻辑错误或警告。
- 与if-else语句的对比
| 特点 | switch语句 | if-else语句 |
|---|---|---|
| 适用场景 | 固定值条件判断 | 任意条件判断 |
| 代码简洁性 | 分支多时更简洁 | 分支多时较冗长 |
| 条件类型 | 仅支持整型/字符型 | 支持任意类型 |
| 执行效率 | 通常更高(直接跳转) | 逐个判断 |
| 代码可读性 | 更清晰(固定值匹配) | 随分支增多变差 |
- 典型应用场景
//星期几判断
int day = 3;
switch(day) {
case 1:
printf("Monday\n");
break;
case 2:
printf("Tuesday\n");
break;
case 3:
printf("Wednesday\n");
break;
// ... 其他星期
default:
printf("Invalid day\n");
}
-
注意事项
-
始终使用break:除非有意要实现贯穿,否则每个case后都应添加break
-
保持case顺序:按逻辑顺序排列case,提高可读性
-
保留default:即使在所有已知情况下都能匹配,也建议保留default处理意外情况
-
使用花括号:当case后有多行语句时,使用花括号括起来
-
避免过度嵌套:如果逻辑复杂,考虑使用函数或重构代码
-
六. 循环辅助:break和continue语句
6.1 break语句
- 基本作用
- 立即终止当前循环:当执行到
break语句时,会立即终止当前所在的 循环(for、while、do-while) ,并跳到循环后的下一条语句
- 立即终止当前循环:当执行到
for() {
if() {
if() {
if() {
break; // 这个break会跳出for循环,而不是if语句
}
}
}
}
-
跳出switch语句:在switch结构中,
break用于防止"贯穿"(fall-through),使程序跳出switch -
语法示例
在循环中使用break
#include <stdio.h>
int main() {
for (int i = 0; i < 10; i++) {
if (i == 5) {
break; // 当i等于5时,终止循环
}
printf("%d ", i);
}
// 输出: 0 1 2 3 4
return 0;
}
在switch中使用break
#include <stdio.h>
int main() {
int x = 1;
switch (x) {
case 1:
printf("Red");
break; // 跳出switch
case 0:
printf("White");
break; // 跳出switch
}
// 不使用break时,会"贯穿"到下一个case
return 0;
}
- 重要特性
- 多层循环中:只能跳出最内层的循环,无法同时跳出多层循环
- 与if联用:通常与if条件语句一起使用,满足条件时跳出循环
- 在switch中:必须使用,否则会"贯穿"执行后续case
6.2 continue语句
-
基本作用
- 跳过当前迭代:当执行到
continue语句时,会跳过当前 循环 的剩余部分,直接进入下一次循环迭代 - 不终止整个循环:只是跳过本次迭代,循环会继续执行
- 跳过当前迭代:当执行到
-
语法示例
#include <stdio.h>
int main() {
for (int i = 0; i < 10; i++) {
if (i % 2 == 0) {
continue; // 跳过偶数
}
printf("%d ", i);
}
// 输出: 1 3 5 7 9
return 0;
}
-
重要特性
- 仅在循环中使用:只能在for、while、do-while等循环结构中使用
- 与if联用:通常与if条件语句一起使用,满足条件时跳过当前迭代
- 不会终止循环:只是跳过当前迭代的剩余代码
-
break与continue的区别
特性 break continue 作用 终止当前循环,跳到循环后 跳过当前迭代,进入下一次迭代 是否终止循环 是 否 执行效果 循环体剩余代码不执行 当前迭代剩余代码不执行 在switch中 可以使用 不能使用 在多层循环中 只能跳出最内层循环 只会影响当前循环
七. goto语句
- 基本概念:
goto语句是C语言中的一种无条件转移语句,允许程序直接跳转到函数内部的任意位置(只要在同一个函数内)。它通过标签(label)实现跳转,是C语言中一种较原始的控制流机制。 - 基本语法
// 标签定义 label: // 标签标识符 // goto语句 goto label; // 跳转到label位置
C语言的goto语句中,标签(label)可以在任何地方,包括在goto语句之前、之后,甚至在goto语句的同一行。
-
使用示例
- 基本示例
#include <stdio.h>
int main() {
int myInteger = 5;
goto myLabel; // 跳转到myLabel
myInteger += 10; // 这行代码不会执行
myLabel: // 标签
printf("myInteger=%d\n", myInteger); // 输出: 5
return 0;
}
- 多层循环跳出
#include <stdio.h>
int main() {
for (int i = 0; i < 10; i++) {
for (int j = 0; j < 10; j++) {
if (i == 5 && j == 5) {
goto end; // 跳出两层循环
}
}
}
end:
printf("循环已跳出\n");
return 0;
}
- 死循环示例
#include <stdio.h>
int main() {
start: // 标签
printf("This is a dead loop.\n");
goto start; // 无条件跳转回start
}
-
关键特性
-
跳转方向:可以向前跳转(跳过前面的代码),也可以向后跳转(跳入循环)
-
标签位置:标签必须与goto语句同处于一个函数中,但可以不在同一循环层中
-
标签规则:
- 标签名需符合标识符命名规则
- 标签必须以冒号结尾
- 不能重名
-
-
使用场景与注意事项
-
合理使用场景(推荐使用)
-
跳出多层嵌套循环:这是goto语句最合理的使用场景
-
错误处理:在需要统一清理资源的场景中,可以使用goto跳转到错误处理代码
-
-
不推荐使用场景
- 一般流程控制:用if-else或switch语句代替
- 循环控制:用break和continue代替
- 创建死循环:应使用while(true)等结构化方式
-
重要注意事项
- 避免滥用:过度使用goto会使代码难以理解和维护,形成"面条代码"
- C语言作者建议:知识库[4]指出:“其实就连C语言的作者也觉得goto语句非常容易被滥用,并且建议一定要谨慎使用,甚至根本不用它。”
- 不能从复杂状态跳转:知识库[8]指出:“不能从一段复杂的执行状态中的位置goto到另外一个位置,比如,从多重嵌套的循环判断中跳出去就是不允许的。”
- 避免双向跳转:知识库[8]强调:“应该避免向两个方向跳转。这样最容易导致’面条代码’。”
-
-
goto语句 vs 其他控制流
控制流 适用场景 优点 缺点 goto 跳出多层循环、统一错误处理 代码简洁 难以理解、易出错 break 跳出单层循环 清晰、标准 无法跳出多层循环 continue 跳过当前循环迭代 清晰、标准 无法跳出循环 if-else/switch 条件分支 清晰、结构化 分支多时代码冗长
1960

被折叠的 条评论
为什么被折叠?



