三:条件判断与循环——if、for、while

一、回顾与本篇目标

上一篇你学会了 C 语言的变量声明、基本数据类型、格式化输入输出和运算符。你知道每个变量必须指定类型,知道了整数除法会丢掉小数部分,知道了 scanf 要加 & 符号。

这一篇我们要学的是控制流——让程序不再只是从上到下直线执行,而是能根据条件选择不同的路径,以及重复执行某段代码。这两个能力加在一起,你的程序就能处理几乎所有的逻辑了。

如果你已经会 JavaScript 或 Python,这一篇你会觉得非常熟悉——C 语言的条件判断和循环,和 JavaScript 几乎一模一样(它们都是从 C 语言借鉴的)。主要差异在语法细节上。

本篇的目标:

  1. 掌握 if/else if/else 条件判断
  2. 学会 switch 多分支选择
  3. 掌握 for 循环的经典三要素写法
  4. 学会 whiledo...while 循环
  5. 掌握 breakcontinue 的用法

二、条件判断: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 语言没有 truefalse 关键字(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;
}

执行顺序:

  1. 初始化int i = 1(只在循环开始时执行一次)
  2. 条件判断i <= 5(如果为真,执行循环体;如果为假,退出循环)
  3. 循环体printf(...)
  4. 更新i++(每次循环体执行完后执行)
  5. 回到步骤 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...whilewhile 的唯一区别是: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 + 1rand() 返回 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 后面要加分号。
  • breakcontinuebreak 退出整个循环,continue 跳过本轮继续下一轮。

C 语言的控制流和 JavaScript 有着共同的语法祖先,所以学起来应该很顺畅。下一篇,我们要学 C 语言中最独特也最重要的一种数据类型——数组。数组让你把多个相同类型的数据打包在一起,是后续学习指针和字符串的基础。

下一篇预告

下一篇——《数组——把相同类型的数据打包在一起》:一维数组的声明和初始化、如何遍历数组、数组和循环的配合、数组在内存中是如何存放的、数组越界的问题。同时对比 Python 的列表和 JavaScript 的数组,看看 C 的数组有什么独特的限制和优势。

C/C++ 零基础入门,每周更新。

© 版权声明
THE END
喜欢就支持一下吧
点赞8 分享
评论 抢沙发

请登录后发表评论

    暂无评论内容