R2 GESP C++ 二级复习手册

打印说明: 这份手册是给你打出来放在桌上翻的,所以全文没有折叠答案——所有参考代码和解析都直接排在题目下面。建议 A4 双面打印。

先过 R1_GESP一级复习手册.md 二级考纲默认你已经掌握一级的全部内容,本册不再重复。


这份手册是什么

对照 CCF 编程能力等级认证 C++ 二级标准,把 9 条考点全部覆盖一遍。

⚠️ 二级和一级最大的不同:非编程的知识点变多了。 计算机存储、计算机网络、程序设计语言分类、流程图——这四条一行代码都不写,但占了考纲的将近一半,而且我们的课上一个字都没讲过。

考试怎么考

题型 题量 每题分 小计
单选题 15 道 2 分 30 分
判断题 10 道 2 分 20 分
编程题 2 道 25 分 50 分

考试时间 120 分钟,满分 100 分。

📝 第四节那几张速记表是本册性价比最高的部分——纯记忆,没有理解门槛,背了就拿分。


一、考纲对照表

二级考点 学过没有 看哪里
(1) 存储器:ROM / RAM / Cache ❌ 没讲过 4.1
(2) 计算机网络:分类、TCP/IP 与 OSI、协议、IP 地址 ❌ 没讲过 4.2
(3) 程序设计语言分类、常见高级语言 ❌ 没讲过 4.3
(4) 流程图:概念、符号、绘制、描述三种基本结构 ❌ 没讲过 4.4
(5) ASCII 编码原理与字符转换 🟡 L05 用过没系统讲 3.1
(6) 强制类型转换与隐式类型转换 🟡 L02 讲过整除的坑 3.2
(7) 多层分支:if / if-else / switch 的嵌套 🟡 嵌套 if 学过,switch 嵌套没有 3.3
(8) 多层循环:for / while / do-while 的嵌套 ❌ 只有 L03 一小节加餐 3.4
(9) 数学函数 abs / sqrt / max / min / rand / srand ❌ 只零星用过 max 3.5

📝 编程部分只有 5 条,而且都不难;难的是把第四节那四张表背下来。


二、一级内容快速回顾

只列二级会继续用到的,详细内容见 R1

要点 一句话
整数除法 7 / 2 = 3,小数直接砍掉
取余 7 % 2 = 1;n % 10 取末位,n / 10 去末位
switch case 只能跟常量;漏 break 会穿透
do-while 至少执行一次;结尾要加分号
++ / -- 在前先加,在后后加
bool 输出 cout 打印的是 1 / 0
char 单引号,只装一个字符
逻辑运算 && || !0 < x < 10 是错的
保留小数 cout << fixed << setprecision(2) << x;fixed 不能漏

三、新增编程考点精讲

3.1 ASCII 编码

考纲原文(5): 了解编码的基本概念,了解 ASCII 编码原理,能识别常用字符的 ASCII 码(空格:32、"0":48、"A":65、"a":97),并掌握 ASCII 码和字符之间相互转换的方法。

计算机只认数字。ASCII 就是一张字符和数字的对照表:每个字符对应一个 0~127 的整数。

四个必背锚点(考纲原文点名的):

字符 ASCII 码
空格 32
'0' 48
'A' 65
'a' 97

📝 由锚点可以推出所有: '1' = 49,'9' = 57;'B' = 66,'Z' = 90;'b' = 98,'z' = 122。

📝 最有用的两个差值:

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

int main() {
    char c = 'A';

    // 字符 → ASCII 码:赋给 int,或者强制转换
    int code = c;                    // 隐式转换,code 得到 65
    cout << code << endl;            // 输出 65
    cout << (int)c << endl;          // 强制转换写法,同样输出 65

    // ASCII 码 → 字符:强制转换成 char
    int n = 66;
    cout << (char)n << endl;         // 输出 B

    // 大写转小写:加 32
    cout << (char)('A' + 32) << endl;    // 输出 a
    // 小写转大写:减 32
    cout << (char)('z' - 32) << endl;    // 输出 Z

    // 数字字符转数值
    char d = '7';
    cout << d - '0' << endl;         // 输出 7(是数字 7,不是字符)

    return 0;
}

输出:

65
65
B
a
Z
7

⚠️ 坑:忘了转回 char,就会打印数字。

cout << 'A' + 32 << endl;       // 输出 97,不是 a

'A' + 32 的结果类型是 intcout 就按整数打印。必须写成 (char)('A' + 32)

⚠️ 判断字符类别的标准写法:

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

int main() {
    char c;
    cin >> c;
    if (c >= '0' && c <= '9') {
        cout << "数字" << endl;
    } else if (c >= 'A' && c <= 'Z') {
        cout << "大写字母" << endl;
    } else if (c >= 'a' && c <= 'z') {
        cout << "小写字母" << endl;
    } else {
        cout << "其他字符" << endl;
    }
    return 0;
}

输入 K 输出 大写字母

📝 字符可以直接用 >= <= 比大小,比的就是它们的 ASCII 码。因为字母在 ASCII 表里是连续排列的,所以 c >= 'a' && c <= 'z' 这种写法才成立。

3.2 数据类型转换

考纲原文(6): 掌握数据类型的转换:强制类型转换和隐式类型转换。

① 隐式转换:编译器自动做的,你没写任何东西。

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

int main() {
    int a = 3;
    double b = 2.5;

    double c = a + b;        // a 自动被提升成 3.0,再相加
    cout << c << endl;       // 输出 5.5

    int d = 3.9;             // double → int,小数部分直接砍掉(不是四舍五入!)
    cout << d << endl;       // 输出 3

    char e = 'A';
    int f = e;               // char → int,得到 ASCII 码
    cout << f << endl;       // 输出 65

    return 0;
}

输出:

5.5
3
65

📝 隐式转换的方向:小范围 → 大范围是安全的intdouble),大范围 → 小范围会丢东西doubleint 砍掉小数)。

② 强制转换:你自己写 (类型) 明确要求。

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

int main() {
    int a = 7, b = 2;

    cout << a / b << endl;                    // 3   两个 int 相除,整除
    cout << (double)a / b << endl;            // 3.5 把 a 变成 double,整个式子就是小数除法
    cout << a * 1.0 / b << endl;              // 3.5 另一种写法,效果一样

    double x = 3.99;
    cout << (int)x << endl;                   // 3   砍掉小数,不四舍五入

    return 0;
}

输出:

3
3.5
3.5
3

⚠️ 本节头号坑(L02 讲过,这里正式收尾):

double avg = a / b;         // 右边先按 int 算完了,才赋给 double

赋给谁不重要,右边先按自己的类型算完。 想要小数结果,必须在除号左边动手:(double)a / ba * 1.0 / b

⚠️ 第二个坑:(double)(a / b) 是没用的。

cout << (double)(a / b) << endl;    // 输出 3,不是 3.5

括号里先算完整除得到 3,再转成 3.0。转换要在除法之前做,不是之后。

写法 7 / 2 的结果 对不对
a / b 3 整除
(double)a / b 3.5
a * 1.0 / b 3.5
(double)(a / b) 3.0 ❌ 转晚了

3.3 多层分支(分支嵌套)

考纲原文(7): 掌握多层分支结构,掌握 if 语句、if...else 语句、switch 语句,及相互嵌套的方法。

嵌套 = 一个分支的里面再放一个分支。

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

int main() {
    int year;
    cin >> year;

    // 闰年判断:能被 4 整除但不能被 100 整除,或者能被 400 整除
    if (year % 4 == 0) {              // 外层:先看能不能被 4 整除
        if (year % 100 == 0) {        // 内层:再看是不是整百年
            if (year % 400 == 0) {    // 整百年要能被 400 整除才算
                cout << "闰年" << endl;
            } else {
                cout << "平年" << endl;
            }
        } else {
            cout << "闰年" << endl;   // 能被 4 整除、不是整百年 → 闰年
        }
    } else {
        cout << "平年" << endl;
    }
    return 0;
}

输入 2024 输出 闰年;输入 1900 输出 平年;输入 2000 输出 闰年;输入 2023 输出 平年

📝 同一件事也可以用逻辑运算符一行写完:

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

int main() {
    int year;
    cin >> year;
    if ((year % 4 == 0 && year % 100 != 0) || year % 400 == 0) {
        cout << "闰年" << endl;
    } else {
        cout << "平年" << endl;
    }
    return 0;
}

⚠️ 括号不能省。 && 的优先级高于 ||,所以这里的括号虽然理论上可以省,但省了以后没人看得懂,而且换个式子就会错。规矩定死:混用 &&|| 一律加括号。

switch 也能嵌套——case 里面再放一个 switchif

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

int main() {
    char op;
    double a, b;
    cin >> a >> op >> b;

    switch (op) {
        case '+':
            cout << a + b << endl;
            break;
        case '-':
            cout << a - b << endl;
            break;
        case '*':
            cout << a * b << endl;
            break;
        case '/':
            if (b == 0) {                    // switch 里面嵌一个 if
                cout << "除数不能为 0" << endl;
            } else {
                cout << a / b << endl;
            }
            break;
        default:
            cout << "非法运算符" << endl;
            break;
    }
    return 0;
}

输入 6 / 3 输出 2;输入 6 / 0 输出 除数不能为 0

⚠️ 嵌套时最容易错的是大括号配对。 写完一层立刻补上 },再往里写——别等全写完了才数括号。

3.4 多层循环(循环嵌套)

考纲原文(8): 掌握多层循环结构,掌握 for 语句、while 语句、do...while 语句,及相互嵌套的方法。

外层走一步,内层跑完一整圈。

#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
            cout << j << "*" << i << "=" << i * j << " ";
        }
        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 

📝 两个关键点:

  1. j <= i 而不是 j <= 9 —— 这一个字符决定了是三角形还是正方形
  2. cout << endl; 放在内层循环外面 —— 放进内层就变成每个式子占一行

内外层总次数 = 外层次数 × 内层次数。 上面这个是 1+2+…+9 = 45 次。

⚠️ 坑一:内外层循环变量重名。

for (int i = 1; i <= 3; i++) {
    for (int i = 1; i <= 3; i++) {    // 内层又叫 i
        ...
    }
}

内层的 i遮住外层的 i,逻辑立刻错乱。外层用 i,内层用 j,再往里用 k——照这个顺序,不要自创。

⚠️ 坑二:break 只能跳出一层。

for (int i = 1; i <= 3; i++) {
    for (int j = 1; j <= 3; j++) {
        if (j == 2) break;            // 只跳出内层,外层继续
    }
}

break 跳出的是离它最近的那一层。想跳出两层要用标志变量,二级不考,知道这回事就行。

打印图形是最常考的嵌套循环题:

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

int main() {
    int n;
    cin >> n;
    for (int i = 1; i <= n; i++) {           // 第 i 行
        for (int j = 1; j <= n - i; j++) {   // 先打 n-i 个空格
            cout << " ";
        }
        for (int j = 1; j <= 2 * i - 1; j++) {   // 再打 2i-1 个星号
            cout << "*";
        }
        cout << endl;
    }
    return 0;
}

输入 4 输出:

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

📝 图形题的通法:找出「第 i 行有几个空格、有几个符号」这两个式子。 找出来题就做完了,剩下的是抄公式。

3.5 常用数学函数

考纲原文(9): 掌握常用的数学函数:绝对值函数、平方根函数、最大值函数、最小值函数、随机数函数,理解相应的算法原理。

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

int main() {
    cout << abs(-5) << endl;             // 整数绝对值 → 5
    cout << fabs(-2.5) << endl;          // 小数绝对值 → 2.5
    cout << sqrt(16) << endl;            // 平方根 → 4
    cout << max(3, 7) << endl;           // 最大值 → 7
    cout << min(3, 7) << endl;           // 最小值 → 3
    cout << max(max(3, 7), 5) << endl;   // 三个数取最大:套两层 → 7
    cout << pow(2, 10) << endl;          // 幂 → 1024
    return 0;
}

输出:

5
2.5
4
7
3
7
1024

函数速查表:

函数 作用 返回类型 注意
abs(x) 整数绝对值 int
fabs(x) 小数绝对值 double
sqrt(x) 平方根 double 参数不能为负
max(a, b) 较大者 同参数 两个参数类型必须一样
min(a, b) 较小者 同参数 同上
pow(a, b) a 的 b 次方 double

⚠️ 坑一:sqrtpow 返回的是 double,不是整数。

int x = sqrt(16);          // 得到 4,看起来没问题
int y = pow(10, 2);        // 可能得到 99!

pow(10, 2) 在浮点运算下可能算出 99.9999999,转成 int 就砍成 99。求整数次幂宁可用循环乘,别用 pow

⚠️ 坑二:max 的两个参数类型必须一致。

max(3, 2.5)                // 编译错误:一个 int 一个 double

改成 max(3.0, 2.5)max(3, (int)2.5)

随机数:

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

int main() {
    srand(2026);                         // 设置随机种子;同一个种子每次结果相同
    for (int i = 1; i <= 5; i++) {
        cout << rand() % 100 << " ";     // 产生 0~99 的随机整数
    }
    cout << endl;
    return 0;
}

📝 随机数的两条规则:

  1. rand() % n 产生 0 ~ n−1 的整数。 想要 a ~ b,写 rand() % (b - a + 1) + a
  2. srand(种子) 设置起点。 不调用 srand,每次运行结果完全一样;想每次不同就写 srand(time(0)),用当前时间当种子

⚠️ 考试常考:rand() % 6 + 1 产生的范围是多少? 答案是 1 ~ 6(模 6 得 0~5,再加 1)。


四、非编程知识速记表

⚠️ 这一节不写代码,全是选择判断题。约占卷面 20~30 分,背下来就是分。

4.1 存储器:ROM / RAM / Cache

考纲原文(1): 了解计算机存储的基本概念及分类,了解随机存储器(RAM)、只读存储器(ROM)和高速缓冲存储器(Cache)的功能及区别。

全称 特点 断电后
RAM 随机存取存储器 可读可写,就是我们说的"内存" 数据丢失
ROM 只读存储器 只能读不能随意写,存开机程序(BIOS) 数据保留
Cache 高速缓冲存储器 在 CPU 和内存之间,速度最快、容量最小、最贵 数据丢失

速度排序(必背):

CPU寄存器 > Cache > 内存(RAM) > 外存(硬盘/U盘)

容量排序正好相反:

外存 > 内存 > Cache > CPU寄存器

📝 Cache 存在的意义: CPU 太快、内存太慢,中间垫一层高速小容量存储,把常用数据先放着,减少 CPU 等待。

4.2 计算机网络

考纲原文(2): 了解计算机网络的概念,了解计算机网络的分类(WAN / MAN / LAN),了解计算机网络的层级结构及作用(TCP/IP 四层模型与 OSI 七层模型),了解不同层级的重要协议,了解 IP 地址及子网划分。

① 按覆盖范围分类:

缩写 全称 中文 范围
LAN Local Area Network 局域网 一栋楼、一个校园
MAN Metropolitan Area Network 城域网 一座城市
WAN Wide Area Network 广域网 跨城市、跨国,如互联网

📝 记忆:L(ocal) 最小 → M(etropolitan) 中等 → W(ide) 最大。

② 两个分层模型(必背对照):

OSI 七层(从上到下) TCP/IP 四层
应用层 应用层
表示层 (并入应用层)
会话层 (并入应用层)
传输层 传输层
网络层 网际层(网络层)
数据链路层 网络接口层
物理层 (并入网络接口层)

📝 OSI 七层口诀(从下往上):物、数、网、传、会、表、应。

③ 各层的重要协议:

协议 干什么的
应用层 HTTP / HTTPS 网页传输(HTTPS 是加密版)
应用层 FTP 文件传输
应用层 SMTP / POP3 发邮件 / 收邮件
应用层 DNS 把域名翻译成 IP 地址
传输层 TCP 可靠传输,要建立连接、会重传
传输层 UDP 不可靠但快,不建立连接
网络层 IP 寻址和路由,负责把包送到目的地

⚠️ TCP 和 UDP 的区别是必考题:

TCP UDP
是否建立连接 是(三次握手)
可靠性 可靠,丢了会重传 不可靠
速度
典型用途 网页、文件下载、邮件 视频直播、语音通话、游戏

④ IP 地址:

IPv4 地址分类(常考 A/B/C 三类):

类别 第一段范围 用途
A 类 1 ~ 126 超大型网络
B 类 128 ~ 191 中型网络
C 类 192 ~ 223 小型网络

几个特殊地址:

子网掩码:用来区分 IP 地址里哪部分是「网络号」、哪部分是「主机号」。常见的 255.255.255.0 表示前三段是网络号、最后一段是主机号。

4.3 程序设计语言分类

考纲原文(3): 了解程序设计语言的几大分类及特点(机器语言、汇编语言、高级语言),了解常见的高级语言(C++、Python 等)。

分类 长什么样 特点
机器语言 二进制 10110000 计算机直接执行,最快,人完全看不懂
汇编语言 助记符 MOV AX, 5 用符号代替二进制,需要汇编程序翻译
高级语言 int a = 5; 接近自然语言,好读好写,需要编译或解释

📝 机器语言和汇编语言合称"低级语言",都依赖具体的机器;高级语言可以跨平台。

高级语言的两种执行方式(必考):

编译型 解释型
怎么执行 整个程序先翻译成机器码,再运行 一行一行边翻译边执行
速度
代表语言 C、C++、Java(半编译) Python、JavaScript

📝 这正是我们从 Python 转 C++ 的原因之一:C++ 是编译型,跑得快,所以竞赛用它。

⚠️ 常考细节:.cpp 是源文件,编译后生成 .exe 可执行文件。 Dev-C++ 里的"编译"就是做这件事,"运行"是执行生成的 exe。

4.4 流程图

考纲原文(4): 了解流程图的概念及基本表示符号,掌握绘制流程图的方法,能正确使用流程图描述程序设计的三种基本结构。

流程图 = 用图形符号把算法的步骤画出来。

基本符号(必背形状):

符号形状 名称 作用
圆角矩形 / 椭圆 起止框 程序的开始和结束
平行四边形 输入输出框 读入数据 / 输出结果
矩形 处理框 赋值、计算
菱形 判断框 条件判断,有两个出口(是 / 否)
带箭头的线 流程线 指示执行方向
小圆圈 连接点 图画不下时接到别处

⚠️ 必考:判断用菱形,输入输出用平行四边形,处理用矩形。 这三个别记混。

三种基本结构:

【顺序结构】            【分支结构】                 【循环结构】

  ┌──────┐              ┌──────┐                   ┌──────┐
  │ 开始 │              │ 开始 │              ┌───▶│ 判断 │
  └───┬──┘              └───┬──┘              │    └───┬──┘
      │                     │                  │     是 │ 否
  ┌───▼──┐             ┌───▼───┐              │  ┌────▼────┐
  │ 步骤A│             ╱  判断  ╲             │  │  循环体 │
  └───┬──┘             ╲        ╱             │  └────┬────┘
      │              是 ╲──┬───╱ 否           │       │
  ┌───▼──┐          ┌────▼┐  ┌▼────┐          └───────┘
  │ 步骤B│          │ 语句1│  │语句2│              (否 → 结束)
  └───┬──┘          └────┬┘  └┬────┘
      │                  └──┬─┘
  ┌───▼──┐              ┌───▼──┐
  │ 结束 │              │ 结束 │
  └──────┘              └──────┘

📝 三种结构的共同点:都只有一个入口、一个出口。 这是结构化程序设计的基本要求,也是判断题常考点。

📝 任何复杂程序都可以由这三种基本结构组合而成——这句话本身就是考点。


五、单选与判断练习

先做完再对答案。

5.1 单选题(每题 2 分)

1. 字符 '0' 的 ASCII 码是:  A. 0 B. 32 C. 48 D. 65

2. 表达式 'a' - 'A' 的值是:  A. 0 B. 32 C. 65 D. 97

3.int a = 7, b = 2;,下列哪个表达式的值是 3.5?  A. a / b B. (double)(a / b) C. (double)a / b D. (int)a / b

4. 下列关于 Cache 的说法,正确的是:  A. 容量比内存大  B. 速度比内存慢  C. 位于 CPU 和内存之间,速度比内存快  D. 断电后数据不丢失

5. 下列哪个是不合法的 IPv4 地址?  A. 192.168.1.1 B. 10.0.0.1 C. 172.16.0.256 D. 127.0.0.1

6. TCP/IP 模型分为几层?  A. 3 层 B. 4 层 C. 5 层 D. 7 层

7. 在流程图中,表示"条件判断"的符号是:  A. 矩形 B. 菱形 C. 平行四边形 D. 圆角矩形

8. 下列语言中属于解释型语言的是:  A. C B. C++ C. Python D. 汇编语言

9. 执行 srand(1); cout << rand() % 6 + 1;,输出值的可能范围是:  A. 0~5 B. 1~6 C. 0~6 D. 1~7

10. 下面这段代码会输出多少行?

for (int i = 1; i <= 3; i++) {
    for (int j = 1; j <= 4; j++) {
        cout << "*";
    }
    cout << endl;
}

 A. 3 行 B. 4 行 C. 12 行 D. 1 行

答案与解析:

答案 解析
1 C 四个锚点之一:空格 32、'0' 48、'A' 65、'a' 97
2 B 97 − 65 = 32,这是大小写字母的固定差值
3 C B 是先整除再转换,转晚了得 3.0;A、D 都是整除得 3
4 C Cache 速度最快、容量最小、断电丢数据
5 C 每段必须在 0~255 之间,256 超范围
6 B TCP/IP 四层:网络接口层、网际层、传输层、应用层
7 B 判断用菱形,有两个出口
8 C Python 是解释型;C/C++ 是编译型;汇编是低级语言
9 B rand() % 6 得 0~5,再 +1 得 1~6
10 A endl 在外层,外层跑 3 次就换 3 次行

5.2 判断题(每题 2 分,对的打 √,错的打 ×)

1. int x = 3.9; 执行后 x 的值是 4。( )

2. sqrt 函数的返回值类型是 int。( )

3. 内存(RAM)断电后数据会丢失,而 ROM 断电后数据保留。( )

4. UDP 协议比 TCP 协议可靠。( )

5. 在双重循环中,break 语句会同时跳出内外两层循环。( )

6. 机器语言可以被计算机直接执行,不需要翻译。( )

7. cout << 'A' + 1; 会输出字符 B。( )

8. 流程图中的每一种基本结构都只有一个入口和一个出口。( )

答案与解析:

答案 解析
1 × doubleint直接砍掉小数,不是四舍五入,结果是 3
2 × 返回 double。这是「本地对、结果错」的常见来源
3 RAM 易失、ROM 非易失,这是两者最根本的区别
4 × 反了。TCP 可靠(会重传),UDP 不可靠但快
5 × break 只跳出离它最近的那一层
6 机器语言就是二进制指令,CPU 直接执行;汇编和高级语言都要翻译
7 × 'A' + 1 的结果类型是 int,输出 66。要输出 B 得写 (char)('A' + 1)
8 单入口单出口是结构化程序设计的基本要求

六、编程练习

先自己写,写完再看参考代码。

题 1 ⭐⭐ 空心矩形

输入两个正整数 n 和 m(3 ≤ n, m ≤ 20),输出一个 n 行 m 列的空心矩形:边框用 *,内部用空格。 样例:输入 4 5,输出

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

参考代码:

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

int main() {
    int n, m;
    cin >> n >> m;

    for (int i = 1; i <= n; i++) {           // 外层:第 i 行
        for (int j = 1; j <= m; j++) {       // 内层:第 j 列
            // 边框的判定:第一行、最后一行、第一列、最后一列
            if (i == 1 || i == n || j == 1 || j == m) {
                cout << "*";
            } else {
                cout << " ";                 // 内部打空格
            }
        }
        cout << endl;                        // ⚠️ 换行放在外层
    }
    return 0;
}

要点:

  1. 嵌套循环 + 一个 if 就够了,不用分成"第一行""中间行""最后一行"三段写
  2. 四个条件用 || 连起来:只要落在任意一条边上就打星号
  3. cout << endl; 放在内层循环的外面——放进去就变成每个字符一行
  4. 每行的空格不能省,题目要的是空心,中间必须有空格占位

⚠️ 自测:输入 3 3 试试。 这是最小情况,此时没有内部,应该输出三行全星号。

题 2 ⭐⭐ 字符分类与转换

输入一个字符 c,按下列规则输出:

样例:输入 K 输出 k;输入 7 输出 8;输入 # 输出 35

参考代码:

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

int main() {
    char c;
    cin >> c;

    if (c >= 'A' && c <= 'Z') {              // 大写字母:ASCII 65~90
        cout << (char)(c + 32) << endl;      // 加 32 变小写,⚠️ 必须转回 char
    } else if (c >= 'a' && c <= 'z') {       // 小写字母:ASCII 97~122
        cout << (char)(c - 32) << endl;      // 减 32 变大写
    } else if (c >= '0' && c <= '9') {       // 数字字符:ASCII 48~57
        cout << (c - '0') + 1 << endl;   // 减 '0' 得数值再加 1,不转 char
    } else {
        cout << (int)c << endl;              // 其他字符:直接当整数打印 ASCII 码
    }
    return 0;
}

要点:

  1. 前两个分支必须 (char) 转回来,否则会打印 97 而不是 a
  2. 第三个分支恰恰不能转 ——题目要的是数值 8,不是字符;而且 9+1=10 是两位数,转 char 就彻底错了
  3. c - '0' 得到数值,这是数字字符转数值的唯一正确写法,别写 c - 48(虽然等价,但可读性差)
  4. 判断范围一律用 >= 且 <=,靠的是字母和数字在 ASCII 表里连续排列

⚠️ 自测边界:AZaz09、空格。 每一类的两个端点都要试——分类题的 bug 全在边界上。

题 3 ⭐⭐⭐ 统计素数

输入一个正整数 n(2 ≤ n ≤ 10000),输出 2 到 n 之间(含 n)素数的个数,以及这些素数的和。两个数用空格隔开。 素数:只能被 1 和它本身整除的、大于 1 的整数。 样例:输入 10,输出 4 17(素数是 2、3、5、7,共 4 个,和为 17)

参考代码:

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

int main() {
    int n;
    cin >> n;

    int cnt = 0;                 // 素数个数
    int sum = 0;                 // 素数之和,两个都要清零

    for (int x = 2; x <= n; x++) {           // 外层:逐个检查 2 到 n
        bool isPrime = true;                 // 先假设 x 是素数
        for (int i = 2; i * i <= x; i++) {   // 内层:试除 2 到 √x
            if (x % i == 0) {                // 能整除 → 有因子 → 不是素数
                isPrime = false;
                break;                       // 已经确定了,立刻跳出内层
            }
        }
        if (isPrime) {                       // 内层跑完还是 true,才是素数
            cnt++;
            sum = sum + x;
        }
    }

    cout << cnt << " " << sum << endl;
    return 0;
}

要点:

  1. i * i <= x 而不是 i <= sqrt(x):一来 sqrt 返回 double 有精度风险,二来 sqrt 每轮都要重算一次,慢。判素数一律写 i * i <= x
  2. isPrime 标志变量必须放在外层循环里面——每检查一个新的 x 都要重新设成 true。放到外面就只能用一次
  3. 找到因子立刻 break:不 break 也对,但白跑
  4. 为什么只试除到 √x 就够? 如果 x = a × b 且 a ≤ b,那么必有 a ≤ √x。所以只要 √x 以内没有因子,就一定是素数
  5. 2 是素数:x = 2 时内层条件 2 * 2 <= 2 一开始就不成立,一次都不进循环,isPrime 保持 true

⚠️ 自测:输入 2 应该输出 1 2 这是最小情况,很多人的代码会在这里把 2 判成非素数。

📝 这题把二级的三个考点凑齐了:嵌套循环、bool 标志、break 素数判断是后面所有等级都会反复用到的零件,务必写熟。


七、考前自查清单

编程部分:

常识部分:

考场习惯:

⚠️ 最后一句:第六节那三道题,合上手册重写一遍,写得出来才算过。