跳到主要内容 CCF-GESP 2025 年 12 月 C++ 四级真题解析 | 极客日志
C++ 算法
CCF-GESP 2025 年 12 月 C++ 四级真题解析 CCF-GESP 2025 年 12 月 C++ 四级考试真题解析,包含单选、判断及编程题。内容覆盖指针、数组、结构体、排序算法、文件流及异常处理等核心考点。提供详细解题步骤与参考代码,旨在帮助考生巩固基础并应对考试。
蓝绿部署 发布于 2026/3/24 更新于 2026/4/18 3.7K 浏览1 单选题(每题 2 分,共 30 分)
第 1 题 小杨想让指针 p 指向整数变量 x,正确写法是( )。
A. int p = &x;
B. int *p = x;
C. int *p = &x;
D. p = *x;
解析: 答案 C。正确声明指针:int *p = &x; 将指针 p 指向变量 x 的地址;输出变量值通过解引用 *p 实现。故选 C。
第 2 题 小杨写了如下的指针接力程序,程序执行完后变量 a、p1 和 p2 的值分别是( )。
int a = 5 ; int * p1 = &a; int * p2 = p1; *p2 = 10 ;
A. 5 10 10
B. 5 10 15
C. 10 10 10
D. 5 5 10
解析: 答案 C。p1 为指向 a 的指针,p2 复制了 p1(指向同一地址),对*p2 赋值等于对 a 赋值,*p1 也同值。所以 a、p1 和 p2 的值分别是 10、10、10。故选 C。
第 3 题 小杨用一个二维数组表示棋盘,其中 1 表示有棋子,0 表示没有棋子。他想知道第 2 行第 3 列有没有棋子,可采用的代码是:( )。
int a[3 ][4 ] = {
{1 , 0 , 1 , 0 },
{0 , 1 , 0 , 1 },
{1 , 1 , 0 , 0 }
};
A. cout << a[1, 2] << endl;
B. cout << a[1][2] << endl;
C. cout << a(1, 2) << endl;
D. cout << a{1}{2} << endl;
解析: 答案 B。C++ 数组的下标是从 0 开始,第一个元素是 0 行 0 列,对第 2 行第 3 列表示为 a[1][2]。故选 B。
第 4 题 执行完下面的代码后,*(p + 5) 和 arr[1][1] 的值分别是( )。
int arr[3 ][4 ] = {{1 ,2 ,3 ,4 }, {5 , , , }, { , , , }}; * p = &arr[ ][ ];
微信扫一扫,关注极客日志 微信公众号「极客日志」,在微信中扫描左侧二维码关注。展示文案:极客日志 zeeklog
相关免费在线工具 加密/解密文本 使用加密算法(如AES、TripleDES、Rabbit或RC4)加密和解密文本明文。 在线工具,加密/解密文本在线工具,online
Base64 字符串编码/解码 将字符串编码和解码为其 Base64 格式表示形式即可。 在线工具,Base64 字符串编码/解码在线工具,online
Base64 文件转换器 将字符串、文件或图像转换为其 Base64 表示形式。 在线工具,Base64 文件转换器在线工具,online
Markdown转HTML 将 Markdown(GFM)转为 HTML 片段,浏览器内 marked 解析;与 HTML转Markdown 互为补充。 在线工具,Markdown转HTML在线工具,online
HTML转Markdown 将 HTML 片段转为 GitHub Flavored Markdown,支持标题、列表、链接、代码块与表格等;浏览器内处理,可链接预填。 在线工具,HTML转Markdown在线工具,online
JSON 压缩 通过删除不必要的空白来缩小和压缩JSON。 在线工具,JSON 压缩在线工具,online
6
7
8
9
10
11
12
int
0
0
A. 5 6
B. 6 5
C. 5 5
D. 6 6
解析: 答案 D。C++ 二维数组是按行连续排的,p 指向 arr 的首地址,指向第一个元素,p+5 指向第 6 个元素,即 a[1][1],*(p+5) 与 a[1][1] 同地址,输出 6 6。故选 D。
第 5 题 执行完下面的代码后,sum 的值是( )。
int arr[2 ][3 ][2 ] = {
{{1 ,2 }, {3 ,4 }, {5 ,6 }},
{{7 ,8 }, {9 ,10 }, {11 ,12 }}
}; int sum = 0 ; for (int i = 0 ; i < 2 ; i++)
for (int j = 0 ; j < 3 ; j++)
for (int k = 0 ; k < 2 ; k++)
if ((i+j+k) % 2 == 0 )
sum += arr[i][j][k];
解析: 答案 B。C++ 三维数组是按行连续排的,满足求和的条件是 i,j,k 分别为 0,0,0,0,1,1,0,2,0,1,0,1,1,1,0,1,2,1,1+4+5+8+9+12=39。故选 B。
int a = 1 ; void test () {
int a = 2 ;
{
int a = 3 ;
a++;
}
a++;
cout << a << " " ;
} int main () {
test ();
cout << a;
return 0 ;
}
A. 3 1
B. 4 1
C. 3 2
D. 4 2
解析: 答案 A。第 1 行的 a 是全局变量,第 14 行调用 test() 函数,函数中有多个局部变量 a,第 4 行定义的局部变量 a=2,第 5~8 行中一对"{}"中定义 a 是局部变量,离开"}"就消失,恢复第 4 定义的 a,第 9 行的 a++ 执行的是第 4 行定义的 a,所以输出 3 和空格,第 15 行输出的是全局变量 a,值为 1。故选 A。
第 7 题 执行完下面的代码后,a、b 和 c 的值分别是( )。
void byValue (int x) { x = 100 ; } void byRef (int & x) { x = 200 ; } void byPointer (int * x) { *x = 300 ; } int main () {
int a = 1 , b = 2 , c = 3 ;
byValue (a);
byRef (b);
byPointer (&c);
return 0 ;
}
A. 100 200 300
B. 1 2 3
C. 1 200 300
D. 1 2 300
解析: 答案 C。byValue(int x) 是值传递,所以修改 x 不影响 a,a 仍为 1;byRef(int& x) 为引用传递,传递是变量地址,修改 x 等于修改 b,所以 b 为 200;byPointer(int* x) 为指针传递,x 指向 c 的地址。修改*x 等于修改 c,所以 c 为 300。a、b 和 c 的值分别是 1、200、300。故选 C。
struct Point {
int x, y;
}; struct Rectangle {
Point topLeft;
Point bottomRight;
}; int main () {
Rectangle rect = {{10 , 10 }, {20 , 20 }};
rect.topLeft.x = 5 ;
Point* p = &rect.bottomRight;
p->y = 5 ;
cout << rect.topLeft.x + rect.bottomRight.y;
return 0 ;
}
解析: 答案 A。结构体定义:Point 包含 x,y;Rectangle 包含 topLeft,bottomRight。初始化:topLeft(10,10), bottomRight(20,20)。修改操作:topLeft.x=5, p->y=5。输出计算:5+5=10。故选 A。
第 9 题 给定函数 climbStairs(int n) 的定义如下,则 climbStairs(5) 的返回的值是( )。
int climbStairs (int n) {
if (n <= 2 ) return n;
int a = 1 , b = 2 ;
for (int i = 3 ; i <= n; i++) {
int temp = a + b;
a = b;
b = temp;
}
return b;
}
解析: 答案 B。当 n=5 时:i=3 时,a=2,b=3;i=4,a=3,b=5;i=5 时,a=5,b=8。故选 B。
struct Card {
int value;
char suit;
}; Card cards[4 ] = {{5 ,'A' }, {3 ,'B' }, {5 ,'C' }, {3 ,'D' }};
使用某排序算法按 value 排序后,结果为:{3,'D'}, {3,'B'}, {5,'A'}, {5,'C'},则这个排序算法是稳定的吗?
A. 稳定,因为相同 value 的元素相对顺序保持不变
B. 不稳定,因为 {3,'D'} 出现在 {3,'B'} 之前
C. 无法判断
D. 稳定,因为结果是有序的
解析: 答案 B。排序算法是否稳定,看同值排序时仍保持原次序的称稳定,否则称不稳定。由于按 value 排序,原{3,'B'}在{3,'D'}之前,{5,'A'}在{5,'C'}之前,稳定排序结果应该是{3,'B'},{3,'D'},{5,'A'},{5,'C'},但结果是{3,'D'}, {3,'B'}, {5,'A'}, {5,'C'},所以这个排序算法是不稳定的。故选 B。
第 11 题 下面的函数 selectTopK() 实现从 n 个学生中选出前 k 名成绩最好的学生颁发奖学金(不需要对所有学生完全排序,只需要找出前 k 名),则横线上应填写( )。
struct Student {
string name;
int score;
}; void selectTopK (Student students[], int n, int k) {
for (int i = 0 ; i < k; i++) {
int maxIdx = i;
for (____________________) {
if (students[j].score > students[maxIdx].score) {
maxIdx = j;
}
}
if (maxIdx != i) {
Student temp = students[i];
students[i] = students[maxIdx];
students[maxIdx] = temp;
}
}
}
A. int j = 0; j < n; j++
B. int j = i + 1; j < n; j++
C. int j = i; j < n; j++
D. int j = 1; j <= n; j++
解析: 答案 B。程序的算法与选择排序类似:先取未排序区域 n 个数中的第 1 个数与后面 n-1 个进行比较,找到最大值,如最大值不是第 1 个则最大值与第 1 个数进行交换,这样最大值到了区域的第 1 个,再取第 2 个开始的区域,同样找区域中的最大,交换到第 2 个位置,以此类推,直到找到前 k 个最大值。所以循环变量 j 从 i+1 开始到 n-1(下标从 0 开始),所以填 j=i+1; j<n; j++。故选 B。
第 12 题 某游戏的排行榜系统需要实时更新玩家分数。每次只有一个玩家的分数发生变化,排行榜已经是按分数降序排列的。现在需要将更新后的玩家调整到正确位置。下面的函数 updateRanking() 要实现上述功能,则两处横线上应分别填写( )。
struct Player {
string name;
int score;
};
Player updatedPlayer = players[playerIdx];
if (playerIdx > 0 && updatedPlayer.score > players[playerIdx - 1 ].score) {
int i = playerIdx;
while (____________________) {
players[i] = players[i - 1 ];
i--;
}
players[i] = updatedPlayer;
}
else if (playerIdx < size - 1 && updatedPlayer.score < players[playerIdx + 1 ].score) {
int i = playerIdx;
while (____________________) {
players[i] = players[i + 1 ];
i++;
}
players[i] = updatedPlayer;
}
}
A.
i > 0 && updatedPlayer.score > players[i - 1].score
i < size - 1 && updatedPlayer.score < players[i + 1].score
B.
i < size - 1 && updatedPlayer.score < players[i + 1].score
i > 0 && updatedPlayer.score > players[i - 1].score
C.
i > 0 && updatedPlayer.score < players[i - 1].score
i < size - 1 && updatedPlayer.score < players[i + 1].score
D.
i > 0 && updatedPlayer.score < players[i - 1].score
i < size - 1 && updatedPlayer.score > players[i + 1].score
解析: 答案 A。程序的第 10 行判指定位置 (playerIdx) 的分数比上一位 (playerIdx-1) 高,则从 i 从 playerIdx 开始向上找直到 0(逆序最大值位置),比较与上一位的分数,如仍大于则继续循环。所以 i>0(i-1>=0),和 updatedPlayer.score > players[i - 1].score 同时成立,否则向后比较,比较与下一位的分数,如仍小于则继续循环。i<size-1(i+1<= size-1),和 updatedPlayer.score < players[i + 1].score 同时成立。故选 A。
第 13 题 给定如下算法,其时间复杂度为( )。
bool f (int arr[], int n, int target) {
for (int i = 0 ; i < n; i++) {
int sum = 0 ;
for (int j = 0 ; j < n; j++) {
if (i & (1 << j)) {
sum += arr[j];
}
}
if (sum == target) return true ;
}
return false ;
}
A. O(n)
B. O(n²)
C. O(n³)
D. O(2ⁿ)
解析: 答案 B。双重循环,循环次数都是 n,所以时间复杂度为 O(n²)。故选 B。
第 14 题 执行下面 C++ 程序,会输出( )。
int main () {
ofstream fout ("test.txt" ) ;
fout << "Happy" << endl;
fout << "New Year" ;
fout.close ();
ifstream fin ("test.txt" ) ;
string s1, s2;
fin >> s1;
getline (fin, s2);
fin.close ();
cout << s1 << "|" << s2;
return 0 ;
}
A. Happy|New Year
B. Happy| New Year
C. HappyNew Year|
D. Happy|
解析: 答案 D。第 4 行写文件时加了换行 (endl),所以写到文件为两行,第一行 Happy,第二行 NewYear。第 10 行读取时,fin >> s1 使用流提取操作符,按空白字符分割输入,读取连续非空白字符并存储到 string 对象 s1 中,会残留第一行的换行符。getline(fin, s2) 读取整行输入,包括空格,直至遇到换行符 (\n),并将换行符从流中移除,结果存储到 s2。由于第 11 行读到的是换行 ('\n'),所以 s2 是空字符串。故选 D。
第 15 题 执行下面 C++ 代码,会输出 ( )。
int divide (int a, int b) {
if (b == 0 ) throw "Division by zero" ;
return a / b;
} int main () {
int result = 0 ;
try {
result = divide (10 , 0 );
cout << "A" ;
}
catch (const char * msg) {
cout << "B" ;
result = -1 ;
}
cout << result;
return 0 ;
}
A. A0
B. B-1
C. A10
D. 程序崩溃
解析: 答案 B。这是异常处理程序,调用 divide(int a, int b) 时,当 b=0 时抛出 "Division by zero" 异常。当主函数在 try 中运行 result = divide(10, 0); 时,因 b=0 会抛出异常,后面的 cout << "A" 不会被执行,抛出的异常要被 catch 子句接收处理,执行 cout << "B",并给 result 赋 -1,第 16 行输出 result,所以输出结果为 B-1。故选 B。
2 判断题(每题 2 分,共 20 分) 第 1 题 小杨正在调试他的温度传感器程序,其中变量 x 保存当前温度。下面这段代码运行后,变量 x 的值变成了 8。
int x = 5 ; int *p = &x; *p = *p + 3 ;
解析: 答案√(正确)。p 为指向 x 的指针,*p 引用即 x,p+3,即 x+3,所以执行 p = *p + 3; 后 x=5+3,x 变成 8。故正确。
解析: 答案╳(错误)。一个结构体可以包含另一个结构体。故错误。
第 3 题 在 C++ 中,定义如下二维数组:int a[3][4];,数组 a 在内存中是按行优先连续存放的,即 a[0][0]、a[0][1]、a[0][2]、a[0][3] 在内存中是连续的。
解析: 答案√(正确)。C++ 二维数组同行数据连续存放,行与行也是连续存放。故正确。
第 4 题 执行下面程序后,变量 a 的值会变成 15。
void add (int &x) {
x += 10 ;
} int a = 5 ; add (a);
解析: 答案√(正确)。函数 add(int &x) 为引用传递参数,实参 a 将地址传递形参 x,对 x 的修改就是对 a 的修改,因此执行 x += 10 之后,x 由 5 变为 15,并与 A 同地址,x 相当于是 a 的别名,a=15。故正确。
第 5 题 执行下面的 C++ 代码,会输出 8,因为两个指针地址相差 8 个字节(假设 int 占 4 字节)。
int arr[5 ] = {1 , 2 , 3 , 4 , 5 }; int * p1 = arr; int * p2 = arr + 2 ; cout << p2 - p1;
解析: 答案╳(错误)。C++ 一维数组,数组名即为数组的首地址,所以 p1 是指向 arr 的指针。arr+2 为地址加,p2 指向后 2 个下标,指针之差是同对象内的'距离',以'元素个数'为单位,而不是字节 p2-p1=2≠8,地址相差 2。故错误。
第 6 题 考虑用如下递推方式计算斐波那契数列,时间复杂度是 O(n)。
int n = 10 ; int f[20 ]; f[0 ] = 0 ; f[1 ] = 1 ; for (int i = 2 ; i <= n; i++)
f[i] = f[i - 1 ] + f[i - 2 ];
解析: 答案√(正确)。程序只是单循环,时间复杂度为 O(n)。故正确。
解析: 答案√(正确)。冒泡排序和插入排序都是稳定排序。故正确。
void sort (int a[], int n) {
for (int i = 1 ; i < n; i++) {
int x = a[i];
int j = i - 1 ;
while (j >= 0 && a[j] > x) {
a[j + 1 ] = a[j];
j--;
}
a[j + 1 ] = x;
}
}
解析: 答案╳(错误)。选择排序,涉及求最大值或最小值,程序中并没有。故错误。
#include <iostream> using namespace std; int calculate(int x, int y = 10); int main() {
cout << calculate (5 );
return 0 ;
} int calculate (int x, int y) {
return x * y;
} int calculate (int x) {
return x * 2 ;
}
解析: 答案╳(错误)。第 4 行函数声明中声明双参数,其中 y 默认为 10,calculate(5); 调用的并未调重载函数,而是按默认参数,双参数调用,x=5,y=10,返回 xy=5 10=50。故错误。
int main () {
ofstream fout ("data.txt" ) ;
fout << 10 << " " << 20 << endl;
fout << 30 << " " << 40 ;
fout.close ();
ifstream fin ("data.txt" ) ;
int a, b, c, d;
fin >> a >> b >> c >> d;
fin.close ();
cout << a + b + c + d;
return 0 ;
}
解析: 答案√(正确)。第 3~4 行向文件写了两行,第一行 10 20 换行,第二行 30 40。fin 会丢掉前缀空白字符,一直读到空白字符 (不含空白字符)。a 读到的是 10,b 读到的是 20,c 读到的是 30,d 读到的是 40,所以结果为 10+20+30+40=100。故正确。
3 编程题(每题 25 分,共 50 分)
3.1 编程题 1
试题名称: 建造
时间限制: 1.0 s
内存限制: 512.0 MB
小 A 有一张 M 行 N 列的地形图,其中第 i 行第 j 列的数字 aᵢⱼ代表坐标 (i, j) 的海拔高度。停机坪为一个 3×3 的区域且内部所有 9 个点的最大高度和最小高度之差不超过 H。
小 A 想请你计算出,在所有适合建造停机坪的区域中,区域内部 9 个点海拔之和最大是多少。
第一行三个正整数 M, N, H,含义如题面所示。
之后 M 行,第 i 行包含 N 个整数,代表坐标 (i, j) 的高度。
5 5 3 5 5 5 5 5 5 1 5 1 5 5 5 5 5 5 5 2 5 2 5 3 5 5 5 2
对于所有测试点,保证 1≤M, N≤10³, 1≤H, aᵢⱼ≤10⁵。
题目要求寻找一个 3×3 的区域,其中的最高海拔与最低海拔之差不超过 H,且 9 个点的海拔之和最大。如图 1 所示,以样例为例,M×N 的区域,选一 3×3 的区域,水平方向可移动 M-2 次,垂直方向可移动 N-2 次。只 3×3 的区域内的最高海拔与最低海拔之差不超过 H,就是一个有效区域,其海拔之和与当前最大海拔之和比较,两者大者作为当前最大海拔之和,最后输出即可。图 1 中黑色框中的 9 个海拔的最大海拔差为 4>H(=3),不合适;黄底紫色框中的 9 个海拔的最大海拔差也是 4>H,不合适;红色框中的 9 个海拔的最大海拔差也是 3=H,合适,但是否是最大海拔之和要验证。
枚举 3×3 的区域的左上角坐标,求以此点为左上角的 3×3 的区域中的各点海拔和、最高海拔、最低海拔。符合最高、最低海拔差有区域求最大海拔和。
#include <iostream>
using namespace std;
int a[1005 ][1005 ];
int main () {
int M, N, H;
long long maxs = 0 ;
cin >> M >> N >> H;
for (int i = 0 ; i < M; i++)
for (int j = 0 ; j < N; j++)
cin >> a[i][j];
for (int i = 0 ; i < M - 2 ; i++)
for (int j = 0 ; j < N - 2 ; j++) {
long long locs = 0 ;
int l_max = a[i][j], l_min = a[i][j];
for (int x = 0 ; x < 3 ; x++)
for (int y = 0 ; y < 3 ; y++) {
locs += a[i + x][j + y];
l_max = l_max > a[i + x][j + y] ? l_max : a[i + x][j + y];
l_min = l_min < a[i + x][j + y] ? l_min : a[i + x][j + y];
}
if (l_max - l_min <= H)
maxs = maxs > locs ? maxs : locs;
}
cout << maxs;
return 0 ;
}
算法相同,3×3 区域的另一种表示,求最大、最小的另一种写法,程序更简洁一些。程序代码如下:
#include <iostream>
using namespace std;
int a[1005 ][1005 ];
int main () {
int M, N, H;
long long maxs = 0 ;
cin >> M >> N >> H;
for (int i = 0 ; i < M; i++)
for (int j = 0 ; j < N; j++)
cin >> a[i][j];
for (int i = 0 ; i < M - 2 ; i++)
for (int j = 0 ; j < N - 2 ; j++) {
long long locs = 0 ;
int l_max = a[i][j], l_min = a[i][j];
for (int x = i; x < i + 3 ; x++)
for (int y = j; y < j + 3 ; y++) {
locs += a[x][y];
if (a[x][y] > l_max) l_max = a[x][y];
if (a[x][y] < l_min) l_min = a[x][y];
}
if (l_max - l_min <= H)
if (locs > maxs) maxs = locs;
}
cout << maxs;
return 0 ;
}
3.2 编程题 2
试题名称: 优先购买
时间限制: 1.0 s
内存限制: 512.0 MB
小 A 有 M 元预算。商店有 N 个商品,每个商品有商品名 S、价格 P 和优先级 V 三种属性,其中 V 为正整数,且越小代表商品的优先级越高。小 A 的购物策略为:
总是优先买优先级最高的东西;
如果有多个最高优先级商品,购买价格最低的;
如果有多个优先级最高且价格最低的商品,购买商品名字典序最小的。
之后 N 行,每行一个商品,依次为 SᵢPᵢVᵢ,代表第 i 个商品的商品名、价格、优先级。
按照字典序从小到大的顺序,输出所有购买商品的商品名。
20 4 apple 6 8 bus 15 1 cab 1 10 water 4 8
对于所有测试点,保证 1≤|Sᵢ|≤10, 1≤M, Pᵢ≤10⁵, 1≤N≤10³, 1≤Vᵢ≤10。商品名仅由小写字母组成且不存在两个相同的商品名。
排序确保了购物策略的正确性 (先按优先级排 (升序),同优先级按价格排 (升序),优先级、同价格按商品名排 (升序,即字典序)),贪心选择在预算允许下尽可能购买商品,最终输出按字典序排列输出。排序用 STL 中的 sort() 函数。
用结构体存储 M 个商品和购买商品的商品名称。参考程序代码如下:
#include <iostream>
#include <algorithm>
using namespace std;
const int N = 1005 ;
struct Node {
string s;
int p, v;
} a[N], b[N];
int m, n, cur;
bool cmp (Node x, Node y) {
if (x.v != y.v) return x.v < y.v;
if (x.p != y.p) return x.p < y.p;
return x.s < y.s;
}
int main () {
cin >> m >> n;
for (int i = 0 ; i < n; i++)
cin >> a[i].s >> a[i].p >> a[i].v;
sort (a, a + n, cmp);
for (int i = 0 ; i < n; i++) {
if (m >= a[i].p) {
m -= a[i].p;
b[cur++] = a[i];
}
}
sort (b, b + cur, [](const Node& a, const Node& b) {
return a.s < b.s;
});
for (int i = 0 ; i < cur; i++) {
cout << b[i].s << endl;
}
return 0 ;
}
由于输出只需输出购买商品的商品名称,为简化排序,购买商品的商品名称用字符串数组进行存储,M 个商品仍用结构体存储。
#include <iostream>
#include <string>
#include <algorithm>
using namespace std;
const int N = 1005 ;
struct Node {
string s;
int p, v;
} a[N];
string b[N];
int m, n, cur;
bool cmp (Node x, Node y) {
if (x.v != y.v) return x.v < y.v;
if (x.p != y.p) return x.p < y.p;
return x.s < y.s;
}
int main () {
cin >> m >> n;
for (int i = 0 ; i < n; i++)
cin >> a[i].s >> a[i].p >> a[i].v;
sort (a, a + n, cmp);
for (int i = 0 ; i < n; i++) {
if (m >= a[i].p) {
m -= a[i].p;
b[cur++] = a[i].s;
}
}
sort (b, b + cur);
for (int i = 0 ; i < cur; i++) {
cout << b[i] << endl;
}
return 0 ;
}