GESP 2025年03月认证 C++ 4级真题

1 单选题(每题 2 分,共 30 分)

题号123456789101112131415
答案ABBDDCDDBBBBAAC

第 1 题 关于下述代码,说法错误的是( )。

int multiply(int x, int y);  

int main() {  
    int a = 4, b = 5;  
    int result = multiply(a, b);  
    std::cout << "The result is: " << result << std::endl;  
    return 0;  
}  

int multiply(int x, int y) {  
    return x * y;  
}  
  • A. 函数 multiply 的定义应该放到函数 main 之前。
  • B. 函数声明 int multiply(int x, int y); 中明确指定了函数 multiply() 的返回值为整数类型。
  • C. 在 main 函数中,函数 multiply 通过 multiply(a, b) 被调用,其中 ab 是定义在 main 函数中的变量,它们作为实参传递给了 multiply 函数的形参 xy
  • D. 运行上述代码,将输出 The result is: 20

知识点解析: C++ 允许函数声明后定义,因此选项 A 错误,函数定义无需放在 main 之前。


第 2 题 执行下述代码将输出( )。

int x = 10;  
void func() { int x = 20; std::cout << x; }  
int main() {  
    func();  
    std::cout << x;  
    return 0;  
}  
  • A. 2020
  • B. 2010
  • C. 1020
  • D. 编译错误

知识点解析func() 中的 x 是局部变量,输出 20;main() 中的 x 是全局变量,输出 10。


第 3 题 执行下述代码后,变量 a 的值为( )。

int a = 10;  
int* p = &a;  
*p = 20;  
  • A. 10
  • B. 20
  • C. 随机值
  • D. 编译错误

知识点解析: 通过指针 p 修改 a 的值为 20。


第 4 题 以下哪种参数传递方式可以避免拷贝大型对象?

  • A. 只能用值传递
  • B. 只能用引用传递
  • C. 只能用指针传递
  • D. 引用传递和指针传递均可

知识点解析: 引用和指针均通过地址操作,避免直接拷贝对象。


第 5 题 执行下述代码将输出( )。

void swap(int a, int &b) {  
    int temp = a;  
    a = b;  
    b = temp;  
}  
int main() {  
    int x = 1, y = 2;  
    swap(x, y);  
    std::cout << x << y;  
    return 0;  
}  
  • A. 12
  • B. 21
  • C. 22
  • D. 11

知识点解析a 是值传递,不影响原值;b 是引用传递,修改后 y 变为 1。


第 6 题 下面的描述中,( )正确定义一个名为 Person 的结构体并正确初始化了一个 Person 结构体的变量 p

  • A
struct Person {  
    string name;  
    int age;  
};  
Person p("Yang", 10);  
  • B
1 struct Person {  
2 string name,  
3 int age;  
4 };  
5 Person p;  
6 p.name = "Yang";  
7 p.age = 10;  
  • C
1 struct Person {  
2 string name;  
3 int age;  
4 };  
5 Person p = { "Yang", 10 };  
  • D
1 struct Person {  
2 string name;  
3 int age;  
4 };  
5 Person p = new Person("Yang", 10);  

第7题. 给定如下代码。

1 struct Person {  
2    std::string name;  
3    int age;  
4    struct Address {  
5        std::string street;  
6        std::string city;  
7    };  
8    Address address;  
9 };  

下面描述错误的是( )。

  • A. 结构 Person 内嵌套结构 Address

  • B. Person 有一个 Address 类型的 address 成员

  • C. 一个 Person 类型的变量 paddress 的初始化可以写成:

    p.address.street = "123 Main St";  
    p.address.city = "Anytown";  
  • D. 结构的嵌套可以减少命名冲突,因此可以不必控制嵌套层次

知识点解析: C++不能在struct里面再定义struct.


第 8 题int arr[2][3] = {{1, 2, 3}, {4, 5, 6}},则 arr[1][2] 的值是( )。

  • A. 2
  • B. 3
  • C. 5
  • D. 6

知识点解析: 数组索引从 0 开始,arr[1][2] 对应第二行第三列的元素 6。


第 9 题 正确定义二维数组的是( )。

  • A. int arr[3,4];
  • B. int arr[3][4];
  • C. int arr(3,4);
  • D. int a[3-4];

知识点解析: C++ 二维数组语法为 类型 数组名[行][列]


第10题

小杨正在爬楼梯,需要爬 n 阶才能到达楼顶。如果每次可以爬1个或2个台阶,下面代码采用递推算法来计算一共有多少种不同的方法可以爬到楼顶,则横线上应填写( )。

1 int f(int n) {  
2    if (n == 1 || n == 2)  
3        return n;  
4  
5    int f1 = 1;  
6    int f2 = 2;  
7    int res = 0;  
8    for (int i = 3; i <= n; i++) {  
9        // 在此处填入代码  
10    }  
11    return res;  
12 }  
  • A
1 res += f1 + f2;  
2 f1 = f2;  
3 f2 = res;  
  • B
1 res = f1 + f2;  
2 f1 = f2;  
3 f2 = res;  
  • C
1 res += f1 + f2;  
2 f2 = res;  
3 f1 = f2;  
  • D
1 res = f1 + f2;  
2 f2 = res;  
3 f1 = f2;  

知识点解析: 递推公式需更新 f1f2 的值,选项 B 正确。


第11题 给定如下算法,其时间复杂度为( )。

bool f(int arr[], int n, int target) {  
    for (int i = 0; i < (1 << 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(n2)
  • B. O(n×2n)
  • C. O(1)
  • D. O(n3)

知识点解析: 外层循环 ( 2^n ),内层循环 ( n ),总复杂度O(n×2n)。


第 12 题 关于排序稳定性的正确描述是( )。

  • A. 时间复杂度恒定
  • B. 相同元素的相对顺序不变
  • C. 选择排序是稳定排序
  • D. 插入排序不稳定

知识点解析: 稳定排序的定义是相同元素顺序不变。


第 13 题 对数组 arr[]={5, 3, 8, 1} 进行升序排序,执行第一轮冒泡排序后数组 arr 中的内容为( )。

  • A. 3, 5, 1, 8
  • B. 3, 1, 5, 8
  • C. 3, 5, 8, 1
  • D. 5, 3, 8, 1

知识点解析: 第一轮交换后,最大元素 8 移动至末尾,数组变为 3, 5, 1, 8


第 14 题 运行下面的代码,将出现( )。

double hmean(double a, double b) {  
    if (a == -b)  
        throw runtime_error("Runtime error occurred.");  
    return 2.0 * a * b / (a + b);  
}  

int main() {  
    double x = 10;  
    double y = -10;  
    try {  
        int result = hmean(x, y);  
        cout << "hmean: " << result << endl;  
    }  
    catch (const runtime_error& e) {  
        cout << "Caught: " << e.what() << endl;  
    } catch (...) {  
        cout << "Caught an unknown exception." << endl;  
    }  
    return 0;  
}  
  • A. 屏幕上输出 Caught: Runtime error occurred.
  • B. 屏幕上输出 Caught an unknown exception.
  • C. 程序调用 std::terminate()
  • D. 编译错误

知识点解析hmean 抛出 runtime_error,被正确捕获。


第 15 题 下⾯哪种⽅式不能实现将字符串 A. 1 2 3 “Happy Spring!” 输出重定向到⽂件 log.txt ( )。

  • A.

    freopen("log.txt", "w", stdout);
    cout << "Happy Spring!" << endl;
    fclose(stdout)
  • B.

    std::ofstream outFile("log.txt");
     outFile << "Happy Spring!" << endl;
     outFile.close()
  • C.

    std::ofstream outFile("log.txt");
     cout << "Happy Spring!" << endl;
     outFile.close();
  • D.

     ofstream log_file("log.txt");
     streambuf* org_cout = cout.rdbuf();
     cout.rdbuf(log_file.rdbuf());
     cout << "Happy Spring!" << endl;
     cout.rdbuf(org_cout);

知识点解析: 选项 C 中 cout 未重定向,仍输出到标准输出。


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

题号12345678910
答案×××××

第1题 函数是C++中的核心概念,用于封装可重用的代码块。

知识点解析:函数是代码封装的核心概念,正确。

第2题 在C++中,函数的返回类型可以省略,默认为 int

知识点解析:C++ 函数必须显式声明返回类型,错误。

第3题 结构体的成员默认是 public 访问权限。

知识点解析:结构体成员默认 public,正确。

第4题 假设整数数组 arr[4]={0, 1, 2, 3} 的第一个元素在内存中的地址为 0x7ffee4065820,经过 int* p = arr; p += 1; 后,指针 p 的值是 1

知识点解析:指针加法按类型大小计算地址,错误。

第5题 二维数组作为函数参数时,必须显式指定所有维度的大小。

知识点解析:二维函数参数需指定列数,错误。

第6题 递推是一种通过已知的初始值和递推公式,逐步求解目标值的算法。

知识点解析:递推算法定义正确。

第7题 考虑最坏情况下冒泡排序算法的时间复杂度,T(n)T(n) 为待排序数字的数目为 nn 的复杂度,则其递推关系式为

T(n)=T(n−1)+n,T(0)=1.T(n)=T(n−1)+n,T(0)=1.

知识点解析:冒泡排序递推式正确。

第8题 插入排序在最好情况(已有序)下的时间复杂度是 O(n2)。

知识点解析:插入排序最好情况复杂度 ( O(n) ),错误。

第9题 对数组 arr[]={4, 3, 1, 5, 2} 进行升序排序,执行第一轮选择排序后数组 arr 中的内容是 {1, 4, 3, 5, 2}

知识点解析:第一轮选择排序结果错误。

第10题 未捕获异常会调用 std::terminate 终止程序。

知识点解析:未捕获异常终止程序,正确。


3 编程题(每题 25 分,共 50 分)

3.1 编程题1

  • 试题名称: 荒地开垦
  • 时间限制: 1.0 s
  • 内存限制: 512.0 MB

3.1.1 题面描述

小杨有一大片荒地,可以表示为一个 nn 行 mm 列的网格图。小杨想要开垦这块荒地,但荒地中一些位置存在杂物。对于一块不存在杂物的荒地,该荒地可以开垦当且仅当其上、下、左、右四个方向相邻的格子均不存在杂物。小杨可以选择至多一个位置,清除该位置的杂物,移除杂物后该位置变为荒地。小杨想知道在清除至多一个位置的杂物的情况下,最多能够开垦多少块荒地。

3.1.2 输入格式

第一行包含两个正整数 n,mn,m,含义如题面所示。 之后 nn 行,每行包含一个长度为 mm 且仅包含字符 ·# 的字符串。如果为 ·,代表该位置为荒地;如果为 #,代表该位置为杂物。

3.1.3 输出格式

输出一个整数,代表在清除至多一个位置的杂物的情况下,最多能够开垦的荒地块数。

3.1.4 样例

输入样例1

3 5  
···##  
··###  
···##  

输出样例1

11  

3.1.5 参考程序

#include<bits/stdc++.h>  
using namespace std;  
const int N = 1005;  
char mat[N][N];  
int a[N][N];  
const int d[4][2] = {{-1, 0}, {1, 0}, {0, -1}, {0, 1}};  

int main() {  
    int n, m, ans = 0;  
    scanf("%d%d", &n, &m);  
    assert(1 <= n && n <= 1000);  
    assert(1 <= m && m <= 1000);  
    for (int i = 1; i <= n; i++)  
        scanf("%s", mat[i] + 1);  
    for (int i = 1; i <= n; i++)  
        for (int j = 1; j <= m; j++) {  
            int num = 0, p = -1;  
            for (int k = 0; k < 4; k++)  
                if (mat[i + d[k][0]][j + d[k][1]] == '#')  
                    num++, p = k;  
            if (mat[i][j] == '.' && num == 1)  
                a[i + d[p][0]][j + d[p][1]]++;  
            else if (mat[i][j] == '.' && num == 0)  
                ans++;  
            else if (mat[i][j] == '#' && num == 0)  
                a[i][j]++;  
        }  
    int mx = 0;  
    for (int i = 1; i <= n; i++)  
        for (int j = 1; j <= m; j++)  
            mx = max(mx, a[i][j]);  
    cout << ans + mx << endl;  
    return 0;  
}  

知识点解析: 遍历网格,统计每个杂物移除后可能新增的可开垦区域,选择最大值。

#include <bits/stdc++.h>  
using namespace std;  
const int N = 1005;  
char mat[N][N];  
int a[N][N];  
const int d[4][2] = {{-1,0}, {1,0}, {0,-1}, {0,1}};  

int main() {  
    int n, m, ans = 0;  
    scanf("%d%d", &n, &m);  
    for (int i = 1; i <= n; i++) scanf("%s", mat[i] + 1);  
    for (int i = 1; i <= n; i++) {  
        for (int j = 1; j <= m; j++) {  
            int num = 0, p = -1;  
            for (int k = 0; k < 4; k++) {  
                int x = i + d[k][0], y = j + d[k][1];  
                if (x < 1 || x > n || y < 1 || y > m) continue;  
                if (mat[x][y] == '#') num++, p = k;  
            }  
            if (mat[i][j] == '.' && num == 1) a[i][j]++;  
            else if (mat[i][j] == '.' && num == 0) ans++;  
            else if (mat[i][j] == '#' && num == 0) a[i][j]++;  
        }  
    }  
    int mx = 0;  
    for (int i = 1; i <= n; i++)  
        for (int j = 1; j <= m; j++) mx = max(mx, a[i][j]);  
    cout << ans + mx << endl;  
    return 0;  
}  

3.2 编程题2

  • 试题名称: 二阶矩阵
  • 时间限制: 1.0 s
  • 内存限制: 512.0 MB

3.2.1 题目描述

小A有一个 n行 m列的矩阵 A。小A认为一个 2×2 的矩阵 D是好的,当且仅当 D[1] [1] × D[2] [2] = D[1] [2] × D[2] [1]。其中 D[i] [j] 表示矩阵 D 的第 i 行第 j 列的元素。小A想知道 A 中有多少个好的子矩阵。

3.2.2 输入格式

第一行,两个正整数 n,m。 接下来 n 行,每行 m个整数 Ai,1,Ai,2,…,Ai。

3.2.3 输出格式

一行,一个整数,表示 A 中好的子矩阵的数量。

3.2.4 样例

输入样例1

3 4  
1 2 1 0  
2 4 2 1  
0 3 3 0  

输出样例1

2  

3.2.5 参考程序

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

const int N = 505;  
int n, m;  
int a[N][N];  
int ans;  

int main() {  
    scanf("%d%d", &n, &m);  
    assert(1 <= n && n <= 500 && 1 <= m && m <= 500);  
    for (int i = 1; i <= n; i++)  
        for (int j = 1; j <= m; j++) {  
            scanf("%d", &a[i][j]);  
            assert(-100 <= a[i][j] && a[i][j]

知识点解析: 遍历所有 2×2 子矩阵,检查是否满足 D1,1×D2,2=D1,2×D2,1D1,1​×D2,2​=D1,2​×D2,1​。

#include <bits/stdc++.h>  
using namespace std;  
const int N = 505;  
int a[N][N], n, m, ans;  

int main() {  
    scanf("%d%d", &n, &m);  
    for (int i = 1; i <= n; i++)  
        for (int j = 1; j <= m; j++) scanf("%d", &a[i][j]);  
    for (int i = 1; i < n; i++)  
        for (int j = 1; j < m; j++)  
            if (a[i][j] * a[i+1][j+1] == a[i+1][j] * a[i][j+1]) ans++;  
    printf("%d\n", ans);  
    return 0;  
}