GESP 客观题评测系统

2024-12-Level-4

2024-12-Level-4

试卷解析总览,可直接查看每题答案与解析。

单选题(每题 2 分)

1 题(单选题

下面的语句中,()正确定义了一个计算浮点数xx的平方(x2=x×x)(x^2 = x \times x)的函数,并成功调用该函数。

A.
float square(float x) {
return x * x;
}
float area = square(2);
B.
square(float x) {
    return x * x;
}
    float area = square(2);
C.
void square(float x) {
return x * x;
}
area = square(2.0);
D.
void square(float x) {
    x * x;
    return;
}
    area = square(2);

正确答案A

解析详情

【答案】A

【考点】函数的定义与调用

【解析】 选项 A 完整定义了返回类型为 float 的函数,并在调用时将 int 类型参数 2 隐式转换为 float,语法正确。选项 B 缺少返回类型;选项 C 中 void 类型函数不能 return 一个值;选项 D 中 void 函数不返回值,不能赋值给变量。

【易错点】 定义函数时必须明确返回类型,且函数体的返回操作必须与返回类型匹配。

2 题(单选题

下面代码的描述中,正确的是()。

void n_chars(char c, int n) {
    while (n-- > 0)
        cout << c;
}
char my_char = 'w';
int times = 5;
n_chars(my_char, times);
A.
代码执行结束后,times 的值为0
B.
n 是形参,times 是实参
C.
n 是实参,times 是形参
D.
代码最后一行换成 n_chars(times, my_char); 也可以

正确答案B

解析详情

【答案】B

【考点】函数参数(形参与实参)

【解析】 函数定义中的参数 n 为形参,函数调用时传入的变量 times 为实参。由于是值传递,函数内部对 n 的修改不会影响实参 times,执行结束后 times 仍为 5。C++ 参数传递需匹配类型和顺序,不能随意更换位置。

【易错点】 混淆形参与实参的概念,或者误认为值传递会影响原始变量。

3 题(单选题

给定以下代码,

void func(int& x) {
    x = x * 2;
}

int a = 5;
func(a);

执行上述代码后,变量 a 的值为()。

A.
5
B.
10
C.
15
D.
20

正确答案B

解析详情

【答案】B

【考点】引用传递

【解析】 函数 func 的参数 x 是一个引用(int&),意味着它直接引用了传入的实参 a。在函数内部执行 x = x * 2 后,a 的值也随之加倍。初始 a=5,执行后 a 为 10。

【易错点】 未识别出参数类型中的 & 符号,误按值传递处理导致认为 a 的值不变。

4 题(单选题

运行下面代码,屏幕上输出是()。

double* p_arr = new double[3];
p_arr[0] = 0.2;
p_arr[1] = 0.5;
p_arr[2] = 0.8;
p_arr += 1;
cout << p_arr[0] << endl;
p_arr -= 1;
delete p_arr;
A.
0.2
B.
0.5
C.
1.2
D.
1.5

正确答案B

解析详情

【答案】B

【考点】指针运算与数组访问

【解析】 指针 p_arr 初始指向数组首元素。执行 p_arr += 1 后,指针后移一位,指向原来的 p_arr[1]。此时访问 p_arr[0] 实际上访问的是数组的第二个元素 0.5。随后指针复位并释放内存,逻辑正确。

【易错点】 指针移动后,索引 0 指向的是当前指针位置的元素,而不是原始数组的首元素。

5 题(单选题

运行下面代码片段后,x 和 *p 的结果分别是()。

int x = 20;
int* p = &x;
*p = *p + 2;
A.
20 20
B.
20 22
C.
22 20
D.
22 22

正确答案D

解析详情

【答案】D

【考点】指针的基本操作

【解析】 指针 p 指向变量 x。执行 *p = *p + 2 时,实际上是通过指针对 x 的值进行修改。x 的值由 20 变为 22。由于 p 仍指向 x,*p 的值自然也是 22。

【易错点】 误以为通过指针对变量进行修改后,原变量的值不会改变,或者混淆了指针本身的值和指针所指向内容的值。

6 题(单选题

下面的描述中,()不能正确 definition 一个名为 Student 的结构体以及一个包含20个元素的结构数组。

A.
struct Student {
    string name;
    int age;
    float score;
};
struct Student students[20];
B.
struct Student {
    string name;
    int age;
    float score;
};
Student students[20];
C.
struct Student {
    string name;
    int age;
    float score;
};
Student* students = new Student[20];
D.
struct Student {
    string name;
    int age;
    float score;
};
Student students = new Student[20];

正确答案D

解析详情

【答案】D

【考点】结构体与动态数组分配

【解析】 使用 new Student[20] 分配动态数组时,返回的是首元素的指针类型 Student*。选项 D 中将指针赋值给了一个 Student 类型的普通变量,类型不匹配,会导致编译错误。

【易错点】 动态内存分配返回的是指针,接收变量必须是指针类型。

7 题(单选题

假定整型是32位,对一个2行3列的二维整数数组 array,假设数组第一个元素在内存中的地址为 0x7ffee4065820,则第2行第2个元素的地址 &array[1][1] 为()。

int array[2][3] = {
    {0, 1, 2},
    {3, 4, 5}
};
A.
0x7ffee4065824
B.
0x7ffee4065828
C.
0x7ffee406582c
D.
0x7ffee4065830

正确答案D

解析详情

【答案】D

【考点】二维数组地址计算

&array[1][1] 的位置相对于 array[0][0] 偏移了 1*3 + 1 = 4 个元素。每个整型占 32 位(4 字节),总偏移量为 4 * 4 = 16 字节(十六进制 0x10)。0x7ffee4065820 + 0x10 = 0x7ffee4065830。

【易错点】 偏移量计算公式:(行索引 * 列数 + 列索引) * 类型大小;十六进制加法计算错误。

8 题(单选题

下面( )正确定义二维数组。

A.
int a[3][];
B.
int a[][];
C.
int a[][4];
D.
int a[][2] = {{1,2},{1,2},{3,4}};

正确答案D

解析详情

【答案】D

【考点】二维数组声明规则

【解析】 定义二维数组时,必须指定除了第一维以外的所有维度的大小。如果提供了初始化列表,第一维可以省略。选项 A、B、C 均违反了必须指定列数的规则,只有 D 在有初始化的前提下省略了行数,语法正确。

【易错点】 误以为第一维是必须指定的,或者不知道列数(最高维之后的所有维)在任何时候都不能省略。

9 题(单选题

下面代码采用递推算法来计算斐波那契数列f(n)=f(n1)+f(n2)f(n)=f(n-1)+f(n-2),则横线上应填写()。

int fib(int n) {
    if (n == 0 || n == 1)
        return n;
    
    int f1 = 0;
    int f2 = 1;
    int result = 0;
    for (int i = 2; i <= n; i++) {
        // 在此处填入代码
    }
    return result;
}
A.
result = f1 + f2;
f1 = f2;
f2 = result;
B.
result += f1 + f2;
f1 = f2;
f2 = result;
C.
result += f1 + f2;
f2 = result;
f1 = f2;
D.
result = f1 + f2;
f2 = result;
f1 = f2;

正确答案A

解析详情

【答案】A

【考点】递推算法(斐波那契数列)

【解析】 斐波那契递推逻辑是当前项等于前两项之和。代码中先算和(result = f1 + f2),然后更新前两项的值:原来的第二项变成新序列的第一项(f1 = f2),当前算的 result 变成新序列的第二项(f2 = result)。选项 B、C 中的 += 是错误的累加操作。

【易错点】 更新变量的顺序错误,或者将赋值误写成累加。

10 题(单选题

下面关于排序算法(冒泡排序、插入排序和选择排序)的描述中,不正确的是()。

A.
冒泡排序基于元素交换实现,需借助临时变量,共涉及3个单元操作;而插入排序基于元素赋值实现,仅需1个单元操作。因此冒泡排序的计算开销通常比插入排序更高。
B.
选择排序在任何情况下的时间复杂度都为O(n²)。
C.
冒泡排序在任何情况下的时间复杂度都为O(n²)。
D.
如果给定数据部分有序,插入排序通常比选择排序效率更高。

正确答案C

解析详情

【答案】C

【考点】排序算法的时间复杂度

【解析】 冒泡排序可以通过设置标志位(flag)来检测是否发生过交换,如果某轮遍历未发生交换则提前结束。在数组已经有序的最优情况下,冒泡排序的时间复杂度为 O(n)。因此,“任何情况下都为 O(n²)”的描述是错误的。

【易错点】 忽略了冒泡排序的优化机制,认为其复杂度始终固定。

11 题(单选题

冒泡排序的第一轮操作是从左到右遍历数组,通过两两比较相邻元素,将当前最大的元素移动到末尾。给定数组 arr[]={4, 1, 3, 1, 5, 2},执行第一轮冒泡排序后数组 arr 中的内容为()。

A.
1, 4, 3, 1, 5, 2
B.
1, 3, 1, 4, 2, 5
C.
1, 4, 3, 1, 2, 5
D.
4, 1, 3, 1, 5, 2

正确答案B

解析详情

【答案】B

【考点】冒泡排序过程分析

【解析】 第一轮过程:(4,1)交换→{1,4,3,1,5,2};(4,3)交换→{1,3,4,1,5,2};(4,1)交换→{1,3,1,4,5,2};(4,5)不换;(5,2)交换→{1,3,1,4,2,5}。最终 5 移动到末尾,序列为 {1, 3, 1, 4, 2, 5}。

【易错点】 模拟交换过程时漏掉某一步,或者错误地将所有轮次的结果算了出来。

12 题(单选题

给定如下代码,其时间复杂度为()。

int cellRecur(int n) {
    if (n == 1)
        return 1;
    return cellRecur(n - 1) + cellRecur(n - 1) + 1;
}
A.
O(n2)O(n^{2})
B.
O(2n)O(2^{n})
C.
O(1)O(1)
D.
O(n)O(n)

正确答案B

解析详情

【答案】B

【考点】递归算法的时间复杂度分析

【解析】 该递归函数的递推式为 T(n) = 2T(n-1) + O(1)。这是一个典型的指数级增长模型,每增加一层,调用次数翻倍。最终复杂度为 O(2ⁿ)。

【易错点】 误以为是线性增长,或者将递归树的深度当成了总复杂度。

13 题(单选题

下面代码实现了插入排序函数,则横线上应填写()。

void insertion_sort(vector<int> &nums) {
    for (int i = 1; i < nums.size(); i++) {
        // 在此处填入代码
    }
    while (j >= 0 && nums[j] > base)
    {
        nums[j + 1] = nums[j];
        j--;
    }
    nums[j + 1] = base;
}
A.
int base = nums[i], j = i - 1;
B.
int base = nums[i], j = i;
C.
int base = nums[0], j = i - 1;
D.
int base = nums[0], j = i;

正确答案A

解析详情

【答案】A

【考点】插入排序算法逻辑

【解析】 插入排序的核心是将当前元素(base = nums[i])插入到前面已排序序列中。比较和移动应从当前元素的前一个位置(j = i - 1)开始向左扫描。选项 A 正确定义了基准值和起始搜索索引。

【易错点】 基准值取错位置,或者 j 的起始位置设定错误导致死循环或越界。

14 题(单选题

下面哪种方式不能实现将字符串"Welcome to GESP!"输出重定向到文件 log.txt()。

A.
freopen("log.txt", "w", stdout);
cout << "Welcome to GESP!" << endl;
fclose(stdout);
B.
std::ofstream outFile("log.txt");
outFile << "Welcome to GESP!" << endl;
outFile.close();
C.
std::ofstream outFile("log.txt");
cout << "Welcome to GESP!" << endl;
outFile.close();
D.
ofstream log_file("log.txt");
streambuf* org_cout = cout.rdbuf();
cout.rdbuf(log_file.rdbuf());
cout << "This output will go to the log file." << endl;
cout.rdbuf(oorg_cout);

正确答案C

解析详情

【答案】C

【考点】文件操作与输出重定向

【解析】 选项 C 虽然打开了文件流 outFile,但随后的输出语句使用了 cout,它默认仍指向标准输出(控制台),并未与 outFile 产生关联。选项 A、D 分别通过 freopen 和重定向流缓冲区实现了 cout 的重定向,B 则是直接向文件流输出。

【易错点】 混淆了“打开文件”和“重定向标准输出”这两个不同的概念。

15 题(单选题

运行下面的代码,将出现什么情况?()

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.
编译错误

正确答案A

解析详情

【答案】A

【考点】异常处理机制 (try-catch)

【解析】 当 x=10, y=-10 时,函数内部 a == -b 为真,执行 throw 抛出 runtime_error。main 函数中的 try 块捕获到该异常,执行对应的第一个 catch 分支,输出异常描述信息。

【易错点】 认为 a == -b 时会发生除零错误,而忽略了代码显式抛出的异常处理流程。

判断题(每题 2 分)

1 题(判断题

在 C++ 中,下面代码可以正确定义指针和初始化指针。

int* ptr;
*ptr = 10;

正确答案错误

解析详情

【答案】错误

【解析】 代码只声明了指针 ptr,但没有将其初始化为指向一个有效的内存地址(如 &x 或 new 分配的地址)。此时 ptr 是野指针,对其进行解引用并赋值会导致程序崩溃。

【易错点】 混淆“声明指针”与“初始化指针所指向的空间”,未意识到解引用前必须保证指针已指向有效地址。

2 题(判断题

一个函数必须在调用之前既声明又定义。

正确答案错误

解析详情

【答案】错误

【解析】 在 C++ 中,只要在调用之前有函数的声明(原型)即可编译通过,具体的定义可以放在调用之后或另一个源文件中。

【易错点】 分不清“声明”与“定义”的区别,误以为函数体的完整实现必须排在调用点之前。

3 题(判断题

函数参数可以通过值传递、引用传递和指针传递,这样函数内对参数的修改可以直接修改传入变量的值。

正确答案错误

解析详情

【答案】错误

【解析】 “值传递”会将实参的副本传给函数,函数内对形参的修改不会影响原变量。只有引用传递和指针传递能直接修改原变量。

【易错点】 将三种传递方式混为一谈,忽略了值传递的副本机制。

4 题(判断题

int arr[3][] 是一个正确的二维数组的声明。

正确答案错误

解析详情

【答案】错误

【解析】 在二维数组声明中,必须指定列数(第二维的大小),行数(第一维)可以根据初始化列表推导,但列数不能省略。

【易错点】 记反了维度的省略规则,或者误以为所有维度都可以留空。

5 题(判断题

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

正确答案正确

解析详情

【答案】正确

【解析】 递推算法通过确定的边界条件和推导公式(如 f(n)=f(n-1)+f(n-2)),由已知项顺序计算出目标项,符合题意。

【易错点】 将递推与递归混淆,实际上递推侧重于由小到大的迭代计算。

6 题(判断题

某算法的递推关系式为T(n)=T(n1)+nT(n)=T(n-1)+nnn为正整数)及T(0)=1T(0)=1,则该算法的时间复杂度为O(n2)O(n^{2})

正确答案正确

解析详情

【答案】正确

【解析】 根据递推式可得出 T(n) = T(0) + 1 + 2 + ... + n = 1 + n(n+1)/2。多项式的最高项为 n²,因此复杂度为 O(n²)。

【易错点】 误以为线性递推一定是 O(n),忽略了每层增加的开销是变量 n 而非常数。

7 题(判断题

冒泡排序的平均时间复杂度为O(n2)O(n^{2}),但最优情况下为O(n)O(n)

正确答案正确

解析详情

【答案】正确

【解析】 对于带有“交换标志位”优化的冒泡排序,如果在第一轮遍历中没有发生任何交换,则说明数组已有序,直接结束,此时复杂度为 O(n)。

【易错点】 死记硬背 O(n²),不知道在特定优化和特定输入下的性能差异。

8 题(判断题

冒泡排序和插入排序都是稳定的排序算法。

正确答案正确

解析详情

【答案】正确

【解析】 稳定性是指相等元素的相对位置在排序后保持不变。冒泡和插入排序在比较时如果不包含等于情况(如只有 a[i] < a[j] 才动),则不会跨越相等元素,是稳定的。

【易错点】 记不住各种排序的稳定性特点,或者不理解稳定性的定义。

9 题(判断题

选择排序是稳定的排序算法。

正确答案错误

解析详情

【答案】错误

【解析】 选择排序在寻找最小元素并与当前位置交换时,可能会将一个元素交换到与其相等的另一个元素的后面。例如 [5, 5, 2] 第一步后变为 [2, 5, 5],原本前面的 5 跑到了后面,因此是不稳定的。

【易错点】 误以为只要是简单排序就是稳定的,忽略了选择排序跨距离交换带来的副作用。

10 题(判断题

在 C++ 语言中,如果一个函数可能抛出异常,那么一定要在 try 子句里调用这个函数。

正确答案错误

解析详情

【答案】错误

【解析】 C++ 并不强制要求处理异常。如果不使用 try-catch,程序在异常抛出时会向上层传递,若最终无人捕获则调用 terminate 终止程序。语法上并不强制要求 try 子句。

【易错点】 将“推荐做法”误认为“语法强制要求”,或者混淆了 C++ 与 Java(对受检异常有强制要求)的规则。