【C语言】分支和循环

摘要 :分支让程序按条件选路,循环让它重复执行。本文从判断一个数的正负开始,先把关系、逻辑操作符和 if、switch 讲成一条选路链,再把 while、for、do-while 放进同一个重复任务里比较,最后用 break、continue、嵌套和 goto 处理循环中途的跳转,并集中列出常见错误。

文章目录

  • [1. 分支:让程序选路](#1. 分支:让程序选路)
    • [1.1 先判断一个数的正负](#1.1 先判断一个数的正负)
    • [1.2 条件怎么写:关系与逻辑操作符](#1.2 条件怎么写:关系与逻辑操作符)
    • [1.3 多分支:else if 与 switch](#1.3 多分支:else if 与 switch)
    • [1.4 条件操作符](#1.4 条件操作符)
  • [2. 循环:让程序重复](#2. 循环:让程序重复)
    • [2.1 while:先判断再执行](#2.1 while:先判断再执行)
    • [2.2 for:三部分写在一行](#2.2 for:三部分写在一行)
    • [2.3 do-while:至少执行一次](#2.3 do-while:至少执行一次)
    • [2.4 三种循环怎么选](#2.4 三种循环怎么选)
  • [3. 循环控制:中途退出与多层跳转](#3. 循环控制:中途退出与多层跳转)
    • [3.1 break 与 continue](#3.1 break 与 continue)
    • [3.2 嵌套循环](#3.2 嵌套循环)
    • [3.3 goto:一次跳出多层](#3.3 goto:一次跳出多层)
  • [4. 常见错误](#4. 常见错误)
  • [5. 小结](#5. 小结)

1. 分支:让程序选路

1.1 先判断一个数的正负

输入一个整数,输出它是正数、负数还是零。程序要分三种情况,用 if 的多分支写:

c 复制代码
#include <stdio.h>

int main(void)
{
    int n = 0;
    scanf("%d", &n);
    if (n > 0)
        printf("正数\n");
    else if (n < 0)
        printf("负数\n");
    else
        printf("零\n");
    return 0;
}

本文程序都在 VS2026 里新建 .c 文件编译。scanf 会触发 C4996,在文件第一行、任何 #include 之前加 #define _CRT_SECURE_NO_WARNINGS 1,后文代码块省略这一行。

依次输入 5、-3、0,输出:

text 复制代码
正数
负数
零

if 后面的括号里是条件表达式。条件按 0 为假、非 0 为真解释,if (n) 和 if (n != 0) 等价。

else if 链从上到下判断,只执行第一个成立的分支。条件要从严格写到宽松,顺序反了,后面的分支就轮不到。

比如按分数分档,先判 score >= 90,再判 score >= 60。如果把 >= 60 放在前面,95 分也会被归进「及格」。

if 和 else 默认只控制紧随其后的一条语句。下面这段代码里,第二行 printf 不受 if 控制,score 小于 60 时也会打印:

c 复制代码
if (score >= 60)
    printf("及格\n");
    printf("庆祝\n");   // 缩进看起来在 if 里,实际不是

要控制多条语句,用一对大括号把它们括成程序块。

else 与前面最近的、还没有配对的 if 结合,和缩进无关。看这段程序:

c 复制代码
#include <stdio.h>

int main(void)
{
    int a = 0;
    int b = 2;
    if (a == 1)
        if (b == 2)
            printf("hehe\n");
    else
        printf("haha\n");
    return 0;
}

运行结果是什么也不输出。else 配给了内层 if,结构变成外层 if 包住整个内层 if...else。

外层条件是 a == 1,a 是 0,不成立,内层没有机会执行。想让 else 配外层,给内层 if 加上大括号。

这个程序只用到分支。要继续处理多个学生、多次输入,还得让程序重复;要把条件组合起来、在多个固定值里选一个,也需要更多写法。后面按四类展开:

要做的事 语法
按条件选一条路 if / else if / switch / ?:
让一段代码重复 while / for / do-while
中途退出或跳过 break / continue
一次跳出多层 goto

先补条件本身的写法,再看多分支。

1.2 条件怎么写:关系与逻辑操作符

1.1 的 n > 0 用到了 >。关系操作符比较两个值,结果是 int 类型的 0 或 1:

操作符 含义 例子 结果
> 大于 20 > 12 1
>= 大于或等于 12 >= 12 1
< 小于 12 < 20 1
<= 小于或等于 20 <= 12 0
== 等于 12 == 20 0
!= 不等于 12 != 20 1

== 和 = 只差一个字符,作用完全不同。if (x = 3) 先把 3 赋给 x,表达式的值也是 3,条件恒真。

把常量写在左边 if (3 == x),误写成 = 时编译器会直接报错,因为 3 不能被赋值。

关系操作符也不能连写。18 <= age <= 36 先算 18 <= age 得到 0 或 1,再拿结果和 36 比,条件恒真:

c 复制代码
#include <stdio.h>

int main(void)
{
    int age = 0;
    scanf("%d", &age);
    if (18 <= age <= 36)
        printf("青年\n");
    return 0;
}

输入 10 也会打印「青年」。正确写法是两个比较用 && 连接:age >= 18 && age <= 36。

逻辑操作符把多个条件组合起来:

| 左操作数 | 右操作数 | && | || |
|------|------|------|------|
| 0 | 0 | 0 | 0 |
| 0 | 非 0 | 0 | 1 |
| 非 0 | 0 | 0 | 1 |
| 非 0 | 非 0 | 1 | 1 |

&& 和 || 从左向右求值,并且保证短路:&& 左边为 0 时,右边不再算;|| 左边非 0 时,右边不再算。

c 复制代码
#include <stdio.h>

int main(void)
{
    int a = 0;
    int b = 2;
    int d = 4;
    int i = a++ && ++b && d++;
    printf("i=%d a=%d b=%d d=%d\n", i, a, b, d);
    return 0;
}

输出:

text 复制代码
i=0 a=1 b=2 d=4

a++ 先取 0 参与判断,再把 a 加到 1。左边已经是 0,&& 直接短路,++b 和 d++ 都没有执行,i 得到 0。

把自增、赋值这类有副作用的操作写进条件,结果就依赖求值顺序,读代码时容易看错。条件里尽量只做比较,避免副作用。

闰年的规则是:能被 4 整除且不能被 100 整除,或者能被 400 整除。用逻辑操作符写成一个条件:

c 复制代码
#include <stdio.h>

int main(void)
{
    int year = 0;
    scanf("%d", &year);
    if ((year % 4 == 0 && year % 100 != 0) || year % 400 == 0)
        printf("%d 是闰年\n", year);
    else
        printf("%d 不是闰年\n", year);
    return 0;
}

输入 2024、1900、2000,依次输出:

text 复制代码
2024 是闰年
1900 不是闰年
2000 是闰年

&& 的优先级高于 ||,括号把两组条件分开,读起来也更清楚。

1.3 多分支:else if 与 switch

1.1 的分档用 else if 能写。如果判断的是「一个整型值等于若干固定常量中的哪一个」,switch 更直接。输入 1~7,判断工作日还是周末:

c 复制代码
#include <stdio.h>

int main(void)
{
    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;
}

输入 3 输出「工作日」,输入 6 输出「周末」,输入 9 走 default 输出「输入错误」。

case 1: 到 case 5: 后面没有语句,它们只是入口标签。匹配到其中任意一个,都会继续往下执行同一个 printf,直到遇到 break。

如果某个 case 末尾漏了 break,执行会继续进入下一个 case,这叫贯穿。下面这段输入 5 会连续打印两行:

c 复制代码
case 5:
    printf("工作日\n");
case 6:
    printf("周末\n");
    break;

有时会故意利用贯穿,让多个值共用一段代码;但每个分支结束时该不该写 break,要明确。

switch 后的表达式必须是整型,case 后必须是整型常量表达式。范围判断、浮点数和字符串比较都只能交给 if:

场景 选择
一个整型值等于若干固定常量之一 switch
范围判断,如 score >= 60 && score < 70 if
浮点数或字符串比较 if

default 的位置不限,通常放在最后;它后面漏了 break,同样会继续往下执行。

1.4 条件操作符

只根据一个条件在两个值里选一个,if...else 要写四行;条件操作符一行就够:

c 复制代码
exp1 ? exp2 : exp3

exp1 为真求 exp2,为假求 exp3,另一支不参与求值。

c 复制代码
#include <stdio.h>

int main(void)
{
    int a = 0;
    int b = 0;
    scanf("%d %d", &a, &b);
    int m = a > b ? a : b;
    printf("较大值:%d\n", m);
    return 0;
}

输入 3 7,输出 较大值:7。它本质上是表达式,可以直接写在 printf 里;嵌套超过两层就该换回 if。

2. 循环:让程序重复

判断一次只能处理一个输入。要打印 1 到 10、处理多个学生,或者一直猜到答案,都需要让同一段代码重复执行。

2.1 while:先判断再执行

while 先判断条件,条件为真才执行循环体,执行完再回到条件:

c 复制代码
#include <stdio.h>

int main(void)
{
    int i = 1;
    while (i <= 10)
    {
        printf("%d ", i);
        i++;
    }
    printf("\n");
    return 0;
}

输出 1 2 3 4 5 6 7 8 9 10。如果一开始条件就为假,循环体一次也不执行。

while (1) 是恒真条件,靠循环体里的 break 退出。普通 while 的条件写错时,也可能一直跑下去。

2.2 for:三部分写在一行

while 的初始化、判断、调整分散在三处,循环一长就容易漏掉调整。for 把三部分集中到一行:

c 复制代码
#include <stdio.h>

int main(void)
{
    for (int i = 1; i <= 10; i++)
        printf("%d ", i);
    printf("\n");
    return 0;
}

输出与 while 版相同。三部分按固定顺序执行:初始化只做一次;每次先判断,条件为真执行循环体,再执行调整,然后回到判断。

计数次数明确时用 for,三个部分集中,不容易漏掉调整。C99 起可以在初始化部分声明循环变量,i 只在循环内可见。

2.3 do-while:至少执行一次

输入一个整数,统计它是几位数。0 也是一位数,循环体必须先执行一次再判断。do-while 正好是先执行、后判断:

c 复制代码
#include <stdio.h>

int main(void)
{
    int n = 0;
    scanf("%d", &n);
    int count = 0;
    do
    {
        count++;
        n /= 10;
    } while (n != 0);
    printf("%d 位数\n", count);
    return 0;
}

输入 1234 输出 4 位数,输入 0 输出 1 位数。如果改成 while (n > 0),输入 0 时一次都不循环,位数会算成 0。

2.4 三种循环怎么选

三种循环的区别集中在判断位置:

循环 判断时机 最少执行次数 适合
while 循环体之前 0 次数未知,先看条件
for 循环体之前 0 次数已知或可计算
do-while 循环体之后 1 至少执行一次,如菜单、输入校验

for (;;) 与 while (1) 等价,都是恒真条件。

3. 循环控制:中途退出与多层跳转

循环不总是从头跑到尾:找到答案要提前结束,跳过某个值要继续下一轮,内层循环结束时外层可能也要停。

3.1 break 与 continue

break 立即结束它所在的那一层循环;continue 跳过本次循环剩下的语句,进入下一次。

for 里的 continue 跳到调整部分,i++ 仍会执行:

c 复制代码
#include <stdio.h>

int main(void)
{
    for (int i = 1; i <= 10; i++)
    {
        if (i == 5)
            continue;
        printf("%d ", i);
    }
    printf("\n");
    return 0;
}

输出 1 2 3 4 6 7 8 9 10,5 被跳过,循环继续。把 continue 换成 break,输出到 4 就停。

while 里的 continue 跳到条件判断。调整语句如果写在 continue 后面,就会被跳过:

c 复制代码
#include <stdio.h>

int main(void)
{
    int i = 1;
    while (i <= 10)
    {
        if (i == 5)
            continue;
        printf("%d ", i);
        i++;
    }
    return 0;
}

输出 1 2 3 4 后,i 停在 5,条件一直成立,程序卡住。运行这段代码需要手动停止。

要避免这种写法:把 i++ 放到 continue 之前,或者直接用 for。

循环 break continue 跳转
while 结束整个循环 条件判断
for 结束整个循环 调整表达式
do-while 结束整个循环 末尾的条件判断

两种跳转都只作用于最近的一层循环。

3.2 嵌套循环

判断 100~200 之间的素数需要两层循环:外层逐个取数,内层试除。

素数是只能被 1 和自身整除的大于 1 的整数。对每个 i,用 2 到 i-1 的数去试除;只要有一个能整除,i 就不是素数。

c 复制代码
#include <stdio.h>

int main(void)
{
    int count = 0;
    for (int i = 100; i <= 200; i++)
    {
        int is_prime = 1;
        for (int j = 2; j * j <= i; j++)
        {
            if (i % j == 0)
            {
                is_prime = 0;
                break;
            }
        }
        if (is_prime)
        {
            printf("%d ", i);
            count++;
        }
    }
    printf("\n共 %d 个\n", count);
    return 0;
}

内层发现因子后把 is_prime 置 0 并 break,这个 break 只退出内层;外层拿到标志,继续判断下一个 i。

试除只需要到 i \sqrt{i} i :如果 i 有一个大于 i \sqrt{i} i 的因子,必然对应一个小于 i \sqrt{i} i 的因子。代码写成 j * j <= i,不用引入 sqrt。

输出:

text 复制代码
101 103 107 109 113 127 131 137 139 149 151 157 163 167 173 179 181 191 193 197 199
共 21 个

共 21 个素数。每个 i 的试除次数从约 i 次降到约 i \sqrt{i} i 次。

3.3 goto:一次跳出多层

内层 break 只退一层。两层以上要连续 break,或者加一个标志变量让外层也停。goto 可以在同一个函数内跳到指定标号:

c 复制代码
#include <stdio.h>

int main(void)
{
    for (int i = 0; i < 3; i++)
    {
        for (int j = 0; j < 3; j++)
        {
            if (i == 1 && j == 1)
                goto found;
            printf("%d,%d\n", i, j);
        }
    }
found:
    printf("跳出两层循环\n");
    return 0;
}

输出:

text 复制代码
0,0
0,1
0,2
1,0
跳出两层循环

当 i == 1 && j == 1 时,goto found 一次跳出两层循环。用 break 只能退出内层,还得在外层再加判断。

goto 也能用于统一错误处理,但跳转范围太自由,容易把流程打乱。除了从多层嵌套中退出,其他场景优先用循环条件和 break。

4. 常见错误

前面各节的错误集中在这里,写完循环和分支后可以对着查:

症状 原因 改法
if (x = 3) 条件总成立 把 == 写成 = 比较用 ==;常量放左边
18 <= age <= 36 对 10 岁也成立 关系操作符连写,先算成 0/1 写成 age >= 18 && age <= 36
else 配错 if 只看缩进,没看配对规则 给内层 if 加大括号
switch 执行了下一个分支 漏写 break 每个分支末尾检查 break
while 里 continue 后卡死 调整语句写在 continue 后面 调整放前面,或改用 for
内层 break 后外层还在跑 break 只退一层 用标志变量或 goto
循环多打印或少打印一次 边界写成 < 还是 <= 没核对 用 1~10 的小范围先验证边界

5. 小结

  • 0 为假,非 0 为真;if / else if / else 只执行第一个成立的分支,else 与最近的未配对 if 结合。
  • 关系操作符的结果是 0 或 1,不能连写;== 不是 =。
  • &&、|| 会短路,右侧可能不执行;结果只有 0 和 1。
  • switch 只做整型等值匹配;case 是入口标签,漏写 break 会贯穿。
  • while、for 先判断,do-while 至少执行一次;for 的三部分最集中。
  • break 结束最近一层循环;continue 在 while 中跳到判断,在 for 中跳到调整。
  • 嵌套循环要退多层时,用标志变量或 goto;常见错误先查第 4 节的表。
相关推荐
Fuyo_11192 小时前
C++ AVL树保姆级详解:从平衡因子到四大旋转机制
java·c++·算法
jktantan3 小时前
每个节点 41 字节:把一棵百万节点树拆进 14 个 typed array
前端·javascript·vue.js·算法·typescript
揽星河..3 小时前
【C语言】猜数字游戏
c语言·算法·游戏
傲世仙尊4 小时前
继承-类设计层次复用切片转换与菱形继承的死结
c++
架构师伯子明4 小时前
FFmpeg C++学习(一):编译和demo
开发语言·c++·学习
LabVIEW开发4 小时前
CTM-3 红外测温仪 + LabVIEW 温度怎么测?
算法·labview·测试·labview程序
纪念 2294 小时前
C++算法(六)
开发语言·c++·算法
ShineWinsu4 小时前
对于Qt:QCheckBox常见属性的详细解析
c++·qt·面试·笔试·gui·qcheckbox·多选框
Dumbness5 小时前
UIA 读微信群消息没有 id,怎么判断哪条是新的:后缀对齐在翻历史和撤回时整屏重报
python·算法