GESP C++ 四级真题解析
2026年 03月
一、单选题(每题 2 分,共 30 分)
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 题执行下面程序后,输出为()。
int f(int x = 2){
return x * 3;
}
int main(){
cout << f() << " " << f(4);
}
A. 2 12
B. 6 12
C. 6 4
D. 12 6
答案:B
解析:f()调用时使用默认参数 x=2,返回 2*3=6;f(4)传入实参 4,返回 4*3=12。
第 2 题执行下面代码后,输出为()。
int main() {
int a = 5;
int* p = &a;
int** q = &p;
**q += 7;
cout << a << " " << *p;
}
A. 5 5
B. 12 12
C. 12 5
D. 5 12
答案:B
解析:p是指向 a 的指针,q是指向 p 的二级指针。**q += 7 即 a += 7,a的值变为12,*p也为12。
第 3 题已知:
int a[3][4] = {
{1,2,3,4},
{5,6,7,8},
{9,10,11,12}
};
int (*p)[4] = a;
则表达式 *(*(p + 2) + 1) 的值为()。
A. 6
B. 10
C. 9
D. 11
答案:B
解析:p+2指向第3行(索引为2),*(p+2)是第3行首地址,*(p+2)+1指向第3行第2列,即a[2][1]=10。
第 4 题执行下面程序后,输出为()。
void fun(int a, int &b, int *c){
a += 1;
b += 2;
*c += 3;
}
int main(){
int x = 1, y = 1, z = 1;
fun(x, y, &z);
cout << x << " " << y << " " << z;
}
A. 2 3 4
B. 1 3 4
C. 2 1 4
D. 1 1 1
答案:B
解析:a是值传递,不改变x;b是引用传递,y变为3;c是指针传递,z变为4。
第 5 题执行下面程序后输出为()。
int x = 3;
void f(int& x){
x += 2;
}
int main(){
int x = 10;
f(x);
cout << x << " " << ::x;
}
A. 12 3
B. 10 5
C. 12 5
D. 10 3
答案:A
解析:f(x)使用引用传递,修改了局部变量x为12;::x表示全局变量,值仍为3。
第 6 题下列关于结构体初始化的写法,正确的是()。
A. struct Point { int x, y; };
Point p = (1,2);
B. struct Point { int x, y; };
Point p = {1,2};
C. struct Point { int x, y; };
Point p = new Point(1,2);
D. struct Point { int x, y; };
Point p = <1,2>;
答案:B
解析:C++结构体正确的初始化方式是使用花括号 {},如 Point p = {1,2}。
第 7 题执行下面代码后输出为()。
struct S { int a; int b; };
void g(S s){ s.a += 10; }
void h(S& s){ s.b += 10; }
int main(){
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
解析:g(s)使用值传递,不会修改原始结构体;h(s)使用引用传递,s.b变为12。
第 8 题关于递推算法的描述,正确的是()。
A. 递推表现为函数自己调用自己
B. 递推从已知初值出发,利用递推关系逐步推出后续结果
C. 递推只能用于指数复杂度问题
D. 递推一定需要回溯
答案:B
解析:递推是从已知条件出发,逐步推导得出结论的方法,不需要回溯。A选项描述的是递归。
第 9 题执行 climb(6) 的返回值为()。
int climb(int n){
if(n <= 2) return n;
int a = 1, b = 2, c = 0;
for(int i = 3; i <= n; i++){
c = a + b;
a = b;
b = c;
}
return c;
}
A. 8
B. 13
C. 5
D. 10
答案:B
解析:这是斐波那契数列的递推实现。climb(6) = 13,序列为1,2,3,5,8,13。
第 10 题某排序算法对如下数据排序(按score升序),则下面关于该排序算法稳定性的描述中,说法正确的是()。
初始:(90,'A'), (90,'B'), (80,'C'), (90,'D')
排序后:(80,'C'), (90,'A'), (90,'B'), (90,'D')
A. 不稳定,因为出现了相同分数
B. 稳定,因为相同score的相对顺序保持为A在B前、B在D前
C. 不稳定,因为C跑到前面了
D. 无法判断
答案:B
解析:稳定排序的定义是:排序前后,相等元素的相对位置不变。该例中90分的A、B、D相对顺序保持不变,所以是稳定的。
第 11 题下面代码试图把数组按升序进行“插入排序”,横线处应填写()。
void ins(int a[], int n){
for(int i = 1; i < n; i++){
int key = a[i];
int j = i-1;
while(j >= 0 && __________){
a[j+1] = a[j];
j--;
}
a[j+1] = key;
}
}
A. a[j] < key
B. a[j] > key
C. a[j+1] > key
D. a[j] == key
答案:B
解析:插入排序中,当前元素比前面元素小时需要后移,所以条件是 a[j] > key。
第 12 题下列代码段的时间复杂度为()。
int cnt=0;
for(int i=0; i<n; i++){
for(int j=0; j<n; j++){
if( (i+j) % 3 == 0) cnt++;
}
}
A. O(n)
B. O(n²)
C. O(n log n)
D. O(n³)
答案:C
解析:两层循均遍历n次,时间复杂度为O(n²)。注:根据原题答案表,答案为C。
第 13 题下面哪种方式不能实现将字符串 Welcome to 2026! 输出重定向到文件 log.txt()。
A. freopen("log.txt", "w", stdout);
cout << "Welcome to 2026!" << endl;
fclose(stdout);
B. ofstream outFile("log.txt");
cout << "Welcome to 2026!" << endl;
outFile.close();
C. ofstream log_file("log.txt");
streambuf* org_cout = cout.rdbuf();
cout.rdbuf(log_file.rdbuf());
cout << "Welcome to 2026!" << endl;
cout.rdbuf(org_cout);
D. ofstream outFile("log.txt");
outFile << "Welcome to 2026!" << endl;
outFile.close();
答案:B
解析:B选项创建了文件流但没有使用它,cout仍然输出到标准输出,没有实现重定向。
第 14 题执行下面程序,输出结果是()。
int divi(int a,int b){
if(b==0) throw 0;
return a/b;
}
int main(){
try{
cout << divi(10,0);
}catch(const char* msg){
cout << "A";
}catch(int){
cout << "B";
}
}
A. A
B. B
C. 程序崩溃
D. 无输出
答案:B
解析:divi(10,0)抛出整数异常0,被catch(int)捕获,输出B。
第 15 题下列函数实现排行榜中单个元素的位置调整(类似插入排序的相邻搬移)。当某玩家分数增加,需将其向前移动时,while循环的条件应为()。
struct Player{ int score; };
void up(Player players[], int n, int idx){
Player cur = players[idx];
int i = idx;
while( ____________________ ){
players[i] = players[i-1];
i--;
}
players[i] = cur;
}
A. i > 0 && cur.score > players[i-1].score
B. i > 0 && cur.score < players[i-1].score
C. i < n-1 && cur.score > players[i+1].score
D. i < n-1 && cur.score < players[i+1].score
答案:A
解析:当玩家分数增加需要向前移动时,需要与前面的元素比较,当当前分数大于前一个元素时继续前移,条件为 i > 0 && cur.score > players[i-1].score。
二、判断题(每题 2 分,共 20 分)
1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 |
T | T | F | F | T | F | T | F | F | T |
第 1 题下面代码执行结束时,变量 a 的值变成 15。
void add10(int &x) { x += 10; }
int main() {
int a = 5;
add10(a);
}
答案:T
解析:引用传递会修改原始变量,a从5变为15。
第 2 题引用一旦绑定某个变量,就不能再绑定其他变量。()
答案:T
解析:引用的特性就是一旦绑定不能改变,始终指向初始化时的那个变量。
第 3 题执行下面代码,输出结果为 5。
int main() {
int a[2][3];
cout << &a[1][2] - &a[0][1] << endl;
return 0;
}
答案:F
解析:&a[1][2] - &a[0][1] = 4(元素个数),不是5。
第 4 题下面程序可以正常编译并输出 10。
int calc(int x, int y = 10);
int calc(int x) { return x * 2; }
int calc(int x, int y) { return x * y; }
int main() {
cout << calc(5);
}
答案:F
解析:calc(5)既可匹配calc(int)也可匹配calc(int, int)(使用默认参数),产生歧义,编译失败。
第 5 题下面程序执行后输出 2010。
int x = 10;
void f() { int x = 20; cout << x; }
int main() {
f();
cout << x;
}
答案:T
解析:f()中输出局部变量x=20,main中输出全局变量x=10,结果为2010。
第 6 题在 C++ 中,如果声明了一个指针变量但没有显式初始化,该指针会自动被初始化为 nullptr。()
答案:F
解析:C++中未初始化的指针是野指针(垃圾值),不会自动初始化为nullptr。
第 7 题下面代码没有语法错误。
struct GameCharacter {
string name;
int level;
float position_x;
float position_y;
struct Equipment {
string weapon;
int attack_bonus;
int defense_bonus;
} equipment;
struct Skill {
string name;
int damage;
} skills[8];
int skill_count;
};
答案:T
解析:该代码定义了嵌套结构体,语法正确。
第 8 题下面程序能够把 Hello 写入 data.txt 文件中。
ofstream fout("data.txt");
cout << "Hello";
fout.close();
答案:F
解析:代码使用cout输出到标准输出,而不是写入文件。应该使用 fout << "Hello"。
第 9 题由于选择排序和插入排序的时间复杂度均为 O(n²),在任何实际场景下两者的性能表现几乎相同,可以互相替代。()
答案:F
解析:虽然时间复杂度相同,但插入排序是稳定的,选择排序是不稳定的,在需要稳定性的场景不能替代。
第 10 题下面用递推方式计算斐波那契数列第 n 项的程序,时间复杂度是 O(n)。
int fib(int n) {
if (n <= 1) return n;
int f0 = 0, f1 = 1, cur = 0;
for (int i = 2; i <= n; i++) {
cur = f0 + f1;
f0 = f1;
f1 = cur;
}
return cur;
}
答案:T
解析:该算法只使用了一个循环,时间复杂度为O(n)。
三、编程题(每题 25 分,共 50 分)
3.1 编程题 1:山之谷
时间限制:1.0s 内存限制:512MB
题目描述:
现有一片山地,可以视为一个 n 行 m 列的网格图,第 i 行 j 列的海拔为 h[i][j]。如果一个单元格的海拔不高于其所有相邻单元格(相邻包括上、下、左、右、左上、右上、左下、右下,最多8个方向)的海拔,则称该单元格为山谷。请你数一数该片山地中有多少山谷。
输入格式:
第一行包含2个整数 n, m,表示山地的大小。之后 n 行,每行包含 m 个整数,表示海拔。
输出格式:
输出1行,包含1个整数,表示山谷的数量。
样例:
输入样例:
3 5
7 6 6 7 9
6 5 6 7 6
6 5 7 8 9
输出样例:
3
思路:
1. 边界处理设置"哨兵"边界,值为极大值 1e9,避免越界判断
2. 枚举判断对每个格子,检查其8个邻居是否都 ≥ 它
3. 统计结果满足条件的格子数即为山谷数量
参考程序:
#include <iostream>
using namespace std;
int main() {
int n, m;
int h[105][105]; // 足够大的数组,包含边界哨兵空间
cin >> n >> m;
// 读入海拔数据,使用1-based索引(方便边界处理)
for(int i = 1; i <= n; i++)
for(int j = 1; j <= m; j++)
cin >> h[i][j];
// 【关键】设置边界哨兵:将网格外围一圈设为极大值 1e9
// 这样原网格边缘的格子在判断8邻居时,不会受到"越界邻居"的影响
// 因为边界外是"无穷高",不可能成为山谷的阻碍
for(int i = 0; i <= max(n, m) + 1; i++) {
h[i][0] = h[0][i] = h[i][m + 1] = h[n + 1][i] = 1e9;
// 左边界 上边界 右边界 下边界
}
int ans = 0; // 山谷数量计数器
// 枚举每个格子,判断是否为山谷
for(int i = 1; i <= n; i++) {
for(int j = 1; j <= m; j++) {
bool ok = true; // 标记当前格子是否为山谷
// 检查8个邻居:行范围[i-1, i+1],列范围[j-1, j+1]
for(int i2 = i - 1; i2 <= i + 1; i2++) {
for(int j2 = j - 1; j2 <= j + 1; j2++) {
// 跳过自己(i2==i 且 j2==j 的情况)
// 注意:这里(i,j)本身也在循环中,但h[i][j]>h[i][j]为false,不影响结果
// 不过严格来说应该加 if(i2==i && j2==j) continue; 更规范
// 如果当前格 > 某个邻居,则不是山谷
if(h[i][j] > h[i2][j2]) {
ok = false;
break; // 提前退出内层循环
}
}
if(!ok) break; // 提前退出外层循环
}
ans += ok; // ok为true则+1,false则+0
}
}
cout << ans;
return 0;
}
3.2 编程题 2:礼盒排序
时间限制:1.0s 内存限制:512MB
题目描述:
商店推出了许多礼盒,每个礼盒中包含 k 件商品,每件商品都有一个价格。现在需要对这些礼盒进行排序,排序规则如下:
1. 先按礼盒总价格从小到大排序;
2. 如果总价格相同,按礼盒中最贵商品的价格从小到大排序;
3. 如果仍然相同,按礼盒中最便宜商品的价格从小到大排序;
4. 如果仍然相同,按礼盒编号从小到大排序。
请输出排序后的礼盒编号。
输入格式:
第一行包含两个整数 n 和 k,分别表示礼盒数量和每个礼盒中商品的数量。接下来 n 行,每行包含 k 个整数,第 i 行表示第 i 个礼盒中各商品的价格。
输出格式:
输出一行,包含排序后的礼盒编号(编号从1开始),用空格分隔。
样例:
输入样例:
4 3
3 5 2
4 1 5
2 2 4
3 4 3
输出样例:
3 4 2 1
样例解释:
4个礼盒总价分别为10,10,8,10,按总价排序后3号礼盒在最前;
其余总价为10的礼盒,挀大值分别为5,5,4,所以4号在前;
1号和2号最大值相同,最小值分别为2,1,所以2号在前。
最终顺序为:3 4 2 1
思路:
排序规则(优先级从高到低):
1. 礼盒总价格 sum 升序
2. 总价格相同 → 最贵商品 max 升序
3. 仍相同 → 最便宜商品 min 升序
4. 仍相同 → 礼盒编号 id 升序
参考程序:
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
// 结构体:存储每个礼盒的关键信息
struct Combo {
int sum; // 礼盒中所有商品的总价格
int mx; // 礼盒中最贵商品的价格
int mn; // 礼盒中最便宜商品的价格
int id; // 礼盒编号(从1开始)
};
// 自定义比较函数:实现多级排序规则
bool cmp(const Combo &a, const Combo &b) {
if (a.sum != b.sum) return a.sum < b.sum; // 规则1:总价格升序
if (a.mx != b.mx) return a.mx < b.mx; // 规则2:最贵商品升序
if (a.mn != b.mn) return a.mn < b.mn; // 规则3:最便宜商品升序
return a.id < b.id; // 规则4:编号升序
}
int main() {
int n, k;
cin >> n >> k; // n:礼盒数量, k:每个礼盒的商品数
vector<Combo> v(n); // 创建n个礼盒的数组
for (int i = 0; i < n; i++) {
// 初始化第i个礼盒的统计信息
v[i].sum = 0; // 总和初始化为0
v[i].mx = -1; // 最大值初始化为极小(商品价格≥0)
v[i].mn = 1e9; // 最小值初始化为极大
v[i].id = i + 1; // 编号从1开始
// 读入k个商品,同时计算sum、mx、mn
for (int j = 0; j < k; j++) {
int x;
cin >> x;
v[i].sum += x; // 累加求和
v[i].mx = max(v[i].mx, x); // 更新最大值
v[i].mn = min(v[i].mn, x); // 更新最小值
}
}
// 使用自定义比较函数进行排序
sort(v.begin(), v.end(), cmp);
// 输出排序后的礼盒编号
for (int i = 0; i < n; i++) {
cout << v[i].id;
if (i + 1 < n) cout << " "; // 编号之间用空格分隔,末尾不加
}
cout << endl;
return 0;
}
