【C 语言】分支、循环和 goto 语句(附实战)

写 C 程序时,我们经常要回答两类问题:接下来执行哪段代码?一段代码要重复多少次?前者要用分支,后者要用循环。本文从基本语法讲起,最后写一个成绩统计程序。

0. 语句

C 程序由一条条语句组成,大多数简单语句以分号结束:

c 复制代码
int score = 90;
printf("score = %d\n", score);

下面会用到 ifswitchforwhiledo while,最后再单独讲 goto。花括号包住的一组语句叫语句块。C 允许在只有一条语句时省略花括号,但刚开始学习时最好不要省,少写两个符号换来的往往是更难排查的错误。

1. 分支语句

C 语言没有要求条件表达式必须等于 truefalse:结果为 0 就是假,非 0 就是真。

1.1 if

c 复制代码
if (条件) {
    /* 条件为真时执行 */
} else {
    /* 条件为假时执行 */
}

多重分支示例:

c 复制代码
if (score >= 90) {
    printf("优秀\n");
} else if (score >= 60) {
    printf("及格\n");
} else {
    printf("不及格\n");
}

这些条件从上往下判断,遇到第一个成立的条件就停下来。这里最容易写错的是等号:= 表示赋值,== 才表示比较。需要同时判断多个条件时,可以用 &&(并且)或 ||(或者)连接。

1.2 switch

如果只是让一个值与几个固定选项比较,switch 通常比一长串 else if 更好读:

c 复制代码
switch (choice) {
case 1:
    printf("开始游戏\n");
    break;
case 2:
    printf("查看帮助\n");
    break;
default:
    printf("无效选项\n");
    break;
}

break 用于结束当前 switch。忘记它会继续执行下一个 case,称为"贯穿"。下面的程序故意省略第一个 break

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

int main(void) {
    int choice = 1;
    switch (choice) {
    case 1:
        printf("选择了 1\n");
        /* 没有 break,会继续执行 case 2 */
    case 2:
        printf("执行了 case 2\n");
        break;
    default:
        printf("无效选项\n");
    }
    return 0;
}

运行结果:

复制代码
选择了 1
执行了 case 2

如果不是有意让代码贯穿到下一个分支,就要在 case 末尾写 breakswitch 常用于整数、字符和枚举,不能直接拿来比较字符串或浮点数。

2. 循环语句

写循环时要看清三件事:从哪里开始、什么时候停、每轮怎样更新。第三项很容易漏掉。一旦条件永远无法变成假,程序就会一直循环。

2.1 for

已经知道大概要循环多少次时,常用 for

c 复制代码
for (初始化; 条件; 更新) {
    /* 循环体 */
}
c 复制代码
for (int i = 1; i <= 5; i++) {
    printf("%d\n", i);
}

运行结果:

复制代码
1
2
3
4
5

2.2 while

如果事先不知道要循环多少次,只知道"条件成立就继续",可以用 while

c 复制代码
int number;
scanf("%d", &number);
while (number >= 0) {
    printf("输入了 %d\n", number);
    scanf("%d", &number);
}

例如依次输入 31-1,运行结果为:

复制代码
输入了 3
输入了 1

2.3 do while

do while 把判断放在循环体之后,所以循环体至少会执行一次:

c 复制代码
do {
    printf("1. 开始  0. 退出\n");
    scanf("%d", &choice);
} while (choice != 0);

例如输入 1 后输入 0,菜单会显示两次:

复制代码
1. 开始  0. 退出
1
1. 开始  0. 退出
0

注意末尾分号不能省略。

break 会立刻结束它所在的循环。比如查找第一个能被 7 整除的数,找到之后便可以停下:

c 复制代码
for (int i = 1; i <= 100; i++) {
    if (i % 7 == 0) {
        printf("第一个能被 7 整除的数是:%d\n", i);
        break;
    }
}

运行结果:

复制代码
第一个能被 7 整除的数是:7

continue 不会结束整个循环,它只跳过本轮剩下的代码。下面的程序借此跳过偶数,只打印 1 到 10 中的奇数:

c 复制代码
for (int i = 1; i <= 10; i++) {
    if (i % 2 == 0) {
        continue; // 偶数跳过,不执行下面的 printf
    }
    printf("%d ", i); // 输出:1 3 5 7 9
}
printf("\n");

运行结果:

复制代码
1 3 5 7 9

简单说,break 是"不再循环",continue 是"这一轮先算了"。在 while 循环里使用 continue 时尤其要小心:如果它把变量更新也跳过去了,循环可能永远停不下来。

3. goto 语句

goto 无条件跳转到同一个函数中的标签:

c 复制代码
goto end;
printf("不会执行\n");
end:
printf("程序结束\n");

运行结果:

复制代码
程序结束

标签的写法是"名字 + 冒号",而且 goto 只能跳到当前函数里的标签。实际项目偶尔会用它集中处理资源释放,但大量跳转会把执行顺序弄得很难追踪。初学阶段,能用循环或条件语句表达的逻辑,就不必用 goto

4. 综合实战:成绩统计菜单

现在把前面的语句放进一个完整程序。它先读取学生成绩,然后通过菜单查看所有成绩、平均分和等级统计。

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

#define MAX 100

int main(void) {
    int scores[MAX], count, choice;
    printf("学生人数(1-%d):", MAX);
    if (scanf("%d", &count) != 1 || count < 1 || count > MAX) {
        printf("人数无效\n");
        return 1;
    }

    for (int i = 0; i < count; i++) {
        printf("第 %d 位成绩(0-100):", i + 1);
        if (scanf("%d", &scores[i]) != 1 || scores[i] < 0 || scores[i] > 100) {
            printf("成绩无效\n");
            return 1;
        }
    }

    do {
        printf("\n1. 所有成绩  2. 平均分  3. 等级统计  0. 退出\n请选择:");
        scanf("%d", &choice);
        switch (choice) {
        case 1:
            for (int i = 0; i < count; i++) {
                printf("第 %d 位:%d 分\n", i + 1, scores[i]);
            }
            break;
        case 2: {
            int sum = 0;
            for (int i = 0; i < count; i++) sum += scores[i];
            printf("平均分:%.2f\n", (double)sum / count);
            break;
        }
        case 3: {
            int excellent = 0, pass = 0, fail = 0;
            for (int i = 0; i < count; i++) {
                if (scores[i] >= 90) excellent++;
                else if (scores[i] >= 60) pass++;
                else fail++;
            }
            printf("优秀:%d 人,及格:%d 人,不及格:%d 人\n",
                   excellent, pass, fail);
            break;
        }
        case 0:
            printf("程序结束\n");
            break;
        default:
            printf("无效选项\n");
        }
    } while (choice != 0);
    return 0;
}

代码逐段解释

#include <stdio.h> 引入标准输入输出功能,程序里的 printfscanf 都来自这个头文件。#define MAX 100 定义了一个符号常量,编译前代码中的 MAX 会被替换成 100

int scores[MAX], count, choice; 定义了一个整数数组 scores,最多保存 100 个成绩;count 保存学生人数,choice 保存菜单选项。数组下标从 0 开始,因此第一个成绩是 scores[0]

初学者重点:scanf&

scanf("%d", &count); 从键盘读取一个整数,再把它存进 count。其中,%d 是整数的格式说明符;&count 是变量 count 的内存地址。

为什么这里有一个 &?因为 scanf 需要找到 count 所在的位置,才能把用户输入写进去。printf("%d", count) 只读取 count 的值,所以不需要取地址。

scanf 还会返回成功读到的数据个数。这里仅有一个 %d,返回 1 代表读取成功,返回 0 则说明输入的不是整数。因此,scanf("%d", &count) != 1 检查的正是输入格式。读取成绩时写成 &scores[i],因为这次要把数值存进数组的第 i 个元素。

for (int i = 0; i < count; i++) 会执行 count 次,依次读取所有成绩。提示中使用 i + 1 是为了显示"第 1 位",但数组仍使用从 0 开始的下标。

菜单至少要出现一次,所以这里用了 do...while。用户输入 0 后,choice != 0 为假,循环随即结束。switch (choice) 负责把不同选项分派到对应的 case,末尾的 break 则阻止程序继续落入下一个分支。

计算平均分时不能直接写 sum / count,因为两个整数相除会丢掉小数部分。(double)sum 先把 sum 临时转换成浮点数,计算结果便能保留小数;%.2fprintf 显示两位小数。统计人数用到的 excellent++,等价于 excellent = excellent + 1,另外两个计数变量也是同样的道理。

5. 小结与练习

场景 推荐语句
根据条件选择 if
多个固定选项 switch
重复次数明确 for
条件成立就继续 while
至少执行一次 do while
当前函数内跳转 goto(谨慎使用)

练习:

  1. for 输出 1 到 100 之间的所有偶数。
  2. do while 编写"圆面积、矩形面积、退出"菜单。
  3. 为成绩程序增加最高分和最低分统计。

做练习时别只看答案。先自己写一遍,再故意删掉一个 break、改错一个循环条件,观察程序怎么出问题。流程控制真正难的不是背语法,而是能在运行前判断代码会走到哪里。

相关推荐
LuminousCPP1 小时前
数据结构-排序(五):计数排序与排序专题阶段总结|从外部归并到线性排序,再看算法边界与选型
c语言·数据结构·笔记·算法·排序算法
山下梅子酒2251 小时前
洛谷-入门-B2046
c语言
李永奉2 小时前
中科蓝讯SDK开发-耳机项目功耗问题排查教程
c语言·开发语言·嵌入式硬件·物联网·智能手机
linx2952 小时前
第七章 · 标准库容器、算法与 ranges
c语言·开发语言·数据结构·c++·算法
Logic1012 小时前
C语言/数据结构位运算题解:异或XOR找出独特数字的索引位置——成对数字在两侧
c语言·数据结构·数组·位运算·时间复杂度·算法题·异或性质
xiangyun6115 小时前
【408数据结构 08】队列:循环队列判空判满,408年年考,一次讲清
c语言·开发语言·数据结构·c++·算法
xiangyun6115 小时前
【408数据结构 06】双链表、循环链表、静态链表
c语言·开发语言·数据结构·c++·算法
Logic10117 小时前
C语言/数据结构数组题解:数字列表加一(Plus One)——进位处理与数组扩展
c语言·数据结构·模拟·数组·时间复杂度·算法题·进位
Escalating_xu18 小时前
【C语言常见概念】从第一行代码到字符串结束标志:一次打通编译、main、ASCII、转义字符与注释
c语言·c++