CC++ & Algorithm

循环嵌套

中等5
语言版本:C++
概述:用生活中的套娃例子,教你如何让循环里面再套一个循环,解决需要重复做多遍重复事情的问题。

循环嵌套:让电脑帮你做“套娃”般的重复工作

同学们,你有没有玩过俄罗斯套娃?一个大娃娃里面藏着一个稍小的娃娃,小娃娃里面又藏着更小的娃娃……这就是“嵌套”的意思。
在编程里,循环嵌套就是——在一个循环的“身体”里,再放一个完整的循环。外面的循环每执行一次,里面的循环就要从头到尾完整地跑一遍。
有了循环嵌套,我们可以轻松处理那些需要“重复做某件事,而这件事本身也需要重复”的场景,比如打印一个方块、画个乘法表,甚至模拟一天的生活作息。


一、什么是循环嵌套?

简单说,就是“循环里面套循环”。外面的叫外层循环,里面的叫内层循环
外层循环每转一圈,内层循环就要从开始到结束完整执行一圈。
这就像你每天上学:一周有5天(外层循环),每一天里你都要上8节课(内层循环)。上课内容就是内层循环体,上完一节课再上下一节,上完一天再进入下一天。

我们来看一个最直观的例子——在屏幕上打印一个 3行5列 的长方形,每行有5个星号。如果只用简单的循环,你要写3遍:

for (int i = 0; i < 5; i++) cout << "* ";   // 打印一行5个星号
cout << endl;
// 再手动写下一行,太麻烦……

用循环嵌套就省事多了:

#include <iostream>
using namespace std;
int main() {
    for (int row = 1; row <= 3; row++) {          // 外层:行数
        for (int col = 1; col <= 5; col++) {      // 内层:每行5个星号
            cout << "* ";
        }
        cout << endl;                             // 换行
    }
    return 0;
}

输出效果:

* * * * * 
* * * * * 
* * * * * 

二、循环嵌套的执行流程(一步步拆解)

很多人刚开始会好奇:计算机到底是怎么跑这些嵌套循环的?我们用上面的长方形例子来一步一步模拟:

  • 第一次外层循环(row = 1):
    程序遇到内层循环,col 从1开始。
    col=1 → 打印“* ”;col=2 → 打印“* ”;……直到col=5,打印完毕。
    内层循环结束,执行 cout << endl 换行。
  • 第二次外层循环(row = 2):
    再次进入内层循环,col 重新从1开始,再重复打印5个星号,再换行。
  • 第三次外层循环(row = 3):
    同理,打印5个星号,换行。
  • 外层循环结束(row变成4,大于3),程序退出。

关键点:内层循环的变量(如col每次外层循环开始时都会被重新初始化(从1开始)。如果忘记初始化,第二次外层循环时内层变量可能还保留上次的值,导致循环不执行或出错。


三、生活中的嵌套例子

除了钟表(分针转一圈时针走一格),再比如学校排队打饭

  • 外层:每个班级轮流去打饭(班级1 → 班级2 → 班级3)
  • 内层:班级里的每个同学依次打饭(同学1 → 同学2 → … → 同学n)

如果班级有40人,3个班,那么食堂阿姨要重复“打饭”这个动作共 3 × 40 = 120 次。这就是嵌套的威力:用两行循环就能表达“每个班每个同学”的重复。

再比如课表

  • 外层:周一到周五(5天)
  • 内层:每天上午四节课,下午两节课(6节课)
    每天的上课节数固定,但每节课内容不同,循环嵌套帮我们把结构清晰地描述出来。

四、常见错误(新手一定要看)

1. 忘记在最外层循环开始时重置内层循环变量

int row = 1, col = 1;          // 错误:col只初始化一次
for (row = 1; row <= 3; row++) {
    for (col = 1; col <= 5; col++) {
        cout << "* ";
    }
    cout << endl;
}

这样写其实也没错,因为内层循环的 col 每次都在 for 括号里被重新赋值为1。但是如果你把 col = 1 写在循环外面,比如:

int col = 1;                    // 错误的初始化位置
for (int row = 1; row <= 3; row++) {
    for ( ; col <= 5; col++) {  // 内层循环不初始化col
        cout << "* ";
    }
    cout << endl;
}

第一次外层循环,内层正常执行,col跑到了6。第二次外层循环时,col还是6,不满足条件,内层循环一次都不执行!结果只打印了一行星号。正确做法:内层循环变量必须在内层 for 括号里初始化,或者在内层循环开始前重置。

2. 内外层循环的条件弄反

比如你想要一个3行5列的长方形,却写成了:

for (int col = 1; col <= 5; col++) {      // 外层变成列?
    for (int row = 1; row <= 3; row++) {
        cout << "* ";
    }
    cout << endl;
}

这时候输出的是5行3列,形状变了。要分清哪个控制行,哪个控制列。

3. 换行语句放错位置

有时你会把 cout << endl; 放在内层循环里面,导致每个星号后面都换行,打印成一列。记住:换行应该属于外层循环的“善后工作”,内层循环负责打印一行里的所有内容,换行交给外层。

4. 死循环(条件永远满足)

比如内层循环变量忘记更新:

for (int i = 1; i <= 5; ) {     // 漏了 i++
    for (int j = 1; j <= 3; j++) {
        // ……
    }
}

外层循环的 i 永远不变,程序卡死。检查循环变量是否有自增(+++=1)。


五、完整示例:打印多种图形

例1:打印直角三角形(左对齐)

行数:5行,第1行1个星,第2行2个星,……第5行5个星。

#include <iostream>
using namespace std;
int main() {
    int lines = 5;                          // 总行数
    for (int row = 1; row <= lines; row++) { // 外层:行号从1到5
        for (int star = 1; star <= row; star++) { // 内层:每行星号数量等于行号
            cout << "* ";
        }
        cout << endl;                       // 每行结束换行
    }
    return 0;
}

输出:

* 
* * 
* * * 
* * * * 
* * * * * 

例2:9×9乘法表(你熟悉的那个)

#include <iostream>
using namespace std;
int main() {
    for (int i = 1; i <= 9; i++) {           // i:被乘数
        for (int j = 1; j <= i; j++) {       // j:乘数,只到i(下三角)
            cout << j << "x" << i << "=" << i*j << " ";
        }
        cout << endl;                         // 每行结尾换行
    }
    return 0;
}

输出前几行:

1x1=1 
1x2=2 2x2=4 
1x3=3 2x3=6 3x3=9 
……

例3:打印空心长方形(结合条件判断)

这个例子展示了循环嵌套可以和 if 语句配合使用,让图案更丰富。

#include <iostream>
using namespace std;
int main() {
    int rows = 4, cols = 6;                     // 4行6列
    for (int r = 1; r <= rows; r++) {
        for (int c = 1; c <= cols; c++) {
            // 如果是第一行、最后一行、第一列、最后一列,打印星号,否则打印空格
            if (r == 1 || r == rows || c == 1 || c == cols) {
                cout << "* ";
            } else {
                cout << "  ";                    // 两个空格占位
            }
        }
        cout << endl;
    }
    return 0;
}

输出:

* * * * * * 
*         * 
*         * 
* * * * * * 

六、相关指引(下一步学什么)

学完循环嵌套,你还可以继续探索:

  • 多重循环(三层、四层):比如打印一个三维数组的每一层,或者模拟多个嵌套的日程表。
  • breakcontinue 在嵌套循环中的用法break 只跳出它所在的那一层循环,continue 跳过本次循环的剩余部分。要注意它们的作用范围。
  • 循环嵌套与数组结合:比如用双层循环遍历一个二维数组(像表格一样的数据),处理成绩表、迷宫、图像等。
  • 优化循环嵌套:过多的嵌套会使程序变慢,学习如何减少不必要的内层循环(比如用公式代替部分循环)。

循环嵌套是编程里非常实用的工具,学会它,很多看似复杂的事情都能轻松搞定。自己动手敲一敲上面的例子,再试试打印一个倒三角形、菱形,或者模拟一个班级的课表吧!

例题精讲

1单选题

以下嵌套循环中,内层循环总共执行多少次? for(int i=1;i<=3;i++) for(int j=1;j<=i;j++) cout<<"*";

A3次
B6次
C9次
D10次
2判断题

在嵌套循环中,break语句只会跳出包含它的最内层循环。

3填空题
以下代码用于打印一个3行5列的矩形星号阵,请填空。
for(int i=1;i<=3;i++){
    for(int j=1;j<=___;j++){
        cout<<"*";
    }
    cout<<endl;
}
4单选题

执行以下代码后,输出结果中数字5出现的次数是? for(int i=1;i<=3;i++){ for(int j=1;j<=3;j++){ if(i*j==5) cout<<i*j<<" "; } }

A0次
B1次
C2次
D3次
5填空题
以下代码用于输出1到100之间的所有质数,请填空。
for(int i=2;i<=100;i++){
    bool isPrime=true;
    for(int j=2;j<=sqrt(i);j++){
        if(___==0){
            isPrime=false;
            break;
        }
    }
    if(isPrime) cout<<i<<" ";
}