GESP 客观题评测系统
2024-12-Level-4
2024-12-Level-4
试卷解析总览,可直接查看每题答案与解析。
第 1 题(单选题)
下面的语句中,()正确定义了一个计算浮点数的平方的函数,并成功调用该函数。
float square(float x) {
return x * x;
}
float area = square(2);square(float x) {
return x * x;
}
float area = square(2);void square(float x) {
return x * x;
}
area = square(2.0);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);正确答案B
解析详情
【答案】B
【考点】函数参数(形参与实参)
【解析】 函数定义中的参数 n 为形参,函数调用时传入的变量 times 为实参。由于是值传递,函数内部对 n 的修改不会影响实参 times,执行结束后 times 仍为 5。C++ 参数传递需匹配类型和顺序,不能随意更换位置。
【易错点】 混淆形参与实参的概念,或者误认为值传递会影响原始变量。
第 3 题(单选题)
给定以下代码,
void func(int& x) {
x = x * 2;
}
int a = 5;
func(a);执行上述代码后,变量 a 的值为()。
正确答案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;正确答案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;正确答案D
解析详情
【答案】D
【考点】指针的基本操作
【解析】 指针 p 指向变量 x。执行 *p = *p + 2 时,实际上是通过指针对 x 的值进行修改。x 的值由 20 变为 22。由于 p 仍指向 x,*p 的值自然也是 22。
【易错点】 误以为通过指针对变量进行修改后,原变量的值不会改变,或者混淆了指针本身的值和指针所指向内容的值。
第 6 题(单选题)
下面的描述中,()不能正确 definition 一个名为 Student 的结构体以及一个包含20个元素的结构数组。
struct Student {
string name;
int age;
float score;
};
struct Student students[20];struct Student {
string name;
int age;
float score;
};
Student students[20];struct Student {
string name;
int age;
float score;
};
Student* students = new Student[20];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}
};正确答案D
解析详情
【答案】D
【考点】二维数组地址计算
&array[1][1] 的位置相对于 array[0][0] 偏移了 1*3 + 1 = 4 个元素。每个整型占 32 位(4 字节),总偏移量为 4 * 4 = 16 字节(十六进制 0x10)。0x7ffee4065820 + 0x10 = 0x7ffee4065830。
【易错点】 偏移量计算公式:(行索引 * 列数 + 列索引) * 类型大小;十六进制加法计算错误。
第 8 题(单选题)
下面( )正确定义二维数组。
正确答案D
解析详情
【答案】D
【考点】二维数组声明规则
【解析】 定义二维数组时,必须指定除了第一维以外的所有维度的大小。如果提供了初始化列表,第一维可以省略。选项 A、B、C 均违反了必须指定列数的规则,只有 D 在有初始化的前提下省略了行数,语法正确。
【易错点】 误以为第一维是必须指定的,或者不知道列数(最高维之后的所有维)在任何时候都不能省略。
第 9 题(单选题)
下面代码采用递推算法来计算斐波那契数列,则横线上应填写()。
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;
}result = f1 + f2;
f1 = f2;
f2 = result;result += f1 + f2;
f1 = f2;
f2 = result;result += f1 + f2;
f2 = result;
f1 = f2;result = f1 + f2;
f2 = result;
f1 = f2;正确答案A
解析详情
【答案】A
【考点】递推算法(斐波那契数列)
【解析】 斐波那契递推逻辑是当前项等于前两项之和。代码中先算和(result = f1 + f2),然后更新前两项的值:原来的第二项变成新序列的第一项(f1 = f2),当前算的 result 变成新序列的第二项(f2 = result)。选项 B、C 中的 += 是错误的累加操作。
【易错点】 更新变量的顺序错误,或者将赋值误写成累加。
第 10 题(单选题)
下面关于排序算法(冒泡排序、插入排序和选择排序)的描述中,不正确的是()。
正确答案C
解析详情
【答案】C
【考点】排序算法的时间复杂度
【解析】 冒泡排序可以通过设置标志位(flag)来检测是否发生过交换,如果某轮遍历未发生交换则提前结束。在数组已经有序的最优情况下,冒泡排序的时间复杂度为 O(n)。因此,“任何情况下都为 O(n²)”的描述是错误的。
【易错点】 忽略了冒泡排序的优化机制,认为其复杂度始终固定。
第 11 题(单选题)
冒泡排序的第一轮操作是从左到右遍历数组,通过两两比较相邻元素,将当前最大的元素移动到末尾。给定数组 arr[]={4, 1, 3, 1, 5, 2},执行第一轮冒泡排序后数组 arr 中的内容为()。
正确答案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;
}正确答案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
解析详情
【答案】A
【考点】插入排序算法逻辑
【解析】 插入排序的核心是将当前元素(base = nums[i])插入到前面已排序序列中。比较和移动应从当前元素的前一个位置(j = i - 1)开始向左扫描。选项 A 正确定义了基准值和起始搜索索引。
【易错点】 基准值取错位置,或者 j 的起始位置设定错误导致死循环或越界。
第 14 题(单选题)
下面哪种方式不能实现将字符串"Welcome to GESP!"输出重定向到文件 log.txt()。
freopen("log.txt", "w", stdout);
cout << "Welcome to GESP!" << endl;
fclose(stdout);std::ofstream outFile("log.txt");
outFile << "Welcome to GESP!" << endl;
outFile.close();std::ofstream outFile("log.txt");
cout << "Welcome to GESP!" << endl;
outFile.close();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
解析详情
【答案】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(0) + 1 + 2 + ... + n = 1 + n(n+1)/2。多项式的最高项为 n²,因此复杂度为 O(n²)。
【易错点】 误以为线性递推一定是 O(n),忽略了每层增加的开销是变量 n 而非常数。
第 7 题(判断题)
冒泡排序的平均时间复杂度为,但最优情况下为。
正确答案正确
解析详情
【答案】正确
【解析】 对于带有“交换标志位”优化的冒泡排序,如果在第一轮遍历中没有发生任何交换,则说明数组已有序,直接结束,此时复杂度为 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(对受检异常有强制要求)的规则。