乐于分享
好东西不私藏

GESP 2026年3月C++四级真题完整解析

GESP 2026年3月C++四级真题完整解析

GESP 2026年3月C++四级真题完整解析

CCF GESP 编程能力等级考试 · 2026年3月认证

C++ 四级 · 满分100分 · 27题

获取 202603gesp4级完整真题及详细解析.pdf

请关注状元编程公众号,回复 202603gesp4


📋 考试概况

项目
内容
等级
C++ 四级
题量
15单选 + 10判断 + 2编程
分值
30 + 20 + 50 = 100分
核心考点
指针与引用、结构体、异常处理、排序算法、递推

一、单选题(每题2分,共30分)

第1题

执行下面程序后,输出为?

intf(int x = 2)return x * 3; }intmain(){ cout << f() << " " << f(4); }

A) 6 6  B) 6 12  C) 4 12  D) 2 12


答案:B(6 12)

f() 无实参,使用默认参数 x=2,返回 2×3=6f(4) 实参为4,返回 4×3=12

💡 知识点:默认参数。当函数声明中某参数有默认值时,调用时可省略该实参。默认参数必须从右向左依次设置。


第2题

执行下面代码后,输出为?

int a = 5;int* p = &a;int** q = &p;**q += 7;cout << a << " " << *p;

A) 5 5  B) 12 12  C) 5 12  D) 12 5


答案:B(12 12)

q 是指向指针 p 的指针,p 指向 a

  • **q → 先解引用 q 得到 p,再解引用 p 得到 a
  • **q += 7 等价于 a += 7a 从5变为12
  • *p 等价于 a,也为12

💡 知识点:二级指针。int** q 表示"指向指针的指针",**q 最终访问的是 a 本身。


第3题

已知二维数组 a[3][4] 和行指针 int (*p)[4] = a,表达式 *(*(p+2)+1) 的值为?

A) 7  B) 10  C) 11  D) 14


答案:B(10)

设数组初始值为按行存储的1~12:

a[0][0]=1  a[0][1]=2  a[0][2]=3  a[0][3]=4a[1][0]=5  a[1][1]=6  a[1][2]=7  a[1][3]=8a[2][0]=9  a[2][1]=10 a[2][2]=11 a[2][3]=12
  • p+2 → 指向第3行(索引2)
  • *(p+2) → 第3行首地址,即 a[2][0] 的地址
  • *(p+2)+1 → a[2][1] 的地址
  • *(*(p+2)+1) → a[2][1] = 10

💡 知识点:数组指针与二维数组。int (*p)[4] 是"指向含4个int元素的一维数组的指针"。


第4题

值传递、引用传递、指针传递混合题,输出为?

voidfun(int a, int &b, int *c){ a+=1; b+=2; *c+=3; }intmain()int x=1,y=1,z=1fun(x,y,&z); cout<<x<<" "<<y<<" "<<z; }

A) 2 3 4  B) 1 3 4  C) 1 1 4  D) 1 3 1


答案:B(1 3 4)

  • a值传递:修改不影响 xx 仍为1
  • b引用传递b+=2 等价于 y+=2y=3
  • c指针传递*c+=3 等价于 z+=3z=4

💡 知识点:三种参数传递方式的区别。值传递复制副本不影响原变量;引用传递直接操作原变量;指针传递通过地址间接操作原变量。


第5题

全局变量与局部变量、引用传递,输出为?

int x = 3;voidf(int& x){ x += 2; }intmain()int x = 10f(x); cout << x << " " << ::x; }

A) 12 3  B) 10 3  C) 12 5  D) 10 5


答案:A(12 3)

  • f(x) 中的 x 是主函数局部变量(值10),引用传递后 +2 变为12
  • ::x 为全局变量,值仍为3,未被修改

⚠️ 易错点f(int& x) 的参数 x 绑定的是调用时传入的变量。在 main 中调用 f(x) 时,传入的是局部变量 x(值10),不是全局变量 x(值3)。::x 是作用域解析运算符,专门访问全局变量。


第6题

下列结构体初始化写法,正确的是?

A)Point p = (1, 2);B)Point p = {1, 2};

C)Point p = new Point(1, 2);D)Point p = <1, 2>;


答案:B

structPoint { int x, y; };Point p = {12};  // ✅ 正确
  • A:(1,2) 圆括号不能用于结构体初始化 ❌
  • B:花括号 {} 是正确的初始化方式 ✅
  • C:new 返回指针,不能赋给非指针变量 ❌
  • D:<1,2> 语法非法 ❌

第7题

结构体值传递与引用传递,输出为?

structS { int a; int b; };voidg(S s){ s.a += 10; }   // 值传递voidh(S& s){ s.b += 10; }  // 引用传递intmain(){ S s{1,2}; g(s); h(s); cout << s.a << " " << s.b; }

A) 11 12  B) 1 12  C) 11 2  D) 1 2


答案:B(1 12)

  • g(s)值传递:函数内修改的是副本,不影响原结构体 → s.a 仍为1
  • h(s)引用传递:直接操作原结构体 → s.b 从2变为12

第8题

关于递推算法的描述,正确的是?

A) 函数自己调用自己

B) 递推从已知初值出发,利用递推关系逐步推出后续结果

C) 递推算法的时间复杂度一定是指数级

D) 递推需要回溯过程


答案:B

  • A:函数自己调用自己是递归的特征 ❌
  • B:正确描述递推算法 ✅
  • C:递推不局限于指数复杂度 ❌
  • D:递推不需要回溯 ❌

💡 递推 vs 递归:递推是"自底向上"迭代推导;递归是"自顶向下"分解问题再合并。


第9题

执行 climb(6) 的返回值为?(类斐波那契数列)

A) 8  B) 13  C) 21  D) 34


答案:B(13)

数列前6项:1, 2, 3, 5, 8, 13

i
a
b
c
3
2
3
3
4
3
5
5
5
5
8
8
6
8
13
13

💡 斐波那契数列f(n) = f(n-1) + f(n-2),是递推算法最经典的例子。


第10题

判断排序算法稳定性:

  • 初始:(90,'A'), (90,'B'), (80,'C'), (90,'D')
  • 排序后:(80,'C'), (90,'A'), (90,'B'), (90,'D')

A) 不稳定  B) 稳定  C) 无法判断  D) 取决于实现


答案:B(稳定)

相同分数90的三个元素排序后相对顺序未变(A→B→D),符合稳定排序定义。

💡 稳定排序:相同关键字元素在排序后保持原有相对顺序。常见的稳定排序有冒泡排序、插入排序、归并排序;不稳定的有选择排序、快速排序、堆排序。


第11题

插入排序,横线处应填写?

while(j >= 0 && __________){ a[j+1] = a[j]; j--; }

A)a[j] < keyB)a[j] > keyC)a[j] >= keyD)a[j] != key


答案:B(a[j] > key

升序插入排序,当前元素大于待插入元素时需后移,条件为 a[j] > key

💡 注意:用 > 而非 >= 可保证排序的稳定性


第12题

下列代码段的时间复杂度为?(双重嵌套循环)

for (int i = 0; i < n; i++)for (int j = 0; j < n; j++)// O(1) 操作

A) O(n)  B) O(n log n)  C) O(n²)  D) O(2ⁿ)


答案:C(O(n²))

两层 for 循环各执行 n 次,总操作次数为 n×n = n²,时间复杂度为 O(n²)


第13题

哪种方式不能将字符串输出重定向到文件 log.txt

A)freopen("log.txt", "w", stdout); cout << "Welcome";B)std::ofstream outFile("log.txt"); cout << "Welcome"; outFile.close();C)std::ofstream outFile("log.txt"); outFile << "Welcome"; outFile.close();D) 使用Shell重定向 ./program > log.txt


答案:B

选项B创建了文件流 outFile,但使用 cout 输出,没有进行重定向,内容不会写入文件。

⚠️ 易错点freopen 可以将 stdout 重定向到文件;ofstream 需要直接用 outFile << ... 输出。创建 ofstream 对象不会自动改变 cout 的输出目标。


第14题

C++异常处理,输出结果是?

intdivi(int a,int b)if(b==0throw0return a/b; }// catch(const char* msg) → 输出"A"// catch(int) → 输出"B"

A) 输出"A"  B) 输出"B"  C) 程序崩溃  D) 无输出


答案:B(输出"B")

throw 0 抛出的是 int 类型异常,匹配第二个 catch(int) 块,输出 "B"

💡 知识点:异常类型匹配。catch 块按声明顺序匹配,throw 的类型决定哪个 catch 被执行。


第15题

排行榜元素向前移动,while循环条件应为?

A)i > 0 && cur.score > players[i-1].score

B)i > 0 && cur.score < players[i-1].score

C)i > 0 && cur.score >= players[i-1].score

D)i > 0 && cur.score <= players[i-1].score


答案:A

  • i > 0:防止越界
  • cur.score > players[i-1].score:当前玩家分数高于前一位时继续向前移动(分数高排前面)

💡 这是插入排序的变体应用,在排行榜场景中按分数从高到低排序。


二、判断题(每题2分,共20分)

题号
答案
要点说明
第1题
✅ 正确
add10
 引用传递,a = 5+10 = 15
第2题
✅ 正确
引用一旦绑定变量,不能再绑定其他变量
第3题
❌ 错误
&a[1][2] - &a[0][1] = 4
,不是5
第4题
❌ 错误
calc(5)
 存在调用歧义(重载冲突),编译报错
第5题
✅ 正确
f()
 输出局部变量20,main 输出全局变量10,合并为2010
第6题
❌ 错误
未显式初始化的局部指针不会自动为 nullptr(全局/静态变量才会)
第7题
✅ 正确
嵌套结构体语法合法,代码无语法错误
第8题
❌ 错误
cout << "Hello"
 输出到控制台,文件内容为空
第9题
❌ 错误
插入排序最好情况O(n),选择排序始终O(n²),两者不能互相替代
第10题
❌ 错误
该程序用循环实现,时间复杂度为 O(n),不是O(2ⁿ)

判断题精选解析

第3题:二维数组 a[3][4] 按行存储,&a[1][2] 是第1行第2列,&a[0][1] 是第0行第1列。两者地址差 = (1行 × 4列 + 2列) - (0行 × 4列 + 1列) = 6 - 1 = 5... 实际上:

  • a[0][1] 的线性索引:0×4+1 = 1
  • a[1][2] 的线性索引:1×4+2 = 6
  • 差值 = 6 - 1 = 5?

但题目说答案是"不是5"——关键是 int 占4字节,地址差以元素个数为单位是5,但如果问的是字节数差则是 5×4=20。具体取决于题目表述。

⚠️ 仔细审题:地址运算的差值含义(元素个数 vs 字节数)是常见陷阱。

第4题:函数重载歧义。当存在 calc(int) 和 calc(double) 两个重载,调用 calc(5) 时 5 可以隐式转换为 int 或 double,编译器无法确定选择哪个,导致二义性错误

第6题:局部变量(包括指针)存储在栈上,不会自动初始化,值是未定义的(垃圾值)。只有全局变量和静态变量才会自动初始化为0(指针为 nullptr)。

第9题

  • 插入排序:最好情况(已排序)O(n),最坏O(n²)
  • 选择排序:无论什么情况都是O(n²)
  • 两者复杂度不同,不能互相替代

第10题

intf(int n){int result = 1;for (int i = 1; i <= n; i++)        result *= i;return result;}

这是用循环计算阶乘,循环执行n次,时间复杂度为 O(n),不是O(2ⁿ)。


三、编程题(每题25分,共50分)

3.1 山之谷

题目描述: N行M列网格,若某单元格海拔不高于其所有8个方向相邻单元格的海拔,则为"山谷",统计山谷数量。

数据范围: 1≤N,M≤100,1≤h≤10⁵

核心思路: 在网格外围填充一圈高海拔值(>10⁵),统一处理边界,遍历每个格子检查8个方向。

参考程序:

#include<iostream>usingnamespace std;intmain(){int n, m, cnt = 0, k;int h[105][105];// 8个方向偏移量int mark[8][2] = {{-1,-1},{-1,0},{-1,1},{0,-1},{0,1},{1,-1},{1,0},{1,1}};    cin >> n >> m;for (int i = 1; i <= n; i++)for (int j = 1; j <= m; j++)            cin >> h[i][j];// 外围填充高海拔(哨兵法)for (int i = 0; i <= max(n,m)+1; i++)        h[i][0] = h[0][i] = h[i][m+1] = h[n+1][i] = 1e6;// 遍历每个格子检查是否为山谷for (int i = 1; i <= n; i++)for (int j = 1; j <= m; j++) {for (k = 0; k < 8; k++)if (h[i][j] > h[i+mark[k][0]][j+mark[k][1]]) break;if (k == 8) cnt++;  // 8个方向都不比当前低 → 山谷        }    cout << cnt;return0;}

💡 技巧:外围填充哨兵值(极大值),避免对边界格子单独判断,代码更简洁。


3.2 礼盒排序

题目描述: 对n个礼盒按以下规则升序排序:

  1. 总价格从小到大
  2. 总价相同 → 最贵商品价格从小到大
  3. 仍相同 → 最便宜商品价格从小到大
  4. 仍相同 → 编号从小到大

数据范围: 1≤n≤10³,1≤k≤10,商品价格≤10⁴

核心思路: 用结构体存储每个礼盒的编号、总价、最高价、最低价,使用 sort + 自定义比较函数排序。

参考程序:

#include<iostream>#include<algorithm>usingnamespace std;structbox {int bh, sum, max, min;} giftbox[1005];// 自定义比较函数:多关键字排序boolcmp(const box &a, const box &b){if (a.sum != b.sum) return a.sum < b.sum;if (a.max != b.max) return a.max < b.max;if (a.min != b.min) return a.min < b.min;return a.bh < b.bh;}intmain(){int n, k, b;    cin >> n >> k;for (int i = 0; i < n; i++) {        giftbox[i].bh = i + 1;  // 编号从1开始        giftbox[i].sum = 0;for (int j = 1; j <= k; j++) {            cin >> b;            giftbox[i].sum += b;if (j == 1) {                giftbox[i].max = b;                giftbox[i].min = b;continue;            }if (b > giftbox[i].max) giftbox[i].max = b;elseif (b < giftbox[i].min) giftbox[i].min = b;        }    }sort(giftbox, giftbox + n, cmp);for (int i = 0; i < n; i++)if (i == 0) cout << giftbox[i].bh;else cout << " " << giftbox[i].bh;return0;}

💡 技巧:多关键字排序时,在 cmp 函数中依次比较各个关键字,先比较的优先级更高。sort 默认不稳定,但配合编号作为最后关键字可保证唯一排序结果。


📊 答案速查表

单选题

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
B
B
B
B
A
B
B
B
B
B
B
C
B
B
A

判断题

1
2
3
4
5
6
7
8
9
10

📈 考点分布分析

知识模块
题号
分值
占比
函数参数传递(值/引用/指针)
单1,4,5,7 + 判1,2
12
12%
指针与二维数组
单2,3 + 判3
6
6%
结构体定义与初始化
单6,7 + 判7
6
6%
函数重载与歧义
判4
2
2%
作用域(全局/局部变量)
单5 + 判5
4
4%
指针初始化
判6
2
2%
递推算法
单8,9
4
4%
排序算法(稳定性/插入排序/复杂度)
单10,11,12 + 判9
10
10%
文件I/O
单13 + 判8
4
4%
异常处理
单14
2
2%
排行榜/插入排序应用
单15
2
2%
时间复杂度分析
判10
2
2%
编程:网格遍历
编1
25
25%
编程:多关键字排序
编2
25
25%
合计100100%

💡 备考建议

  1. 扎实掌握三种参数传递方式:值传递、引用传递、指针传递是四级核心考点,务必理解每种方式对原变量的影响
  2. 理解指针与数组的关系:一级指针、二级指针、数组指针(行指针)的概念和用法,多做指针运算题
  3. 结构体是重点:结构体定义、初始化、值传递vs引用传递,是高频考点
  4. 排序算法要全面掌握:不仅会写代码,还要理解稳定性、时间复杂度、适用场景
  5. 递推与递归的区别:递推是迭代推导,递归是自调用分解,两者思想不同
  6. 异常处理的类型匹配throw 的类型决定匹配哪个 catch 块,注意类型转换规则
  7. 编程题注意边界处理:使用哨兵法(外围填充特殊值)可以简化边界判断,减少代码复杂度
  8. 多关键字排序:掌握 sort + 自定义 cmp 函数的写法,注意比较顺序对应优先级

📌 GESP C++ 四级 考察的核心是 C++ 中高级特性:指针、引用、结构体、异常处理,以及基础算法(排序、递推)。相比三级,四级更侧重于内存模型理解算法思维,建议在掌握语法的基础上多练习编程实现。