CC++ & Algorithm

C++ 循环嵌套详解

困难26
语言版本:C++Python
概述:理解循环里面套循环,学会用嵌套循环解决二维问题。

循环嵌套:就像时钟的时针和分针

想象一下,你盯着墙上的时钟看时间:分针要跑完一圈(60分钟),时针才会动一格(1小时)。在编程里,循环嵌套就是这种“大循环套小循环”的结构——外层循环每执行一次,内层循环就要完整地跑完一整轮。我们用它来处理像表格、棋盘、图形这类有“行和列”的二维问题。

一、循环嵌套到底是怎么执行的?

我们先把分钟和小时的关系写成伪代码:

for (小时 = 1; 小时 <= 12; 小时++) {      // 外层:时针走一圈
    for (分钟 = 1; 分钟 <= 60; 分钟++) {  // 内层:分针走一圈
        时间过去了1分钟
    }
}

小时 = 1 时,内层的 分钟 要从1跑到60,等分钟跑完了,小时才变成2,然后分钟又从1跑到60……这样一共会输出 12 × 60 = 720 条“时间过去了1分钟”。

把这种思想搬到编程里,就是外层循环控制“大范围”(比如行数、组数),内层循环控制“小范围”(比如列数、每组的个数)。两个循环套在一起,就能生成像表格、图形、组合排列这样的二维数据。

小例子:班里排座位,4行5列。你从第1行开始,每行要依次坐满5个同学(第1列→第2列→…→第5列),然后换到第2行,再坐满5个同学……这就是一个嵌套循环。

二、用嵌套循环打印图形

1. 打印一个5行5列的星号矩形

想象你有一个5行5列的棋盘,每个格子放一个星号 *。外层循环管“第几行”,内层循环管“这一行里放几个星”。

for (int row = 1; row <= 5; row++) {         // 外层:控制行数(1到5)
    for (int col = 1; col <= 5; col++) {     // 内层:控制列数(每行5个)
        cout << "* ";                        // 打印一个星号加空格
    }
    cout << endl;                            // 一行结束后换行
}

输出效果:

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

2. 打印直角三角形

如果想让星号排成三角形的形状,比如:

* 
* * 
* * * 
* * * * 

观察规律:第1行1个星,第2行2个星,第3行3个星……也就是内层循环的次数等于当前的行号。我们可以让内层循环的条件依赖于外层循环的变量。

for (int i = 1; i <= 4; i++) {               // 外层:控制行数(1到4)
    for (int j = 1; j <= i; j++) {           // 内层:每行打印 i 个星
        cout << "* ";
    }
    cout << endl;                            // 换行
}

试一试:把 j <= i 改成 j <= 5 会怎样?那就变成矩形了,因为每一行都固定打印5个星。

3. 倒着打印三角形(自己练手)

如果想把三角形倒过来:

* * * * 
* * * 
* * 
* 

你应该怎么做?提示:第一行4个星,第二行3个星……内层循环的上限可以写成 5 - i 或者 4 - i + 1。试着自己写一写吧!

三、实战:打印九九乘法表

乘法表是我们最熟悉的嵌套循环应用:行从1到9,列从1到当前的行数。比如第5行只打印1×5=5、2×5=10、3×5=15、4×5=20、5×5=25,一共5个算式。

for (int i = 1; i <= 9; i++) {               // 外层:乘数 i(1到9)
    for (int j = 1; j <= i; j++) {           // 内层:被乘数 j(1到i)
        cout << j << "x" << i << "=" << i * j << "\t";  // 输出算式,\t是制表符,让列对齐
    }
    cout << endl;                            // 换行
}

输出效果(部分):

1x1=1	
1x2=2	2x2=4	
1x3=3	2x3=6	3x3=9	
1x4=4	2x4=8	3x4=12	4x4=16	
...

生活小联想:这种“列数随行数增长”的模式,就像课间排队打水——第1个人只和自己比,第2个人要和前两个人比……每排的“比较次数”越来越多。

四、生活中的嵌套循环无处不在

  • 时钟:时针(外层循环12格)和分针(内层循环60格)
  • 日历:月份(外层,112)和日期(内层,128/30/31)
  • 超市货架:第几排(外层)和第几列(内层),每排的商品数量可能不同
  • 课间操队列:第几排(外层)和第几个同学(内层)
  • 巧克力排:一盒巧克力有3行4列,吃的时候要一行一行地吃,每行从左到右吃4块

五、新手最容易犯的3个错误

错误1:内外层变量混用

for (int i = 1; i <= 5; i++) {
    for (int i = 1; i <= 5; i++) {   // ❌ 内层也用了 i,外层 i 被覆盖
        cout << "* ";
    }
}

正确做法:外层用 i,内层用 j(或者 kcol 等),不要重名。如果内层也用了 i,编译器可能会报错或产生奇怪的循环次数。

错误2:忘记换行

for (int i = 1; i <= 5; i++) {
    for (int j = 1; j <= 5; j++) {
        cout << "* ";
    }
    // 这里忘记写 cout << endl;
}

结果:所有星号挤在一行里,变成了 * * * * * * * * * * * * * * * * * * * * * * * * *每处理完一行,必须手动换行!

错误3:内层循环条件写错

比如想打印直角三角形,却写成 j <= 5

for (int i = 1; i <= 4; i++) {
    for (int j = 1; j <= 5; j++) {   // ❌ 固定5列,不会随着 i 变化
        cout << "* ";
    }
    cout << endl;
}

结果会打印一个4行5列的矩形,而不是三角形。

六、完整可运行示例:打印一个带边框的空心矩形

下面是一个完整的 C++ 程序,包含了头文件、主函数。它用嵌套循环打印一个 5×7 的空心矩形,只有边框有星号:

#include <iostream>
using namespace std;

int main() {
    int rows = 5;                      // 行数
    int cols = 7;                      // 列数

    // 外层循环:控制每一行
    for (int i = 1; i <= rows; i++) {
        // 内层循环:控制每一列
        for (int j = 1; j <= cols; j++) {
            // 如果是第一行、最后一行、第一列、最后一列,打印星号,否则打印空格
            if (i == 1 || i == rows || j == 1 || j == cols) {
                cout << "* ";
            } else {
                cout << "  ";   // 两个空格(一个星号占两个字符)
            }
        }
        cout << endl;            // 换行
    }

    return 0;
}

运行结果:

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

你可以试着修改 rowscols,或者把 if 条件改成其他图案(比如对角线)。

七、如果还想继续学什么?

  1. 二维数组:嵌套循环常和二维数组搭配使用,比如存储班级成绩表
  2. 多层嵌套:最多嵌套3层就够了,比如三维坐标(x, y, z)或者三层比赛(年级→班级→学号)
  3. break 和 continue:在嵌套循环中,break 只跳出它所在的那一层循环;想跳出所有外层需要额外标记(goto 或 flag 变量)
  4. 循环优化:尽量减少内层循环中的计算量,比如把常数计算提到外层

现在就打开你的编译器,把上面的代码敲进去运行一下,再自己改一改,看看会得到什么新图形吧!

例题精讲

1单选题

以下C++代码中,内层循环体(cout << "*";)总共执行多少次? for (int i = 0; i < 3; i++) { for (int j = 0; j < 4; j++) { cout << "*"; } }

A7
B12
C4
D3
2单选题

以下代码的输出是什么? for (int i = 1; i <= 3; i++) { for (int j = 1; j <= i; j++) { cout << j; } cout << endl; }

A123
B1\n12\n123
C1\n22\n333
D1\n23\n456
3判断题

在嵌套循环中,外层循环每执行一次,内层循环就会完整地从头到尾执行一轮。

4判断题

以下代码段执行后,输出的星号数量是6个。 for (int i = 1; i <= 3; i++) { for (int j = 1; j <= 2; j++) { cout << "*"; } }

5填空题
补全以下代码,使得程序输出如下图案(三行,第一行输出1,第二行输出12,第三行输出123):

#include <iostream>
using namespace std;
int main() {
    for (int i = 1; i <= 3; i++) {
        for (int j = 1; j <= ___; j++) {
            cout << j;
        }
        cout << endl;
    }
    return 0;
}