• 0
  • 0
  • 0
  • 从零掌握 C 语言循环控制与跳转:break、continue、goto 全方位详解

  • 小言心
  • 765
  • 2026-06-13 16:18
  • 在 C 语言的学习过程中,循环是处理重复任务的利器,而循环中的跳转语句 breakcontinue 以及更加自由的 goto 则是精确控制流程的关键。今天这篇超详细文章将带你从基础语法出发,结合大量练习,层层深入,彻底吃透这些看似简单却容易混淆的知识点。文中的每一个示例都来自经典课堂练习,我会逐行分析、补充原理、总结易错细节,让你不仅会写,更能理解背后的执行逻辑。

    一、跳出整个循环:break

    break 不能单独出现,它必须搭配 switch 选择结构或者循环结构(forwhiledo-while)使用。它的作用是立即终止当前所在的整个循环,程序会跳到循环之后的语句继续执行。如果是嵌套循环,break 只能跳出它所直接隶属的那一层循环

    练习 1:找出 1~100 中第一个既能被 3 整除又能被 5 整除的数

    for (int i = 1; i <= 100; i++) {
        if (i % 3 == 0 && i % 5 == 0) {
            printf("%d\n", i);
            break;
        }
    }

    详细解析:

    • 循环从 i = 1 递增到 100。
    • if (i % 3 == 0 && i % 5 == 0) 判断当前数字是否同时是 3 和 5 的倍数。注意 && 表示“且”,只有两个条件都成立才进入分支。
    • 一旦找到第一个这样的数(显然就是 15),立即执行 printf 输出 15,然后执行 break。
    • break 强制结束整个 for 循环,后面的 i = 16 ~ 100 都不会再判断,程序继续执行循环后的代码。

    核心要点:

    • break 只终止一层循环,如果有嵌套循环,外层循环不受影响。
    • 这种用法常用于“查找某个满足条件的最小值后提前退出”,可以大幅提高效率,避免无用遍历。

    二、跳过本次循环:continue

    continue 也只能写在循环内部,它的作用是结束本次循环,直接进入下一次循环的条件判断和迭代。对于 for 循环,执行 continue 后会立即跳转到循环更新部分(如 i++),然后进行条件检查;对于 while 循环,则会直接回到条件判断。

    练习 2:吃包子——有虫子的包子要跳过

    for (int i = 1; i <= 5; i++) {
        if (i == 3) {
            printf("这个%d包子有虫子\n", i);
            continue;
        }
        printf("在吃第%d个包子\n", i);
    }

    运行结果:

    在吃第1个包子
    在吃第2个包子
    这个3包子有虫子
    在吃第4个包子
    在吃第5个包子

    详细解析:

    • 循环执行 5 次,i 从 1 到 5。
    • 当 i 不等于 3 时,跳过 if 块,直接执行 printf("在吃第%d个包子\n", i);,表示正常吃掉。
    • 当 i == 3 时,先打印“这个3包子有虫子”,然后执行 continue。
    • continue 使得循环立刻放弃执行后面的“在吃第3个包子”,转而执行 i++(此时 i 变成 4),然后判断 i <= 5,继续下一次迭代。
    • 最终第 3 个包子没有被“吃”,但循环仍继续处理剩下的包子。

    核心要点:

    • continue 只跳过当前迭代中尚未执行的循环体部分,并不会终止整个循环。
    • 在 for 循环中,更新表达式(i++)依然会正常执行;在 while 和 do-while 中需要小心,避免因更新被跳过而进入死循环。

    三、循环嵌套与内层分析思维

    当循环中出现嵌套时,最有效的分析方法是从内向外看:先把最内层的循环逻辑搞明白,然后把整个内层循环当作一个整体,放到外层循环中重复执行。这种思维能帮助我们快速理解二维图形打印、乘法表等复杂输出。

    细节提示:

    • 外层循环每执行一次,内层循环都会从头到尾完整跑完一遍。
    • 外层循环常控制“行数”或“分组”,内层循环控制每一行中的具体内容。

    练习 3:打印 5×5 星号矩阵

    for (int i = 1; i <= 5; i++) {      // 外层:控制行
        for (int j = 1; j <= 5; j++) {  // 内层:控制每一行的星号数
            printf("*");
        }
        printf("\n");                   // 一行结束后换行
    }

    解析:

    • 内层循环 for (int j = 1; j <= 5; j++) 每次输出一个 *,连续输出 5 个。
    • 外层循环让这段“输出一行 5 个星号并换行”的代码重复 5 次,最终得到一个 5 行 5 列的矩形。

    练习 4:打印倒三角形

    /*
    预期输出:
    *****
    ****
    ***
    **
    *
        */
    for (int i = 1; i <= 5; i++) {
        for (int j = i; j <= 5; j++) {
            printf("*");
        }
        printf("\n");
    }

    解析:

    • 第 1 次外层循环 i=1:内层 j 从 1 到 5,输出 5 个 *。
    • 第 2 次外层 i=2:内层 j 从 2 到 5,输出 4 个 *。
    • 依此类推,每行减少一个星号,形成倒三角。

    练习 5:打印正三角形

    for (int i = 1; i <= 5; i++) {
        for (int j = 1; j <= i; j++) {
            printf("*");
        }
        printf("\n");
    }

    解析:

    • 当 i=1 时,内层循环 j 从 1 到 1,输出 1 个 *;i=2 时输出 2 个;……直到 i=5 输出 5 个。
    • 这样就形成了逐行递增的正三角形。

    四、九九乘法表与制表符 \t

    练习 6:打印九九乘法表

    for (int i = 1; i <= 9; i++) {
        for (int j = 1; j <= i; j++) {
            int temp = i * j;
            printf("%d * %d = %d\t", j, i, temp);
        }
        printf("\n");
    }

    输出格式分析:

    • 外层 i 表示行号,同时也代表乘数;内层 j 表示列号,是被乘数。
    • 每一行输出 j * i = 积,其中 j ≤ i,因此形成下三角样式。
    • 使用了制表符 \t 来对齐各列。

    关于 \t 的细节:

    • \t 是一个水平制表符,它的作用不是固定数量的空格,而是将光标移动到下一个“制表位”。通常制表位之间的距离是 8 个字符宽度。
    • 它会根据前面已输出内容的长度动态补充空格,使得当前输出到达下一个 8 的倍数列位置,最少补一个空格,最多补 8 个。
    • 对于英文字符(单字节)和数字,这个规则很清晰;但对于中文字符,一个汉字通常占 2 个字符宽度(在某些环境中可能显示宽度不同),混合输出时对齐效果可能略有偏差,因此在中英文混排时要谨慎使用。

    五、求 1~100 中的质数个数

    问题: 统计 1~100 范围内有多少个质数(也叫素数)。
    质数定义: 大于 1 的自然数中,除了 1 和它本身以外不再有其他因数。也就是说,对于数 n(n>1),如果存在整数 m(1 < m < n)能整除 n,则 n 不是质数。

    练习 7:质数统计代码

    int count = 0;
    for (int j = 2; j <= 100; j++) {
        int index = 0;          // 标记是否找到因数,0 表示未找到
        for (int i = 2; i < j; i++) {
            if (j % i == 0) {
                index++;        // 找到一个能整除 j 的数
                break;          // 已经确定不是质数,直接跳出内循环
            }
        }
        if (index == 0) {       // 如果整个内循环都没找到因数
            count++;
        }
    }
    printf("%d", count);        // 输出 25

    逐步解析:

    • 外层 j 遍历从 2 到 100 的每一个待判断的数。
    • 对于每个 j,内层 i 从 2 遍历到 j-1,检查是否有除数。
    • 用变量 index 记录是否找到因数:初始为 0,一旦 j % i == 0 成立,就执行 index++ 变成 1,然后 break 跳出内层循环。
    • 跳出后,判断 index 是否仍然为 0。若是,说明没有找到任何因数,j 就是质数,计数器 count 加一。
    • 最终 count 的值为 25(实际 1~100 内的质数有 25 个:2,3,5,7,11,13,17,19,23,29,31,37,41,43,47,53,59,61,67,71,73,79,83,89,97)。

    优化思想:

    • 我们无需检查到 j-1,只需检查到 sqrt(j) 即可,但原代码为演示简单清晰用了全范围。
    • 提前 break 避免了继续做无用的除法,是一种很重要的优化习惯。

    六、计算 1¹ + 2² + ... + 10¹⁰

    练习 8:累加次方

    long long rov = 0;
    for (int i = 1; i <= 10; i++) {
        long long pow = 1;
        for (int j = 1; j <= i; j++) {
            pow = pow * i;    // 计算 i 的 i 次方
        }
        rov = rov + pow;       // 累加到总和
    }
    printf("%lld\n", rov);

    详细解读:

    • 外层 i 控制底数和指数(这里恰好底数指数相同)。
    • 内层通过循环 j 从 1 到 i,将 pow 连乘 i 次,得到 i 的 i 次方。
    • 例如 i=3 时,内层循环 3 次,pow 初始 1,第一次乘 3 得 3,第二次得 9,第三次得 27,即 3³。
    • 累加变量 rov 是 long long 类型,因为 10¹⁰ 已经超过普通 int 的表示范围(约 21 亿),用 long long 防止溢出。
    • 最后输出使用 %lld 格式说明符。

    运行结果: 总和是一个很大的数,具体为 10405071317(可以动手算一算加深记忆)。

    易错提醒:

    • 内层 pow 必须每次外层循环重新初始化为 1,否则会继承上一次的结果导致错误。
    • 数据类型选择要根据计算最大值合理设置,避免溢出得到负数或错误值。

    七、找出所有各位数字之和等于 15 的数

    练习 9:数位分解与累加

    for (int i = 0; i <= 1000; i++) {
        int number = i;
        int sum = 0;
        while (number != 0) {
            int temp = number % 10;   // 取出最后一位数字
            number = number / 10;     // 去掉最后一位
            sum = sum + temp;         // 累加到和
        }
        if (sum == 15) {
            printf("%d\n", i);
        }
    }

    算法解析:

    • 遍历 i 从 0 到 1000 的每一个整数。
    • 对每个数,将其逐位分解:反复 %10 取最后一位,然后 /10 丢弃最后一位,直到 number 变为 0。
    • 所有位的数字累加到 sum 中,然后判断 sum 是否等于 15,如果是则输出该数。
    • 注意:我们复制了一份 number = i,这样不会破坏外层循环变量 i 的值。

    典型输出举例:

    • 69(6+9=15),78,87,96,159(1+5+9=15),168 等等。
    • 这个思路是处理数字各位数求和的标准模板,非常实用。

    八、用数学公式打印一颗“心”

    这是一个有趣的小彩蛋,利用数学不等式和双重循环在控制台打印一个心形图案。

    float x, y;
    for (y = 1.5f; y > -1.5f; y -= 0.1f) {
        for (x = -1.5f; x < 1.5f; x += 0.05f) {
            float ver = x * x + y * y - 1;
            if (ver * ver * ver - x * x * y * y * y <= 0) {
                printf("*");
            } else {
                printf(" ");
            }
        }
        printf("\n");
    }

    原理浅析:

    • 这里使用了心形的隐函数方程:(x² + y² - 1)³ - x² y³ ≤ 0
    • 外层 y 从上到下(1.5 到 -1.5),步长 0.1,模拟纵坐标。
    • 内层 x 从左到右(-1.5 到 1.5),步长 0.05,模拟横坐标。
    • 对于坐标平面上的每一个点,计算 ver = x² + y² - 1,然后判断 ver³ - x² y³ 是否小于等于 0。如果满足不等式,说明该点在心形区域内部,打印 *;否则打印空格。
    • 最终逐行输出,形成一个由星号组成的心形图案。

    细节:

    • 步长 y 的步长是 0.1,x 的步长是 0.05,这样使得图形在横向上分辨率更高一些,看起来更平滑。
    • 若在你的环境中输出比例不对,可以微调步长,因为控制台字符宽高比通常不是 1:1。
    • 这种利用数学公式生成图形的技术,就是“字符画”或“ASCII艺术”的一种。

    九、强大的 goto 跳转:自由与危险并存

    语法与基本用法

    goto 语句允许程序无条件跳转到同一函数内带有标签(label)的任意位置。它的基本格式是:

    标签名:
        // 代码块
    goto 标签名;

    示例:用 goto 实现循环和条件跳转

    #include <stdio.h>
    int main() {
        int i = 1;
    
    a:  printf("看看我是多少:%d\n", i);
        i++;
        if (i == 15) {
            goto b;
        } else {
            goto a;
        }
    
    b:  printf("看看我执行没有");
        return 0;
    }

    执行流程:

    • 程序先定义变量 i=1。
    • 标签 a: 处打印 i,然后自增。
    • 判断 i 是否等于 15,如果不等于 15,则执行 goto a;,强制跳回标签 a 处,形成循环,相当于不断执行打印和自增,直到 i 变为 15。
    • 当 i == 15 时,执行 goto b;,跳转到标签 b:,打印“看看我执行没有”,程序结束。

    运行结果会输出:

    看看我是多少:1
    看看我是多少:2
    ...
    看看我是多少:14
    看看我执行没有

    (注意当 i 变成 15 时直接跳转,不会执行标签 a 后的打印,所以只显示到 14。)

    goto 的使用准则

    虽然 goto 很灵活,但在结构化程序设计中应尽量避免使用,因为它会破坏代码的模块性和可读性,使程序流程变得混乱,容易产生所谓的“意大利面条式代码”。在大多数情况下,breakcontinue、函数调用、循环和条件语句已经能够清晰表达所有逻辑。

    少数合理的应用场景:

    • 在深层嵌套循环中一次性跳出多层循环(因为 break 只能跳出一层)。
    • 统一处理错误并释放资源(在 C 语言的错误处理中比较常见,类似“异常处理”的雏形)。
    • 在某些状态机或非常底层的系统代码中,goto 可能比一大堆标志变量更直接。

    在初学阶段,请将 goto 作为一种语法了解,实际编程时优先使用结构化控制流。

    十、总结与学习建议

    通过以上十个循序渐进的练习,我们全面梳理了 C 语言循环控制中的关键概念:

    语句/技术作用注意事项
    break立即终止当前循环只能跳出最近一层循环;常与条件配合
    continue跳过本次循环剩余部分,进入下一次迭代for 中仍会执行更新表达式;注意避免死循环
    循环嵌套多重循环实现二维问题从内向外分析,外层控制整体重复次数
    \t 制表符动态对齐输出基于制表位,与前面内容长度有关
    goto无条件跳转到标签强大但易滥用,慎用!


    评论

  • 0
    /1000
    最热
  • 最新

    确认跳转

    您即将离开当前页面,访问外部链接。请注意核对网址,保护隐私安全。

    https://example.com

    言心安全助手 · 建议确认来源可信

    • 0
    • 0
    • 0
    登录后参与评论