📖 本文目录
- [📌 1. 引言](#📌 1. 引言) --- 结构化程序设计概述
- [🎯 2. if 语句](#🎯 2. if 语句) --- if基本语法、if...else、嵌套if、悬空else
- [🔗 3. 关系操作符](#🔗 3. 关系操作符) --- 6种关系运算符及常见错误
- [❓ 4. 条件操作符(三目运算符)](#❓ 4. 条件操作符(三目运算符)) --- 三目运算符的使用
- [🔀 5. 逻辑操作符](#🔀 5. 逻辑操作符) --- &&、||、! 及短路求值
- [🔄 6. switch 语句](#🔄 6. switch 语句) --- switch语法、break、default
- [🔁 7. while 循环](#🔁 7. while 循环) --- while语法、执行流程、实践练习
- [🔄 8. for 循环](#🔄 8. for 循环) --- for语法、执行流程、与while对比
- [🔄 9. do-while 循环](#🔄 9. do-while 循环) --- do-while语法、执行流程、实践练习
- [⏹️ 10. break和continue](#⏹️ 10. break和continue) --- break与continue的区别与对比
- [🔗 11. 循环的嵌套](#🔗 11. 循环的嵌套) --- 循环嵌套及素数查找练习
- [🏷️ 12. goto语句](#🏷️ 12. goto语句) --- goto适用场景、实际应用、注意事项实际应用、注意事项 |
📌 1. 引言
C语言是结构化的程序设计语言,这里的结构指的是 顺序结构 、选择结构 、循环结构。C语言能够实现这三种结构,其实我们如果仔细分析,我们日常所见的事情都可以拆分为这三种结构或者这三种结构的组合。
我们可以使用 if、switch 实现分支结构,使用 for、while、do while 实现循环结构。
💡 面试小贴士:结构化程序设计是C语言的核心思想,面试中常会问到三种基本结构的区别与使用场景。
🎯 2. if 语句
2.1 if 的基本语法
c
if (表达式)
语句
- 表达式成立(为真),则语句执行,表达式不成立(为假),则语句不执行。
- 在C语言中,0为假,非0表示真。也就是说,表达式的结果如果是0,则语句不执行;表达式的结果如果不是0,则语句执行。
示例:输入一个整数,判断是否为奇数
c
#include <stdio.h>
int main()
{
int num = 0;
scanf("%d", &num);
if(num % 2 == 1)
printf("%d 是奇数\n", num);
return 0;
}
执行流程图:

2.2 if...else 语句
如果一个数不是奇数,那就是偶数了。如果任意一个整数,我们要清楚地判断是奇数还是偶数,就需要 if...else... 语句。
c
if (表达式)
语句1
else
语句2
示例:输入一个整数,判断奇偶
c
#include <stdio.h>
int main()
{
int num = 0;
scanf("%d", &num);
if(num % 2 == 1)
printf("%d 是奇数\n", num);
else
printf("%d 是偶数\n", num);
return 0;
}
练习:输入一个年龄,>=18岁就输出"成年",否则输出"未成年"
c
#include <stdio.h>
int main()
{
int age = 0;
scanf("%d", &age);
if(age >= 18)
printf("成年\n");
else
printf("未成年\n");
return 0;
}
2.3 分支中包含多条语句
默认在 if 和 else 语句中默认都只控制一条语句,比如:
c
#include <stdio.h>
int main()
{
int age = 0;
scanf("%d", &age);
if(age >= 18)
printf("成年了\n");
printf("可以谈恋爱了\n"); // 这条语句不受if控制!
return 0;
}


上面的代码,你会发现输入的值不管是>=18还是<18,"可以谈恋爱了"都会打印在屏幕上。这是因为 if 语句只能控制一条语句,就是 printf("成年了\n");。printf("可以谈恋爱了\n"); 是独立存在的,不管if语句条件的真假,都会被执行。
解决方法:使用 {} 将代码括起来
c
#include <stdio.h>
int main()
{
int age = 0;
scanf("%d", &age);
if(age >= 18) //if 后使用{} 控制多条语句-这个块也叫:程序块,或者复合语句
{
printf("成年了\n");
printf("可以谈恋爱了\n");
}
else //else 后使用{}控制多条语句
{
printf("未成年\n");
printf("不可以早恋哦\n");
}
return 0;
}
💡 面试小贴士 :面试中常问"if默认控制几条语句?"------答案是一条 。如果需要控制多条,必须使用大括号
{}。
2.4 嵌套 if
在 if else 语句中,else 可以与另一个 if 语句连用,构成多重判断。
示例:判断输入的数字是0、正数还是负数
c
#include <stdio.h>
int main()
{
int num = 0;
scanf("%d", &num);
if(num == 0)
printf("输入的数字是0\n");
else if(num > 0) //这里的if相当于嵌套在else语句中,形成了嵌套结构
printf("输入的数字是正数\n");
else
printf("输入的数字是负数\n");
return 0;
}
示例:输入一个整数,如果是正数,再判断是奇数还是偶数
c
#include <stdio.h>
int main()
{
int num = 0;
scanf("%d", &num);
if(num > 0)
{
if(num % 2 == 0)
printf("偶数\n");
else
printf("奇数\n");
}
else
{
printf("非正数\n");
}
return 0;
}
练习:输入一个人的年龄,判断年龄段
要求:
- 年龄<18岁 → 打印"少年"
- 18岁至44岁 → 打印"青年"
- 45岁至59岁 → 打印"中老年"
- 60岁至89岁 → 打印"老年"
- 90岁及以上 → 打印"老寿星"
方法一(简洁写法):
c
#include <stdio.h>
int main()
{
int age = 0;
scanf("%d", &age);
if(age < 18)
printf("少年\n");
else if(age <= 44)
printf("青年\n");
else if(age <= 59)
printf("中老年\n");
else if(age <= 89)
printf("老年\n");
else
printf("老寿星\n");
return 0;
}
方法二(带大括号,更清晰):
c
#include <stdio.h>
int main()
{
int age = 0;
scanf("%d", &age);
if(age < 18)
{
printf("少年\n");
}
else
{
if(age <= 44)
{
printf("青年\n");
}
else
{
if(age <= 59)
{
printf("中老年\n");
}
else
{
if(age <= 89)
printf("老年\n");
else
printf("老寿星\n");
}
}
}
return 0;
}
2.5 悬空 else 问题
如果有多个 if 和 else,可以记住这样一条规则:else 总是跟最接近的 if 匹配。
c
#include <stdio.h>
int main()
{
int a = 0;
int b = 2;
if(a == 1)
if(b == 2)
printf("hehe\n");
else
printf("haha\n");
return 0;
}
程序运行的结果是:啥都不输出。
很多初学者以为 else 和第一个 if 匹配,但实际上 else 是和第二个 if 进行匹配的。这样后边的 if...else 语句是嵌套在第一个 if 语句中的,如果第一个 if 语句就不成立,嵌套 if 和 else 就没机会执行了。

正确写法(加括号):
c
#include <stdio.h>
int main()
{
int a = 0;
int b = 2;
if(a == 1)
{
if(b == 2)
printf("hehe\n");
else
printf("haha\n");
}
return 0;
}
如果希望else确实和第一个if匹配:
c
#include <stdio.h>
int main()
{
int a = 0;
int b = 2;
if(a == 1)
{
if(b == 2)
printf("hehe\n");
}
else
{
printf("haha\n");
}
return 0;
}
💡 面试小贴士 :悬空else是C语言面试中的经典陷阱题!记住:else总是与最近的if匹配,加上大括号可以避免歧义。
🔗 3. 关系操作符
C语言用于比较的表达式,称为"关系表达式"(relational expression),里面使用的运算符就称为"关系运算符"(relational operator),主要有下面6个:
| 运算符 | 含义 | 示例 |
|---|---|---|
> |
大于运算符 | a > b |
< |
小于运算符 | a < b |
>= |
大于等于运算符 | a >= b |
<= |
小于等于运算符 | a <= b |
== |
相等运算符 | a == b |
!= |
不相等运算符 | a != b |
关系表达式通常返回 0 或 1 ,表示真假。C语言中,0表示假,所有非零值表示真。比如,20 > 12 返回1,12 > 20 返回0。
关系表达式常用于 if 或 while 结构。
c
if (x == 3) {
printf("x is 3.\n");
}
💡 注意:相等运算符 == 与赋值运算符 = 是两个不⼀样的运算符,不要混淆。有时候,可能会不⼩⼼写出下⾯的代码,它可以运⾏,但很容易出现意料之外的结果。
⚠️ 常见错误
错误1:混淆 == 和 =
c
if (x = 3) // 这是赋值,不是判断相等!
上面示例中,原意是 x == 3,但是不小心写成 x = 3。这个式子表示对变量x赋值3,它的返回值为3,所以if判断总是为真。
防御性写法:将常量写在左边
c
if (3 == x) // 如果不小心写成 if (3 = x),编译器会报错
错误2:关系运算符连用
c
i < j < k // 错误写法!
关系运算符是从左到右计算,所以实际执行的是 (i < j) < k。i < j 返回0或1,最终是0或1与变量k进行比较。
正确写法:
c
i < j && j < k
示例:判断年龄是否在18~36岁之间
c
// ❌ 错误写法
#include <stdio.h>
int main()
{
int age = 0;
scanf("%d", &age);
if(18 <= age <= 36) // 逻辑错误!
{
printf("青年\n");
}
return 0;
}
当我们输入10的时候,依然输出"青年"。这是因为先拿18和age中存放的10比较,表达式 18 <= 10 为假,结果为0,再拿0和36比较,0 <= 36 为真,所以打印了"青年"。
c
// ✅ 正确写法
#include <stdio.h>
int main()
{
int age = 0;
scanf("%d", &age);
if(age >= 18 && age <= 36)
{
printf("青年\n");
}
return 0;
}
❓ 4. 条件操作符(三目运算符)
条件操作符也叫三目操作符,需要接受三个操作数,形式如下:
c
exp1 ? exp2 : exp3
计算逻辑 :如果 exp1 为真,exp2 计算,计算的结果是整个表达式的结果;如果 exp1 为假,exp3 计算,计算的结果是整个表达式的结果。
练习1:使用条件操作符改写if-else代码
c
// 原始代码
#include <stdio.h>
int main()
{
int a = 0;
int b = 0;
scanf("%d", &a);
if (a > 5)
b = 3;
else
b = -3;
printf("%d\n", b);
return 0;
}
// 改造后(使用条件操作符)
#include <stdio.h>
int main()
{
int a = 0;
int b = 0;
scanf("%d", &a);
b = a > 5 ? 3 : -3;
printf("%d\n", b);
return 0;
}
练习2:使用条件表达式实现找两个数中较大值
c
#include <stdio.h>
int main()
{
int a = 0;
int b = 0;
scanf("%d %d", &a, &b);
int m = a > b ? a : b;
printf("%d\n", m);
return 0;
}
💡 面试小贴士:三目运算符可以简化简单的if-else判断,但嵌套使用会降低可读性,面试中建议适度使用。
🔀 5. 逻辑操作符:&&、||、!
逻辑运算符提供逻辑判断功能,用于构建更复杂的表达式,主要有下面三个运算符:
| 运算符 | 含义 | 说明 |
|---|---|---|
! |
逻辑取反 | 改变单个表达式的真假 |
&& |
逻辑与(并且) | 两侧都为真,结果才为真 |
| ` | ` |
注:C语言中,非0表示真,0表示假。
5.1 逻辑取反运算符 !
c
#include <stdio.h>
int main()
{
int flag = 0;
if(!flag) // flag为假时执行
{
printf("do something\n");
}
return 0;
}
如果 flag 为真,!flag 就是假;如果 flag 为假,!flag 就是真。
5.2 逻辑与运算符 &&
&& 是双⽬操作符,两边的表达式都是真的时候,整个表达式才为真,只要有一个是假,则整个表达式为假。
示例:判断月份是否为春季(3月~5月)
c
int month = 0;
scanf("%d", &month);
if(month >= 3 && month <= 5)
{
printf("春季\n");
}
这里表达的意思就是month既要大于等于3,又要小于等于5,必须同时满足。
5.3 逻辑或运算符 ||
|| 也是双⽬操作符,两边的表达式只要有一个是真,整个表达式就是真,两边的表达式都为假的时候,才为假。
示例:判断月份是否为冬季(12月、1月、2月)
c
int month = 0;
scanf("%d", &month);
if(month == 12 || month == 1 || month == 2)
{
printf("冬季\n");
}
5.4 练习:闰年的判断
闰年判断规则:
- 能被4整除并且不能被100整除是闰年
- 能被400整除是闰年
c
// 代码1
#include <stdio.h>
int main()
{
int year = 0;
scanf("%d", &year);
if(year % 4 == 0 && year % 100 != 0)
printf("是闰年\n");
else if(year % 400 == 0)
printf("是闰年\n");
return 0;
}
// 代码2(更简洁)
#include <stdio.h>
int main()
{
int year = 0;
scanf("%d", &year);
if((year % 4 == 0 && year % 100 != 0) || (year % 400 == 0))
printf("是闰年\n");
return 0;
}
5.5 短路求值
C语言逻辑运算符还有一个特点:它总是先对左侧的表达式求值,再对右边的表达式求值 ,这个顺序是保证的。如果左边的表达式满足逻辑运算符的条件,就不再对右边的表达式求值。这种情况称为"短路"。
对于 &&: 左边为0(假)时,右边不再执行
c
if(month >= 3 && month <= 5)
表达式中 && 的左操作数是 month >= 3,右操作数是 month <= 5,当左操作数 month >= 3 的结果是0的时候,即使不判断 month <= 5,整个表达式的结果也是0。
对于 ||: 左边为非0(真)时,右边不再执行
c
if(month == 12 || month == 1 || month == 2)
如果 month == 12,则不用再判断month是否等于1或者2,整个表达式的结果也是1。
练习:阅读代码,计算代码输出的结果
c
#include <stdio.h>
int main()
{
int i = 0, a = 0, b = 2, c = 3, d = 4;
i = a++ && ++b && d++;
// i = a++ || ++b || d++;
printf("a = %d\nb = %d\nc = %d\nd = %d\n", a, b, c, d);
return 0;
}
💡 面试小贴士 :短路求值是面试高频考点!记住:
&&左边为假就短路,||左边为真就短路。短路时右边表达式不会执行。
🔄 6. switch 语句
除了 if 语句外,C语言还提供了 switch 语句来实现分支结构。switch 语句是一种特殊形式的 if...else 结构,用于判断条件有多个结果的情况。
c
switch (expression) {
case value1: statement
case value2: statement
default: statement
}
注:
switch后的expression必须是整型表达式case后的值,必须是整型常量表达式
6.1 if语句和switch语句的对比
练习:输入任意一个整数值,计算除3之后的余数
使用if语句:
c
#include <stdio.h>
int main()
{
int n = 0;
scanf("%d", &n);
if(n % 3 == 0)
printf("整除,余数为0\n");
else if(n % 3 == 1)
printf("余数是1\n");
else
printf("余数是2\n");
return 0;
}
使用switch语句:
c
#include <stdio.h>
int main()
{
int n = 0;
scanf("%d", &n);
switch(n % 3)
{
case 0:
printf("整除,余数为0\n");
break;
case 1:
printf("余数是1\n");
break;
case 2:
printf("余数是2\n");
break;
}
return 0;
}
注意:
case和后边的数字之间必须有空格- 每一个
case语句中的代码执行完成后,需要加上break,才能跳出这个switch语句
6.2 switch语句中的break
如果去掉case语句中的break,会出现什么情况呢?
c
#include <stdio.h>
int main()
{
int n = 0;
scanf("%d", &n);
switch(n % 3)
{
case 0:
printf("整除,余数为0\n");
case 1:
printf("余数是1\n");
case 2:
printf("余数是2\n");
}
return 0;
}
测试发现,7除以3本来余数是1,但程序运行的结果多了一行"余数是2"的打印。这是因为如果没有 break,代码会继续往下执行,直到遇到 break 或 switch 语句结束。这种现象称为"穿透"。
练习:输入1~7的数字,打印对应的星期几
c
#include <stdio.h>
int main()
{
int day = 0;
scanf("%d", &day);
switch(day)
{
case 1:
printf("星期一\n");
break;
case 2:
printf("星期二\n");
break;
case 3:
printf("星期三\n");
break;
case 4:
printf("星期四\n");
break;
case 5:
printf("星期五\n");
break;
case 6:
printf("星期六\n");
break;
case 7:
printf("星期天\n");
break;
}
return 0;
}
需求变化: 输入15输出"工作日",输入67输出"休息日"
c
#include <stdio.h>
int main()
{
int day = 0;
scanf("%d", &day);
switch(day)
{
case 1:
case 2:
case 3:
case 4:
case 5:
printf("工作日\n");
break;
case 6:
case 7:
printf("休息日\n");
break;
}
return 0;
}
💡 面试小贴士:switch的"穿透"特性可以巧妙利用,如上例中多个case共享同一段代码。面试中常问"switch中break的作用"------break用于跳出switch,防止穿透。
6.3 switch语句中的default
当 switch 后的表达式的值无法匹配代码中的 case 语句时,可以使用 default 子句。
c
switch (expression) {
case value1: statement
case value2: statement
default: statement
}
示例:输入错误时提示
c
#include <stdio.h>
int main()
{
int day = 0;
scanf("%d", &day);
switch(day)
{
case 1:
case 2:
case 3:
case 4:
case 5:
printf("工作日\n");
break;
case 6:
case 7:
printf("休息日\n");
break;
default:
printf("输入错误\n");
break;
}
return 0;
}
6.4 switch语句中case和default的顺序
在 switch 语句中 case 语句和 default 语句是没有顺序要求的,只要满足实际需求就可以。不过我们通常是把 default 子句放在最后处理。
🔁 7. while 循环
C语言提供了3种循环语句,while 就是其中一种。
7.1 if 和 while 的对比
c
if(表达式)
语句;
while(表达式)
语句; // 如果循环体想包含更多的语句,可以加上大括号
代码对比:
c
// 代码1 - if
#include <stdio.h>
int main()
{
if(1)
printf("hehe\n"); // if后边条件满足,打印一次hehe
return 0;
}
// 代码2 - while
#include <stdio.h>
int main()
{
while(1)
printf("hehe\n"); // while后边的条件满足,死循环的打印hehe
return 0;
}
这就是他们的区别,while 语句是可以实现循环效果的。
7.2 while语句的执行流程
#mermaid-svg-DwZdFGIaFtKzYBJu{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-DwZdFGIaFtKzYBJu .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-DwZdFGIaFtKzYBJu .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-DwZdFGIaFtKzYBJu .error-icon{fill:#552222;}#mermaid-svg-DwZdFGIaFtKzYBJu .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-DwZdFGIaFtKzYBJu .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-DwZdFGIaFtKzYBJu .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-DwZdFGIaFtKzYBJu .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-DwZdFGIaFtKzYBJu .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-DwZdFGIaFtKzYBJu .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-DwZdFGIaFtKzYBJu .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-DwZdFGIaFtKzYBJu .marker{fill:#333333;stroke:#333333;}#mermaid-svg-DwZdFGIaFtKzYBJu .marker.cross{stroke:#333333;}#mermaid-svg-DwZdFGIaFtKzYBJu svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-DwZdFGIaFtKzYBJu p{margin:0;}#mermaid-svg-DwZdFGIaFtKzYBJu .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-DwZdFGIaFtKzYBJu .cluster-label text{fill:#333;}#mermaid-svg-DwZdFGIaFtKzYBJu .cluster-label span{color:#333;}#mermaid-svg-DwZdFGIaFtKzYBJu .cluster-label span p{background-color:transparent;}#mermaid-svg-DwZdFGIaFtKzYBJu .label text,#mermaid-svg-DwZdFGIaFtKzYBJu span{fill:#333;color:#333;}#mermaid-svg-DwZdFGIaFtKzYBJu .node rect,#mermaid-svg-DwZdFGIaFtKzYBJu .node circle,#mermaid-svg-DwZdFGIaFtKzYBJu .node ellipse,#mermaid-svg-DwZdFGIaFtKzYBJu .node polygon,#mermaid-svg-DwZdFGIaFtKzYBJu .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-DwZdFGIaFtKzYBJu .rough-node .label text,#mermaid-svg-DwZdFGIaFtKzYBJu .node .label text,#mermaid-svg-DwZdFGIaFtKzYBJu .image-shape .label,#mermaid-svg-DwZdFGIaFtKzYBJu .icon-shape .label{text-anchor:middle;}#mermaid-svg-DwZdFGIaFtKzYBJu .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-DwZdFGIaFtKzYBJu .rough-node .label,#mermaid-svg-DwZdFGIaFtKzYBJu .node .label,#mermaid-svg-DwZdFGIaFtKzYBJu .image-shape .label,#mermaid-svg-DwZdFGIaFtKzYBJu .icon-shape .label{text-align:center;}#mermaid-svg-DwZdFGIaFtKzYBJu .node.clickable{cursor:pointer;}#mermaid-svg-DwZdFGIaFtKzYBJu .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-DwZdFGIaFtKzYBJu .arrowheadPath{fill:#333333;}#mermaid-svg-DwZdFGIaFtKzYBJu .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-DwZdFGIaFtKzYBJu .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-DwZdFGIaFtKzYBJu .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-DwZdFGIaFtKzYBJu .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-DwZdFGIaFtKzYBJu .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-DwZdFGIaFtKzYBJu .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-DwZdFGIaFtKzYBJu .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-DwZdFGIaFtKzYBJu .cluster text{fill:#333;}#mermaid-svg-DwZdFGIaFtKzYBJu .cluster span{color:#333;}#mermaid-svg-DwZdFGIaFtKzYBJu div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-DwZdFGIaFtKzYBJu .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-DwZdFGIaFtKzYBJu rect.text{fill:none;stroke-width:0;}#mermaid-svg-DwZdFGIaFtKzYBJu .icon-shape,#mermaid-svg-DwZdFGIaFtKzYBJu .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-DwZdFGIaFtKzYBJu .icon-shape p,#mermaid-svg-DwZdFGIaFtKzYBJu .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-DwZdFGIaFtKzYBJu .icon-shape .label rect,#mermaid-svg-DwZdFGIaFtKzYBJu .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-DwZdFGIaFtKzYBJu .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-DwZdFGIaFtKzYBJu .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-DwZdFGIaFtKzYBJu :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 是
否
判断表达式
值为0?
结束
执行循环语句
首先执行判断表达式,表达式的值为0,循环直接结束;表达式的值不为0,则执行循环语句,语句执行完后再继续判断,是否进行下一次判断。
7.3 while循环的实践
练习:在屏幕上打印1~10的值
c
#include <stdio.h>
int main()
{
int i = 1;
while(i <= 10)
{
printf("%d ", i);
i = i + 1;
}
return 0;
}
7.4 练习:逆序打印整数
题目: 输入一个正的整数,逆序打印这个整数的每一位
例如:
- 输入:1234,输出:4 3 2 1
- 输入:521,输出:1 2 5
题目解析:
- 要想得到n的最低位,可以使用
n % 10的运算,得到的余数就是最低位,如:1234%10得到4 - 要想去掉n的最低位,找出倒数第二位,则使用
n = n / 10操作就可以去掉最低位的,如:n=1234/10得到123,123%10就得到倒数第二位3 - 循环1和2两个步骤,在n变成0之前,就能得到所有的位
c
#include <stdio.h>
int main()
{
int n = 0;
scanf("%d", &n);
while(n)
{
printf("%d ", n % 10);
n /= 10;
}
return 0;
}
🔄 8. for 循环
8.1 语法形式
for 循环是三种循环中使用最多的,语法形式如下:
c
for(表达式1; 表达式2; 表达式3)
语句; // 如果循环体想包含更多的语句,可以加上大括号
- 表达式1:用于循环变量的初始化
- 表达式2:用于循环结束条件的判断
- 表达式3:用于循环变量的调整
8.2 for循环的执行流程
#mermaid-svg-mDyrIjRyzE7Ta0B7{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-mDyrIjRyzE7Ta0B7 .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-mDyrIjRyzE7Ta0B7 .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-mDyrIjRyzE7Ta0B7 .error-icon{fill:#552222;}#mermaid-svg-mDyrIjRyzE7Ta0B7 .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-mDyrIjRyzE7Ta0B7 .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-mDyrIjRyzE7Ta0B7 .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-mDyrIjRyzE7Ta0B7 .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-mDyrIjRyzE7Ta0B7 .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-mDyrIjRyzE7Ta0B7 .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-mDyrIjRyzE7Ta0B7 .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-mDyrIjRyzE7Ta0B7 .marker{fill:#333333;stroke:#333333;}#mermaid-svg-mDyrIjRyzE7Ta0B7 .marker.cross{stroke:#333333;}#mermaid-svg-mDyrIjRyzE7Ta0B7 svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-mDyrIjRyzE7Ta0B7 p{margin:0;}#mermaid-svg-mDyrIjRyzE7Ta0B7 .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-mDyrIjRyzE7Ta0B7 .cluster-label text{fill:#333;}#mermaid-svg-mDyrIjRyzE7Ta0B7 .cluster-label span{color:#333;}#mermaid-svg-mDyrIjRyzE7Ta0B7 .cluster-label span p{background-color:transparent;}#mermaid-svg-mDyrIjRyzE7Ta0B7 .label text,#mermaid-svg-mDyrIjRyzE7Ta0B7 span{fill:#333;color:#333;}#mermaid-svg-mDyrIjRyzE7Ta0B7 .node rect,#mermaid-svg-mDyrIjRyzE7Ta0B7 .node circle,#mermaid-svg-mDyrIjRyzE7Ta0B7 .node ellipse,#mermaid-svg-mDyrIjRyzE7Ta0B7 .node polygon,#mermaid-svg-mDyrIjRyzE7Ta0B7 .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-mDyrIjRyzE7Ta0B7 .rough-node .label text,#mermaid-svg-mDyrIjRyzE7Ta0B7 .node .label text,#mermaid-svg-mDyrIjRyzE7Ta0B7 .image-shape .label,#mermaid-svg-mDyrIjRyzE7Ta0B7 .icon-shape .label{text-anchor:middle;}#mermaid-svg-mDyrIjRyzE7Ta0B7 .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-mDyrIjRyzE7Ta0B7 .rough-node .label,#mermaid-svg-mDyrIjRyzE7Ta0B7 .node .label,#mermaid-svg-mDyrIjRyzE7Ta0B7 .image-shape .label,#mermaid-svg-mDyrIjRyzE7Ta0B7 .icon-shape .label{text-align:center;}#mermaid-svg-mDyrIjRyzE7Ta0B7 .node.clickable{cursor:pointer;}#mermaid-svg-mDyrIjRyzE7Ta0B7 .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-mDyrIjRyzE7Ta0B7 .arrowheadPath{fill:#333333;}#mermaid-svg-mDyrIjRyzE7Ta0B7 .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-mDyrIjRyzE7Ta0B7 .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-mDyrIjRyzE7Ta0B7 .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-mDyrIjRyzE7Ta0B7 .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-mDyrIjRyzE7Ta0B7 .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-mDyrIjRyzE7Ta0B7 .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-mDyrIjRyzE7Ta0B7 .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-mDyrIjRyzE7Ta0B7 .cluster text{fill:#333;}#mermaid-svg-mDyrIjRyzE7Ta0B7 .cluster span{color:#333;}#mermaid-svg-mDyrIjRyzE7Ta0B7 div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-mDyrIjRyzE7Ta0B7 .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-mDyrIjRyzE7Ta0B7 rect.text{fill:none;stroke-width:0;}#mermaid-svg-mDyrIjRyzE7Ta0B7 .icon-shape,#mermaid-svg-mDyrIjRyzE7Ta0B7 .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-mDyrIjRyzE7Ta0B7 .icon-shape p,#mermaid-svg-mDyrIjRyzE7Ta0B7 .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-mDyrIjRyzE7Ta0B7 .icon-shape .label rect,#mermaid-svg-mDyrIjRyzE7Ta0B7 .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-mDyrIjRyzE7Ta0B7 .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-mDyrIjRyzE7Ta0B7 .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-mDyrIjRyzE7Ta0B7 :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 是
否
表达式1:初始化
表达式2:判断
==0?
结束
执行循环语句
表达式3:调整
首先执行表达式1初始化循环变量,接下来执行表达式2的判断部分。表达式2的结果如果==0,则循环结束;表达式2的结果如果!=0则执行循环语句,循环语句执行完后,再去执行表达式3,调整循环变量,然后再去表达式2的地方执行判断,决定循环是否继续。
整个循环的过程中,表达式1初始化部分只被执行1次,剩下的就是表达式2、循环语句、表达式3在循环。
8.3 for循环的实践
练习:在屏幕上打印1~10的值
c
#include <stdio.h>
int main()
{
int i = 0;
for(i = 1; i <= 10; i++)
{
printf("%d ", i);
}
return 0;
}
8.4 while循环和for循环的对比
for 和 while 在实现循环的过程中都有初始化、判断、调整这三个部分,但是 for 循环的三个部分非常集中,便于代码的维护,而如果代码较多的时候 while 循环的三个部分就比较分散,所以从形式上 for 循环要更优一些。
8.5 练习:计算1~100之间3的倍数的数字之和
c
// 方法1
#include <stdio.h>
int main()
{
int i = 0;
int sum = 0;
for(i = 1; i <= 100; i++)
{
if(i % 3 == 0)
sum += i;
}
printf("%d\n", sum);
return 0;
}
// 方法2(优化版:直接产生3的倍数,省去多余循环和判断)
#include <stdio.h>
int main()
{
int i = 0;
int sum = 0;
for(i = 3; i <= 100; i += 3)
{
sum += i;
}
printf("%d\n", sum);
return 0;
}
🔄 9. do-while 循环
9.1 语法形式
在循环语句中 do while 语句的使用最少,它的语法如下:
c
do
语句;
while(表达式);
while 和 for 这两种循环都是先判断,条件如果满足就进入循环,执行循环语句,如果不满足就跳出循环;而 do while 循环则是先直接进入循环体,执行循环语句 ,然后再执行 while 后的判断表达式,表达式为真,就会进行下一次,表达式为假,则不再继续循环。
9.2 do-while循环的执行流程
#mermaid-svg-4Jq0vxd5Z24JYehe{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-4Jq0vxd5Z24JYehe .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-4Jq0vxd5Z24JYehe .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-4Jq0vxd5Z24JYehe .error-icon{fill:#552222;}#mermaid-svg-4Jq0vxd5Z24JYehe .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-4Jq0vxd5Z24JYehe .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-4Jq0vxd5Z24JYehe .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-4Jq0vxd5Z24JYehe .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-4Jq0vxd5Z24JYehe .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-4Jq0vxd5Z24JYehe .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-4Jq0vxd5Z24JYehe .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-4Jq0vxd5Z24JYehe .marker{fill:#333333;stroke:#333333;}#mermaid-svg-4Jq0vxd5Z24JYehe .marker.cross{stroke:#333333;}#mermaid-svg-4Jq0vxd5Z24JYehe svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-4Jq0vxd5Z24JYehe p{margin:0;}#mermaid-svg-4Jq0vxd5Z24JYehe .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-4Jq0vxd5Z24JYehe .cluster-label text{fill:#333;}#mermaid-svg-4Jq0vxd5Z24JYehe .cluster-label span{color:#333;}#mermaid-svg-4Jq0vxd5Z24JYehe .cluster-label span p{background-color:transparent;}#mermaid-svg-4Jq0vxd5Z24JYehe .label text,#mermaid-svg-4Jq0vxd5Z24JYehe span{fill:#333;color:#333;}#mermaid-svg-4Jq0vxd5Z24JYehe .node rect,#mermaid-svg-4Jq0vxd5Z24JYehe .node circle,#mermaid-svg-4Jq0vxd5Z24JYehe .node ellipse,#mermaid-svg-4Jq0vxd5Z24JYehe .node polygon,#mermaid-svg-4Jq0vxd5Z24JYehe .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-4Jq0vxd5Z24JYehe .rough-node .label text,#mermaid-svg-4Jq0vxd5Z24JYehe .node .label text,#mermaid-svg-4Jq0vxd5Z24JYehe .image-shape .label,#mermaid-svg-4Jq0vxd5Z24JYehe .icon-shape .label{text-anchor:middle;}#mermaid-svg-4Jq0vxd5Z24JYehe .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-4Jq0vxd5Z24JYehe .rough-node .label,#mermaid-svg-4Jq0vxd5Z24JYehe .node .label,#mermaid-svg-4Jq0vxd5Z24JYehe .image-shape .label,#mermaid-svg-4Jq0vxd5Z24JYehe .icon-shape .label{text-align:center;}#mermaid-svg-4Jq0vxd5Z24JYehe .node.clickable{cursor:pointer;}#mermaid-svg-4Jq0vxd5Z24JYehe .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-4Jq0vxd5Z24JYehe .arrowheadPath{fill:#333333;}#mermaid-svg-4Jq0vxd5Z24JYehe .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-4Jq0vxd5Z24JYehe .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-4Jq0vxd5Z24JYehe .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-4Jq0vxd5Z24JYehe .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-4Jq0vxd5Z24JYehe .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-4Jq0vxd5Z24JYehe .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-4Jq0vxd5Z24JYehe .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-4Jq0vxd5Z24JYehe .cluster text{fill:#333;}#mermaid-svg-4Jq0vxd5Z24JYehe .cluster span{color:#333;}#mermaid-svg-4Jq0vxd5Z24JYehe div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-4Jq0vxd5Z24JYehe .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-4Jq0vxd5Z24JYehe rect.text{fill:none;stroke-width:0;}#mermaid-svg-4Jq0vxd5Z24JYehe .icon-shape,#mermaid-svg-4Jq0vxd5Z24JYehe .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-4Jq0vxd5Z24JYehe .icon-shape p,#mermaid-svg-4Jq0vxd5Z24JYehe .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-4Jq0vxd5Z24JYehe .icon-shape .label rect,#mermaid-svg-4Jq0vxd5Z24JYehe .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-4Jq0vxd5Z24JYehe .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-4Jq0vxd5Z24JYehe .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-4Jq0vxd5Z24JYehe :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 是
否
执行循环语句
判断表达式
!=0?
结束
在 do while 循环中先执行"语句",执行完语句,再去执行"判断表达式",判断表达式的结果是!=0,则继续循环;判断表达式的结果==0,则循环结束。所以 do while 语句中循环体至少执行一次。
9.3 do-while循环的实例
在屏幕上打印1~10的值
c
#include <stdio.h>
int main()
{
int i = 1;
do
{
printf("%d ", i);
i = i + 1;
} while(i <= 10);
return 0;
}
一般 do while 使用在循环体至少被执行一次的场景下,所以较少一些。
9.4 练习:计算整数的位数
题目: 输入一个正整数,计算这个整数是几位数?
例如:
- 输入:1234 → 输出:4
- 输入:12 → 输出:2
c
#include <stdio.h>
int main()
{
int n = 0;
scanf("%d", &n);
int cnt = 0;
do
{
cnt++;
n = n / 10;
} while(n);
printf("%d\n", cnt);
return 0;
}
这里并非必须使用 do while 语句,但是这个代码就比较适合使用 do while 循环,因为n即使是0,也是1位数,也要统计位数的。
⏹️ 10. break和continue语句
在循环执行的过程中,如果某些状况发生的时候,需要提前终止循环,这是非常常见的现象。C语言中提供了 break 和 continue 两个关键字。
break:用于永久地终止循环 ,只要break被执行,直接就会跳出循环,继续往后执行。continue:用于跳过本次循环 中continue后边的代码,在for循环和while循环中有所差异。
10.1 while循环中的break和continue
break举例:
c
#include <stdio.h>
int main()
{
int i = 1;
while(i <= 10)
{
if(i == 5)
break; // 当i等于5后,就执行break,循环就终止了
printf("%d ", i);
i = i + 1;
}
return 0;
}
执行结果:打印了1,2,3,4后,当i等于5的时候,循环在 break 的地方终止,不再打印,不再循环。
continue举例:
c
#include <stdio.h>
int main()
{
int i = 1;
while(i <= 10)
{
if(i == 5)
continue;
// 当i等于5后,就执行continue,直接跳过continue的代码,去循环的判断的地方
// 因为这里跳过了i = i+1,所以i一直为5,程序陷入了死循环
printf("%d ", i);
i = i + 1;
}
return 0;
}
💡 面试小贴士:while循环中continue容易造成死循环!因为continue跳过了后面的"i = i + 1"调整语句,导致i一直为5,永远无法递增。
10.2 for循环中的break和continue
break举例:
c
#include <stdio.h>
int main()
{
int i = 1;
for(i = 1; i <= 10; i++)
{
if(i == 5)
break;
printf("%d ", i);
}
return 0;
}
执行结果:1 2 3 4
continue举例:
c
#include <stdio.h>
int main()
{
int i = 1;
for(i = 1; i <= 10; i++)
{
if(i == 5)
continue; // 这里continue跳过了后边的打印,来到了i++的调整部分
printf("%d ", i);
}
return 0;
}
执行结果:1 2 3 4 6 7 8 9 10
💡 面试小贴士:for循环中的continue不会造成死循环,因为continue后会自动执行表达式3(i++)进行循环变量的调整。这是for循环相比while循环的一个优势。
10.3 while和for中continue的区别对比
| 循环类型 | continue行为 | 是否可能死循环 |
|---|---|---|
while |
跳过continue后的所有代码,包括循环变量调整 | ⚠️ 可能死循环 |
for |
跳过continue后的代码,但会执行表达式3(调整部分) | ✅ 不会死循环 |
10.4 do-while循环中的break和continue
do-while 语句中的 break 和 continue 的作用和 while 循环中几乎一模一样。
c
// break示例
#include <stdio.h>
int main()
{
int i = 1;
do
{
if(i == 5)
break;
printf("%d ", i);
i = i + 1;
} while(i <= 10);
return 0;
}
// continue示例
#include <stdio.h>
int main()
{
int i = 1;
do
{
if(i == 5)
continue;
printf("%d ", i);
i = i + 1;
} while(i <= 10);
return 0;
}
🔗 11. 循环的嵌套
前面学习了三种循环 while、do while、for,这三种循环往往会嵌套在一起才能更好的解决问题,这就是我们所说的:循环嵌套。
11.1 练习:找出100~200之间的素数
题目: 找出100~200之间的素数,并打印在屏幕上。
注:素数又称质数,只能被1和本身整除的数字。
题目解析:
- 要从100200之间找出素数,首先得有100200之间的数,这里可以使用循环解决
- 假设要判断i是否为素数,需要拿2i-1之间的数字去试除i,需要产生2i-1之间的数字,也可以使用循环解决
- 如果2~i-1之间有数字能整除i,则i不是素数,如果都不能整除,则i是素数
c
#include <stdio.h>
int main()
{
int i = 0;
// 循环产生100~200的数字
for(i = 100; i <= 200; i++)
{
// 判断i是否为素数
// 循环产生2~i-1之间的数字
int j = 0;
int flag = 1; // 假设i是素数
for(j = 2; j < i; j++)
{
if(i % j == 0)
{
flag = 0;
break;
}
}
if(flag == 1)
printf("%d ", i);
} return 0;
}
🏷️ 12. goto语句
C语言提供了一种非常特别的语法,就是 goto 语句和跳转标号,goto 语句可以实现在同一个函数内跳转到设置好的标号处。
c
#include <stdio.h>
int main()
{
printf("hehe\n");
goto next;
printf("haha\n");
next:
printf("跳过了haha的打印\n");
return 0;
}
12.1 goto语句的适用场景
goto 语句在现代编程中不推荐频繁使用 ,因为滥用 goto 会导致代码逻辑混乱、难以维护(即所谓的"面条式代码 ")。但在某些特定场景下,合理使用 goto 反而能让代码更清晰:
- 跳出多层嵌套循环 :当嵌套循环层数较多时,使用
break只能跳出当前一层循环,而goto可以一次性跳出多层 - 统一的错误处理:在函数中多个位置检测到错误后,跳转到统一的错误处理代码块
- 清理资源:在嵌入式或底层编程中,用于统一释放已分配的资源
12.2 实际应用:跳出多层嵌套循环
c
#include <stdio.h>
int main()
{
int i, j;
int found = 0;
for(i = 0; i < 10; i++)
{
for(j = 0; j < 10; j++)
{
if(i * j > 50)
{
goto found; // 找到目标,直接跳出两层循环
}
}
}
found:
printf("找到满足条件的组合:i = %d, j = %d, i*j = %d\n", i, j, i*j);
return 0;
}
如果不使用 goto,则需要借助额外的标志变量来实现:
c
#include <stdio.h>
int main()
{
int i, j;
int found = 0;
for(i = 0; i < 10 && !found; i++)
{
for(j = 0; j < 10 && !found; j++)
{
if(i * j > 50)
{
found = 1; // 设置标志,跳出循环
}
}
}
if(found)
printf("找到满足条件的组合:i = %d, j = %d, i*j = %d\n", i-1, j-1, (i-1)*(j-1));
return 0;
}
对比可见,使用 goto 的版本逻辑更直观,不需要额外的标志变量和复杂的循环条件判断。
12.3 实际应用:统一的错误处理
在底层编程或嵌入式开发中,经常需要分配多个资源,任何一个分配失败都需要清理已分配的资源:
c
#include <stdio.h>
#include <stdlib.h>
int main()
{
int *p1 = NULL;
int *p2 = NULL;
int *p3 = NULL;
// 分配资源
p1 = (int*)malloc(100 * sizeof(int));
if(p1 == NULL)
goto error;
p2 = (int*)malloc(100 * sizeof(int));
if(p2 == NULL)
goto error;
p3 = (int*)malloc(100 * sizeof(int));
if(p3 == NULL)
goto error;
// 正常使用资源
printf("所有资源分配成功!\n");
// 正常释放
free(p3);
free(p2);
free(p1);
return 0;
error:
// 统一的错误处理:释放已分配的资源
printf("内存分配失败,正在清理...\n");
if(p3) free(p3);
if(p2) free(p2);
if(p1) free(p1);
return 1;
}
💡 面试小贴士 :Linux内核源码中大量使用
goto进行错误处理,这是C语言中一种经典的"集中式错误处理 "模式。面试中可以说:合理使用goto进行错误处理是C语言的高级技巧。
12.4 使用注意事项
- 不能跨函数跳转 :
goto只能在同一个函数内部跳转,不能从一个函数跳转到另一个函数 - 不能跳入变量作用域 :
goto不能跳过一个变量的初始化语句进入其作用域 - 避免滥用 :不要用
goto替代正常的循环和分支结构 - 保持可读性:标号命名要有意义,跳转方向尽量向前(向下跳转),避免向后跳转造成循环
c
// ❌ 错误示例:跳过变量初始化
goto jump;
{
int x = 10; // 变量x的初始化被跳过了
jump:
printf("%d\n", x); // 未定义行为!
}
12.5 本章小结
| 知识点 | 说明 |
|---|---|
| 基本语法 | goto 标号; 配合 标号: 使用 |
| 主要用途 | 跳出多层循环、统一错误处理、资源清理 |
| 优点 | 在特定场景下让代码更清晰 |
| 缺点 | 滥用会导致"面条式代码",难以维护 |
| 建议 | 仅在必要时使用,优先考虑结构化编程方式 |
🎯 经典面试题
题目:以下代码的输出结果是什么?
c
#include <stdio.h>
int main()
{
int i = 0;
for(i = 0; i < 5; i++)
{
if(i == 2)
goto end;
printf("%d ", i);
}
end:
printf("循环结束,i = %d\n", i);
return 0;
}
答案: 0 1 循环结束,i = 2
解析: 当 i == 2 时,执行 goto end;,直接跳转到 end: 标号处,跳过了 i == 2 时的 printf 打印,也跳出了整个 for 循环。此时 i 的值保持为 2。
📌 总结:
goto语句是一把"双刃剑"------用得好可以简化特定场景的代码,用得不好则会让代码变得混乱不堪。在面试和实际开发中,建议优先使用结构化编程方式(循环、分支、函数),仅在跳出多层循环或统一错误处理等场景下谨慎使用goto。