一、回顾与本篇目标
上一篇你学会了 C 语言的变量声明、基本数据类型、格式化输入输出和运算符。你知道每个变量必须指定类型,知道了整数除法会丢掉小数部分,知道了 scanf 要加 & 符号。
这一篇我们要学的是控制流——让程序不再只是从上到下直线执行,而是能根据条件选择不同的路径,以及重复执行某段代码。这两个能力加在一起,你的程序就能处理几乎所有的逻辑了。
如果你已经会 JavaScript 或 Python,这一篇你会觉得非常熟悉——C 语言的条件判断和循环,和 JavaScript 几乎一模一样(它们都是从 C 语言借鉴的)。主要差异在语法细节上。
本篇的目标:
- 掌握
if/else if/else条件判断 - 学会
switch多分支选择 - 掌握
for循环的经典三要素写法 - 学会
while和do...while循环 - 掌握
break和continue的用法
二、条件判断:if/else if/else
C 语言的条件判断和 JavaScript 的语法几乎完全相同——条件用括号包裹,代码块用花括号。
基本结构
if (条件) {
// 条件成立时执行
} else if (另一个条件) {
// 第一个条件不成立,但第二个条件成立时执行
} else {
// 所有条件都不成立时执行
}
和 JavaScript/Python 的对比
// JavaScript(和 C 几乎一模一样)
if (score >= 90) {
printf("优秀\n");
} else if (score >= 60) {
printf("及格\n");
} else {
printf("不及格\n");
}
# Python(差异较大)
if score >= 90:
print("优秀")
elif score >= 60:
print("及格")
else:
print("不及格")
C 和 JavaScript 条件判断的三个共同点:
- 条件用括号
()包裹。 - 代码块用花括号
{}包裹。 - 多分支用
else if(两个单词),而不是 Python 的elif。
完整示例:成绩判断
#include <stdio.h>
int main() {
int score;
printf("请输入你的成绩(0-100):");
scanf("%d", &score);
if (score >= 90) {
printf("优秀!\n");
} else if (score >= 80) {
printf("良好\n");
} else if (score >= 70) {
printf("中等\n");
} else if (score >= 60) {
printf("及格\n");
} else {
printf("不及格,继续加油!\n");
}
return 0;
}
C 语言中“真”和“假”的定义
C 语言没有 true 和 false 关键字(C99 之后可以通过 stdbool.h 使用)。在 C 中:
- 0 表示假
- 非 0 表示真(1、-1、100 都算真)
if (0) {
printf("这行不会执行\n");
}
if (42) {
printf("这行会执行,因为 42 非 0\n");
}
if (-1) {
printf("这行也会执行,-1 也非 0\n");
}
比较表达式的结果是 1(真)或 0(假):
int result = (10 > 5);
printf("%d\n", result); // 输出 1
result = (10 < 5);
printf("%d\n", result); // 输出 0
连续比较:C 和 Python 的区别
Python 支持连续比较:
# Python
if 0 < x < 10:
print("x 在 0 和 10 之间")
C 语言不支持这种写法。0 < x < 10 在 C 中会被解析为 (0 < x) < 10。先计算 (0 < x),得到 0 或 1,再和 10 比较——结果永远是 1(真),因为 0 和 1 都小于 10。这是一个隐蔽的 bug。正确写法:
// C:必须分开写
if (x > 0 && x < 10) {
printf("x 在 0 和 10 之间\n");
}
if 语句的简写
如果代码块只有一行语句,花括号可以省略:
if (score >= 60)
printf("及格了\n");
else
printf("不及格\n");
但强烈建议始终使用花括号。省略花括号容易导致悬空 else 问题:
// 你以为 else 属于外层 if,实际上它属于内层 if
if (a > 0)
if (b > 0)
printf("a 和 b 都大于 0\n");
else
printf("a 不大于 0\n"); // 实际:当 b <= 0 时执行!
始终加花括号就可以避免这个问题:
if (a > 0) {
if (b > 0) {
printf("a 和 b 都大于 0\n");
}
} else {
printf("a 不大于 0\n");
}
三元运算符
C 语言有三元运算符,和 JavaScript 完全一样:
int age = 20;
char* status = (age >= 18) ? "成年" : "未成年";
printf("%s\n", status); // 成年
三、switch:多分支选择
当需要根据一个变量的不同值来执行不同代码时,用 switch 比写一长串 if...else if 更清晰。
基本语法
switch (表达式) {
case 值1:
// 当表达式等于值1时执行
break;
case 值2:
// 当表达式等于值2时执行
break;
default:
// 所有 case 都不匹配时执行
break;
}
完整示例
#include <stdio.h>
int main() {
int day;
printf("请输入星期几(1-7):");
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;
default:
printf("输入有误,请输入 1-7\n");
break;
}
return 0;
}
break 不能省略!
这是 C 语言 switch 最独特的特性:如果 case 后面没有 break,程序会继续执行下一个 case 的代码。这叫“穿透”。这不是 bug,而是设计特性——有时候正好需要多个 case 共享同一段处理逻辑:
switch (day) {
case 1:
case 2:
case 3:
case 4:
case 5:
printf("工作日,要上班\n");
break;
case 6:
case 7:
printf("周末,休息!\n");
break;
}
上面的代码中,day 是 1、2、3、4、5 都会执行“工作日”那条 printf,因为前四个 case 没有 break,会穿透到 case 5 的代码。
注意:忘记写 break 是 C 初学者最常见的 bug 之一。如果你发现 switch 执行了不该执行的代码,先检查是不是漏了 break。
switch 的限制
- 表达式必须是整数类型(int、char、enum)。不能是浮点数、字符串。
- case 后面的值必须是常量,不能是变量。
- 如果分支逻辑复杂,用 if/else 更合适。switch 适合“一个变量等于几个固定值”的场景。
四、for 循环
C 语言的 for 循环和 JavaScript 的 for 循环完全一样——括号里用分号分隔三个表达式:初始化、条件、更新。
基本语法
for (初始化; 条件; 更新) {
// 循环体
}
完整示例
#include <stdio.h>
int main() {
// 打印 1 到 5
for (int i = 1; i <= 5; i++) {
printf("第 %d 次循环\n", i);
}
return 0;
}
执行顺序:
- 初始化:
int i = 1(只在循环开始时执行一次) - 条件判断:
i <= 5(如果为真,执行循环体;如果为假,退出循环) - 循环体:
printf(...) - 更新:
i++(每次循环体执行完后执行) - 回到步骤 2,重复
和 Python for 的区别
Python 的 for 是“遍历循环”——遍历列表、字符串、range:
# Python
for i in range(1, 6):
print(f"第 {i} 次循环")
C 的 for 是“计数循环”——你手动控制初始值、终止条件、步长。C 的 for 比 Python 的 for 更灵活(因为你可以自由控制三个表达式),但写起来也稍微繁琐一点。
for 循环的变体
省略某些部分:
// 初始化放在外面
int i = 0;
for (; i < 5; i++) {
printf("%d\n", i);
}
// 更新放在循环体里
for (int i = 0; i < 5;) {
printf("%d\n", i);
i++;
}
// 无限循环(三个部分全省略)
for (;;) {
printf("无限循环\n");
break; // 用 break 退出
}
在 for 循环中声明变量:
C99 标准允许在 for 的初始化部分声明变量(如 for (int i = 0; ...))。这个变量的作用域仅限于循环内部,循环结束后就不能用了。
for (int i = 0; i < 5; i++) {
printf("%d\n", i);
}
// printf("%d\n", i); // 编译错误!i 已经不存在了
如果你使用的是较老的编译器(或者编译时指定了 C89 标准),可能不支持这种写法。遇到报错时,把变量声明移到循环外面即可。
五、while 循环
while 循环的逻辑是:先判断条件,条件成立则执行循环体,然后再次判断条件,直到条件不成立。
基本语法
while (条件) {
// 循环体
}
完整示例
#include <stdio.h>
int main() {
int count = 1;
while (count <= 5) {
printf("第 %d 次循环\n", count);
count++;
}
printf("循环结束,count = %d\n", count); // count = 6
return 0;
}
while 和 for 怎么选?
- 知道循环次数(比如遍历 0 到 9、遍历数组所有元素)→ 用
for。 - 不知道循环次数(比如让用户一直输入直到输入正确)→ 用
while。
经典 while 示例:密码验证
#include <stdio.h>
int main() {
int password = 123456;
int input;
printf("请输入密码:");
scanf("%d", &input);
while (input != password) {
printf("密码错误,请重试:");
scanf("%d", &input);
}
printf("密码正确,登录成功!\n");
return 0;
}
六、do…while 循环
do...while 和 while 的唯一区别是:do…while 先执行一次循环体,再判断条件。 这意味着循环体至少会被执行一次。
基本语法
do {
// 循环体
} while (条件); // 注意:这里有一个分号!
完整示例
#include <stdio.h>
int main() {
int number;
do {
printf("请输入一个正数(输入 0 退出):");
scanf("%d", &number);
printf("你输入了:%d\n", number);
} while (number != 0);
printf("程序结束\n");
return 0;
}
不管用户输入什么,循环体至少执行一次(打印出输入的值),然后才判断是否退出。
注意:while (条件) 后面有一个分号。这是 do...while 语法的一部分,忘记写分号会导致编译错误。
七、break 和 continue
这两个关键字用来在循环体内部控制循环的执行流程。
break:立即退出整个循环
// 找到第一个能被 7 整除的数就停止
for (int i = 1; i <= 50; i++) {
if (i % 7 == 0) {
printf("找到了:%d\n", i);
break; // 退出循环,后面的 8 到 50 都不会执行
}
}
break 只能退出一层循环。如果是嵌套循环,break 只退出最内层的那个循环。
continue:跳过本轮循环,继续下一轮
// 只打印奇数
for (int i = 1; i <= 10; i++) {
if (i % 2 == 0) {
continue; // 跳过偶数,不执行后面的 printf
}
printf("%d\n", i);
}
输出:1 3 5 7 9
break 和 continue 的作用范围
| break | continue | |
|---|---|---|
| for 循环 | 退出整个循环 | 跳到更新部分(如 i++),然后判断条件 |
| while 循环 | 退出整个循环 | 跳回条件判断 |
| switch 语句 | 退出 switch | 不能用(只在循环中有效) |
八、嵌套循环
一个循环内部可以再放一个循环。最常见的例子是打印乘法口诀表:
#include <stdio.h>
int main() {
// 外层循环控制行
for (int i = 1; i <= 9; i++) {
// 内层循环控制列
for (int j = 1; j <= i; j++) {
printf("%d×%d=%d\t", j, i, i * j);
}
printf("\n"); // 每行结束后换行
}
return 0;
}
输出:
1×1=1
1×2=2 2×2=4
1×3=3 2×3=6 3×3=9
...
1×9=9 2×9=18 3×9=27 4×9=36 5×9=45 6×9=54 7×9=63 8×9=72 9×9=81
\t 是制表符(Tab),让列之间对齐。
九、综合演示:猜数字游戏
下面这段代码综合运用了循环、条件判断、随机数:
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
int main() {
// 用当前时间作为随机数种子
srand(time(NULL));
// 生成 1 到 100 之间的随机数
int secret = rand() % 100 + 1;
int guess = 0;
int attempts = 0;
printf("===== 猜数字游戏 =====\n");
printf("我想了一个 1 到 100 之间的数字,你猜猜看?\n");
while (guess != secret) {
printf("请输入你猜的数字:");
scanf("%d", &guess);
attempts++;
if (guess > secret) {
printf("太大了,再小一点\n");
} else if (guess < secret) {
printf("太小了,再大一点\n");
} else {
printf("恭喜!你猜对了,答案就是 %d\n", secret);
printf("你一共猜了 %d 次\n", attempts);
}
}
return 0;
}
代码解释:
#include <stdlib.h>:引入rand()和srand()函数。#include <time.h>:引入time()函数。srand(time(NULL)):用当前时间作为随机数种子,保证每次运行程序产生不同的随机数。不写这行的话,每次运行随机数都一样。rand() % 100 + 1:rand()返回 0 到RAND_MAX(至少 32767)的随机整数。取余 100 得到 0 到 99,再加 1 得到 1 到 100。
十、本篇动手练习
练习 1:判断素数
新建 practice3-1.c,让用户输入一个正整数,判断它是不是素数(只能被 1 和自身整除的数)。用 for 循环检查 2 到该数的平方根之间是否有因子。
练习 2:斐波那契数列
新建 practice3-2.c,用循环输出前 20 个斐波那契数列的值(0, 1, 1, 2, 3, 5, 8, 13, …)。每个数等于前两个数之和。
练习 3:数字反转
新建 practice3-3.c,让用户输入一个整数,用 while 循环把这个数反转输出。例如输入 12345,输出 54321。提示:每次用取余拿到最后一位,累加到结果变量上。
练习 4:打印菱形
新建 practice3-4.c,让用户输入一个奇数 n,用嵌套 for 循环打印一个由星号组成的菱形图案,宽度为 n。例如 n=5:
*
***
*****
***
*
十一、本篇小结
这一篇你学会了 C 语言的控制流——条件判断和循环:
if/else if/else:和 JavaScript 语法几乎一样。条件用括号包裹,代码块用花括号。连续比较必须用&&连接,不能像 Python 那样写成0 < x < 10。switch/case:多分支选择,每个 case 后面需要break,否则会穿透到下一个 case。只能处理整数类型。for循环:三要素(初始化、条件、更新)用分号分隔。和 JavaScript 完全一样。C99 允许在初始化部分声明变量。while循环:先判断条件再执行。适合不知道循环次数的场景。do...while循环:先执行一次再判断。循环体至少执行一次。while后面要加分号。break和continue:break退出整个循环,continue跳过本轮继续下一轮。
C 语言的控制流和 JavaScript 有着共同的语法祖先,所以学起来应该很顺畅。下一篇,我们要学 C 语言中最独特也最重要的一种数据类型——数组。数组让你把多个相同类型的数据打包在一起,是后续学习指针和字符串的基础。
下一篇预告
下一篇——《数组——把相同类型的数据打包在一起》:一维数组的声明和初始化、如何遍历数组、数组和循环的配合、数组在内存中是如何存放的、数组越界的问题。同时对比 Python 的列表和 JavaScript 的数组,看看 C 的数组有什么独特的限制和优势。
C/C++ 零基础入门,每周更新。












暂无评论内容