2026年9月 GESP C++ 二级真题解析:循环是主角,转换是配角
二级这张卷,"多层循环"和"数据类型转换"两条线贯穿始终。读懂这两个板块,70% 的分数就稳了。
一、答案速查
判断题官方未公布答案,以下为按题意推算的参考答案。
二、单选题:五个板块
板块 1:计算机基础(第 1、2 题)
第 1 题 → C:与一级第 1 题完全相同——IDE 的功能边界(不能直接控制硬件)。
第 2 题 → B:Cache 的正确定位是"暂存 CPU 频繁访问的数据"。
一句话记忆:寄存器最快最小 → Cache 次之 → 主存最慢最大,且 Cache 是易失的。
板块 2:类型转换与布尔运算(第 3、4 题)
第 3 题 → A:cout << (3 == 3.0);比较时 int 3 会隐式提升为 double 3.0,3 == 3.0 成立,输出 1。
陷阱:有人以为"整数和浮点数不能直接比较",实际上 C++ 会自动做类型提升。
第 4 题 → D:cout << (bool(5) + bool(-5) + bool(5.0));bool 转换规则:非 0 即真。5、−5、5.0 全部为真 → 1 + 1 + 1 = 3。
关键点:
bool参与算术运算时会提升为int,true当 1、false当 0 用。
板块 3:逻辑表达式与分支(第 5、9 题)
第 5 题 → A:闰年条件
(N % 4 == 0 && N % 100 != 0) || (N % 400 == 0)B 错在缺括号: &&优先级高于||,N % 4 == 0 && N % 100 == 0 || N % 400 == 0会先算前半段,逻辑不成立;C 用 /代替%,完全错(N / 4 == 0只有 N 很小时才成立);D 用了 &&连接两个互斥条件,永远为假。
闰年判断是"必考级"知识点,
%和括号一个都不能错。
第 9 题 → B:for (i = -5; i < 5; i++) if (not(i % 3 != 0)) tot += 1;
not(x) 等价于 !x。先看内层:i % 3 != 0 为真表示"i 不是 3 的倍数";再取 not → 条件变成"i 是 3 的倍数"。
i 取 −5 ~ 4 中 3 的倍数:−3、0、3 →3 个。
这类题不用逐个数,先把逻辑表达式化简,再找满足条件的数。
板块 4:多层循环(第 6、7、8、11、12 题)
第 6 题 → C
for (i = 0; i < 10; i++) if (i) tot += 1;if (i) 表示 i != 0。i = 1~9 共9次。
if (i)就是if (i != 0),这是 C++ 的简写习惯,必须一眼看懂。
第 7 题 → B(n = 4)
for (i = 1; i < n; i++) // i = 1, 2, 3for (j = 1; j < i; j++) // i=1: 0次 i=2: 1次 i=3: 2次tot += 1;
总数 = 0 + 1 + 2 =3。
结果是
C(n-1, 2),n = 4 时为 3。
第 8 题 → D
for (i = 0; i < 10; i++) if (i % 3) tnt += i;i % 3 非 0 即 i 不是 3 的倍数:1、2、4、5、7、8 → 和 =27。
第 11 题 → D
i = 1;while (i <= 3) { for (j = 1; j < i + 1; j++) total += i * j; i += 1; }
i = 1:1×1 = 1 → total = 1 i = 2:2×1 + 2×2 = 6 → total = 7 i = 3:3×1 + 3×2 + 3×3 = 18 → total = 25
第 12 题 → C(输出 4 1 2)
for (i = 1; i < 4; i++)for (j = 0; j < i; j++) {if (j % 3 == 0) continue; // j=0 时直接跳过count += 1;if (i * j >= 2) break;}printf(”%d %d %d”, i, j, count);
i = 1:只有 j = 0,被 continue跳过 → count 不变i = 2:j = 0 跳过;j = 1 → count = 1, 2×1 ≥ 2→ breaki = 3:j = 0 跳过;j = 1 → count = 2, 3×1 ≥ 2→ break循环变量:外层走完后 i = 4,内层最后一次 break 时 j = 1
输出 4 1 2。
注意:
for循环结束后,内层变量保留的是最后一次执行时的值,外层变量则是超出边界的值。
板块 5:填空与算法应用(第 10、13、14、15 题)
第 10 题 → D(选"错误的"):素数判定程序的边界分析
limit = sqrt(n) + 1;for (i = 2; i < limit; i++)if (n % i == 0) { printf(”%d 非素数”, n); break; }if (i >= limit) printf(”%d 是素数”, n);
A ✔: n <= 1分支不能省,否则 0、1 会被误判为素数;B ✔:省略 n == 2分支后,n = 2 走 else,limit = 1 + 1 = 2,循环不执行,i = 2 >= 2成立,仍输出"2 是素数",结果不变;C ✔: break不能省,否则非素数会继续循环到i >= limit,被误判为素数;D ✘ 错误:把 +1改成很大的数(比如 100)时,limit可能超过n,循环会枚举到i = n,此时n % n == 0成立,素数会被误判为合数。
这是二级最有区分度的一道题。它考的不是"会不会写素数判定",而是能不能分析边界。
第 13 题 → A:line - j - 1
输出图形共 12 行,第 0 行前有 11 个空格、第 1 行前有 10 个……最后一行前 0 个空格。
空格数 = 总行数 - 1 - 当前行号 = line - j - 1这是"居中图形"的标准公式:每行先补空格,再打字符。二级几乎每场都会出现这类图形题——2026 年 6 月是矩形边框的条件填空,本次是居中数字塔,2025 年则考过等腰三角形。换个图形、换个字符,内核都是同一个双重循环模型。
第 14、15 题 → 均为 A(同一情境的两种代码版本)
场景:找"身高最接近 1.65 米"的小朋友,若差值相同则取较矮的那个。
版本一(单横线)
if (diff < min_diff || (diff == min_diff && h < best_height)) {min_diff = diff;best_height = h;}
版本二(else-if 分支)
if (diff < min_diff) { min_diff = diff; best_height = h; }else if (diff == min_diff) { if (h < best_height) best_height = h; }
两个关键点
差值更小 → 一定更新( diff < min_diff);差值相等时,只更新更矮的( h < best_height)——这就是"取较矮的第一个"的实现。
干扰项
diff <= min_diff && h < best_height错在:差值相等但身高更高时也会被排除,逻辑不完整。
三、判断题(10 题)
参考答案:√ √ × × × √ √ √ √ ×
cin / scanf | ||
5 && 2 | ||
'2'2 * (-50) / 4 = -25,不是 −1 | ||
a == +5; | ||
not 5 = 0not 0 = 1,输出 1,不是 5 | ||
i % 3 == 0369 | ||
for (i = 0; i < N + 1; i++) tot += i; | ||
continue,内层从不执行,cnt = 0,输出 10 × 0 = 0 | ||
int(sqrt(N))int(sqrt(5)) = 2 = abs(2),程序会误判"5 是 2 的平方" |
两处高频误区
第 3 题:把 '2'当成数字 2。字符常量'2'参与运算时用的是 ASCII 码 50。第 4 题: ==是判断相等,=才是赋值。少打一个等号,行为完全不同——这是 C++ 最经典的坑。
四、编程题
4.1 直角三角形
题意:给定数列前两项 a1、a2,从第三项起 a_k = √(a_{k-1}² + a_{k-2}²)。求第几项开始超过给定上限 U。
样例:3.0、4.0、上限 10.0
a1 = 3.0 a2 = 4.0 a3 = 5.0 a4 ≈ 6.403a5 ≈ 8.124 a6 ≈ 10.344 > 10 → 答案 6
参考实现
double a, b, U;cin >> a >> b >> U;int ans = 1;if (a <= U) ans++;while (b <= U) {ans++;double t = sqrt(a * a + b * b);a = b; b = t; // 滚动前进}cout << ans << endl;
三个关键点
用滚动变量,不要开数组:只需保留前两项。 开方用 sqrt(),必须#include <cmath>,返回double。计数逻辑要想清楚: ans表示"当前已经数到第几项",一旦b > U就不再累加,此时ans就是第一个超限的项号。
易错:把
ans初始化成 0 或漏掉a1的判断,会整体差 1。
4.2 字符变换
题意:8 行 16 列的画布,共 128 格,从 1 开始按行编号。初始全是 *。给定 3 个 ASCII 码值,把对应编号的格子换成该字符,输出最终画布。
核心换算
编号 id → 行 = (id - 1) / 16 + 1列 = (id - 1) % 16 + 1
样例:48 → 第 3 行第 16 列 → 0;65 → 第 5 行第 1 列 → A;97 → 第 7 行第 1 列 → a
***********************************************0****************A*******************************a*******************************
参考实现(计数器法,最简洁)
int a, b, c, p = 0;cin >> a >> b >> c;for (int i = 1; i <= 8; ++i) {for (int j = 1; j <= 16; ++j) {++p;if (p == a) cout << (char)a;else if (p == b) cout << (char)b;else if (p == c) cout << (char)c;else cout << '*';}cout << '\n';}
三个关键点
(char)转换:输入的整数本身就是 ASCII 码(48 是 '0'、65 是'A'、97 是'a'),直接做强转即可。编号 vs 下标:画布编号从 1 开始,用计数器 p自增最省事,避免(id-1)/16的换算错误。每行结束要换行,且用一个 for控制 8 行 16 列,不要手写 128 个字符。
五、二级划重点
bool | |
if (i) | if (i != 0) |
continuebreak 位置 | |
sqrtabs、pow、max、min | |
总行数 - 行号 - 1(居中图形) | |
(id-1) / 列数(id-1) % 列数 |