C 班 第 5 课:循环里再套一个循环

适用对象: 完成了第 4 课(for 循环、累加)的同学 使用方式: 自学讲义。放在电脑旁边,边读边照着做 学完本课,你应该能:

  1. 看懂"循环里面又有一个循环"是怎么跑的
  2. 打印出完整的九九乘法表(上节课欠你的那个)
  3. 用嵌套循环打印星星组成的长方形和三角形

遇到问题怎么办: 这节课最容易乱的地方是"到底谁转得快"。记住一句话:外层转一圈,内层要整个跑完一遍。


1. 热身:把上节课的乘法表跑一遍(10 分钟)

打开上节课的 t3.cpp(7 的乘法表),重新运行一遍,确认输出的是 7、14、21……63 共 9 行。

上节课结尾我说过:完整的九九乘法表(9 行 9 列)"需要循环里再套一层循环,以后学"。今天就学这个。


2. 循环里套循环(25 分钟)

先看一个问题: 怎么打印 3 行星星,每行 5 个?

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

上节课学的 for 只能解决"一行 5 个星星":

#include <bits/stdc++.h>
using namespace std;

int main() {
    for (int j = 1; j <= 5; j++) {
        cout << "*";
    }
    cout << endl;
    return 0;
}

输出:*****

那"重复做 3 次这件事"呢? 再套一层循环就行——把上面那段整个塞进另一个 for 里:

#include <bits/stdc++.h>
using namespace std;

int main() {
    for (int i = 1; i <= 3; i++) {        // 外层:控制行,转 3 圈
        for (int j = 1; j <= 5; j++) {    // 内层:控制每行几个星星
            cout << "*";
        }
        cout << endl;                      // 一行打完了,换行
    }
    return 0;
}

输出:

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

📝 外层循环转一圈,内层循环要从头到尾整个跑完一遍。 所以内层一共跑了 3 × 5 = 15 次,打出 15 个星星。

⚠️ 内层循环的变量不能和外层同名。 外层用了 i,内层就要换一个名字,习惯上用 j。两层都用 i 会互相打架。

看不见执行顺序?把 ij 都打印出来:

#include <bits/stdc++.h>
using namespace std;

int main() {
    for (int i = 1; i <= 2; i++) {
        for (int j = 1; j <= 3; j++) {
            cout << "i=" << i << " j=" << j << endl;
        }
    }
    return 0;
}

输出:

i=1 j=1
i=1 j=2
i=1 j=3
i=2 j=1
i=2 j=2
i=2 j=3

看清楚了吗?i 一直是 1 的时候,j 已经从 1 数到 3 了;j 数完一轮,i 才敢往前走一步。内层跑得快,外层跑得慢。

动手检查点 1(5 分钟)

新建 check1.cpp:用嵌套循环打印 2 行、每行 4 个 #


3. 兑现上节课的承诺:完整九九乘法表(20 分钟)

九九乘法表长这样——注意第 1 行只有 1 个式子,第 2 行有 2 个,第 9 行有 9 个

1*1=1
1*2=2   2*2=4
1*3=3   2*3=6   3*3=9
...

秘密就在内层循环的"继续条件"上:内层不是固定跑到 9,而是跑到外层的 i 为止——写成 j <= i

#include <bits/stdc++.h>
using namespace std;

int main() {
    for (int i = 1; i <= 9; i++) {
        for (int j = 1; j <= i; j++) {     // 注意这里是 j <= i,不是 j <= 9
            cout << j << "*" << i << "=" << i * j << "\t";
        }
        cout << endl;
    }
    return 0;
}

输出:

1*1=1
1*2=2   2*2=4
1*3=3   2*3=6   3*3=9
1*4=4   2*4=8   3*4=12  4*4=16
1*5=5   2*5=10  3*5=15  4*5=20  5*5=25
1*6=6   2*6=12  3*6=18  4*6=24  5*6=30  6*6=36
1*7=7   2*7=14  3*7=21  4*7=28  5*7=35  6*7=42  7*7=49
1*8=8   2*8=16  3*8=24  4*8=32  5*8=40  6*8=48  7*8=56  8*8=64
1*9=9   2*9=18  3*9=27  4*9=36  5*9=45  6*9=54  7*9=63  8*9=72  9*9=81

📝 "\t" 是"制表符",作用是让后面的内容对齐到下一个"跳格位置",比空格整齐得多。写在双引号里,一个反斜杠加一个字母 t。

📝 内层循环的次数可以跟着外层变。 j <= 5 是每行都一样多,j <= i 是每行越来越多——这是嵌套循环最有用的技巧。


4. 打印图形(15 分钟)

明白了"内层次数跟着外层变",就能画三角形了。

正三角形(一行比一行多):

#include <bits/stdc++.h>
using namespace std;

int main() {
    for (int i = 1; i <= 5; i++) {
        for (int j = 1; j <= i; j++) {
            cout << "*";
        }
        cout << endl;
    }
    return 0;
}

输出:

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

倒三角形(一行比一行少): 把外层改成倒着数就行:

#include <bits/stdc++.h>
using namespace std;

int main() {
    for (int i = 5; i >= 1; i--) {         // 外层从 5 倒数到 1
        for (int j = 1; j <= i; j++) {
            cout << "*";
        }
        cout << endl;
    }
    return 0;
}

输出:

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

5. 读错误:2 个典型坑(10 分钟)

错误 1:内外层用了同一个变量名

for (int i = 1; i <= 3; i++) {
    for (int i = 1; i <= 5; i++) {    ← 内层又叫 i!
        cout << "*";
    }
    cout << endl;
}

编译器可能不报错(因为内层的 i 是一个"新盒子",把外层的 i 挡住了),但程序会变得极难看懂,一旦想在内层用外层的 i(比如乘法表里的 i * j)就彻底乱套。

📝 老老实实外层 i、内层 j,第三层用 k

错误 2:endl 放错了地方

for (int i = 1; i <= 3; i++) {
    for (int j = 1; j <= 5; j++) {
        cout << "*" << endl;    ← endl 写在内层了!
    }
}

本来想要 3 行、每行 5 个星星,结果每打一个星星就换一次行,变成了 15 行、每行 1 个星星。

📝 endl 写在内层 = 每个符号一行;endl 写在内层循环的后面(外层里面)= 每行一组。想清楚"什么时候该换行",endl 就该放在哪。


6. 本课练习(30 分钟起步)

⭐ 基础题 1:星星长方形(文件名 t1.cpp

打印 4 行、每行 6 个星星。

输出样例:
******
******
******
******
参考答案
#include <bits/stdc++.h>
using namespace std;

int main() {
    for (int i = 1; i <= 4; i++) {
        for (int j = 1; j <= 6; j++) {
            cout << "*";
        }
        cout << endl;
    }
    return 0;
}

⭐⭐ 实战题 2:n 行直角三角形(文件名 t2.cpp

输入一个正整数 n,打印 n 行的星星直角三角形(第 1 行 1 个,第 n 行 n 个)。

输入样例:
6

输出样例:
*
**
***
****
*****
******
参考答案
#include <bits/stdc++.h>
using namespace std;

int main() {
    int n;
    cin >> n;
    for (int i = 1; i <= n; i++) {
        for (int j = 1; j <= i; j++) {
            cout << "*";
        }
        cout << endl;
    }
    return 0;
}

内层条件写 j <= i,行数由读进来的 n 控制——这题就是把课上的正三角形改成"行数可变"。


⭐⭐⭐ 冲刺题 3:完整九九乘法表(文件名 t3.cpp

打印完整的九九乘法表,格式 1*1=1,同一行的式子之间用 "\t" 隔开,第 i 行有 i 个式子。

输出样例(前 3 行):
1*1=1
1*2=2   2*2=4
1*3=3   2*3=6   3*3=9
参考答案
#include <bits/stdc++.h>
using namespace std;

int main() {
    for (int i = 1; i <= 9; i++) {
        for (int j = 1; j <= i; j++) {
            cout << j << "*" << i << "=" << i * j << "\t";
        }
        cout << endl;
    }
    return 0;
}

上节课的"7 的乘法表"其实就是这张表里 i = 7 的那一行——现在你能一次把 9 行全打出来了。想打印上三角形式(第 1 行 9 个、第 9 行 1 个)的话,把内层改成 for (int j = i; j <= 9; j++) 试试看。


本课要点速查

写法 意思
for (int i = ...) { for (int j = ...) { ... } } 嵌套循环:外层转一圈,内层整个跑完一遍
内层 j <= 5 每行个数固定
内层 j <= i 每行个数跟着外层变(三角形、乘法表)
"\t" 制表符,让输出对齐成表格

变量名惯例: 外层 i、内层 j、再往里 k,不要重名。

易错点:

症状 原因
每个符号占一行 endl 写在内层循环里面了
内层想用外层的 i 结果拿到的是内层的 内外层变量重名
图形多一行或少一行 循环条件的 <=< 搞混了

结束前的自我检查

  1. 不看讲义,说出"外层转一圈,内层要做什么"
  2. 练习 1、2 都运行成功;⭐⭐⭐ 九九乘法表能完整打出来最好
  3. 向家里人展示你打印的九九乘法表,并解释 j <= i 这个条件的作用
  4. 合上讲义,把"3 行 5 个星星"的嵌套循环一次性写对