GESP 客观题评测系统
2025-09-Level-4
2025-09-Level-4
试卷解析总览,可直接查看每题答案与解析。
第 1 题(单选题)
运行下面程序后变量 a 的值是()。
int a = 42;
int* p = &a;
*p = *p + 1;正确答案B
解析详情
【答案】B 【考点】指针解引用与变量修改 【解析】 1. 指针 p 存储了变量 a 的地址(&a)。 2. *p = *p + 1 通过解引用访问 a 的值(42),加 1 后赋值回 a。 3. 最终 a 的值更新为 43。 【易错点】未理解解引用操作 *p 对原变量 a 的直接修改作用。
第 2 题(单选题)
以下关于数组的描述中,()是错误的。
正确答案C
解析详情
【答案】C 【考点】数组与指针的区别 【解析】 在 C++ 中,数组名被视为常量指针,其指向的内存地址在定义后不可更改。 因此,不能对数组名执行自增(arr++)或自减(arr--)等修改指针指向的操作。 其他选项如随机访问和 sizeof 运算均符合数组的基本特性。 【易错点】混淆数组名(常量指针)与普通指针变量的区别。
第 3 题(单选题)
给定如下定义的数组 arr,则的值是()。
int arr[2][3] = {{1, 2, 3}, {4, 5, 6}};正确答案D
解析详情
【答案】D 【考点】二维数组的指针表示法 【解析】 1. arr + 1 定位到二维数组的第二行(下标为 1 的行)。 2. *(arr + 1) 获取该行的首地址,+(2) 偏移到该行的第三个元素。 3. 最外层的 * 获取该位置的值,即 arr[1][2] 的值 6。 【易错点】混淆行指针与列指针的转换及偏移逻辑。
第 4 题(单选题)
下面这段代码会输出()。
int add(int a, int b = 1); // 函数声明
int main() {
cout << add(2) << " " << add(2, 3);
return 0;
}
int add(int a, int b) { // 函数定义
return a + b;
}正确答案A
解析详情
【答案】A 【考点】默认参数及其应用 【解析】 1. add(2) 调用时使用默认参数 b=1,返回 2+1=3。 2. add(2, 3) 调用时显式提供参数 b=3,覆盖默认值,返回 2+3=5。 3. C++ 允许在声明中指定默认值,定义时无需重复。 【易错点】误以为默认参数必须在定义处重复声明。
第 5 题(单选题)
下面这段代码会输出()。
int x = 5;
void foo() {
int x = 10;
cout << x << " ";
}
void bar() {
cout << x << " ";
}
int main() {
foo();
bar();
}正确答案D
解析详情
【答案】D 【考点】局部变量作用域屏蔽 【解析】 1. foo() 内部定义了局部变量 x=10,它屏蔽了全局变量 x,故输出 10。 2. bar() 内部没有局部变量 x,直接访问全局变量 x=5,故输出 5。 3. 局部变量的声明仅在所属函数作用域内有效,不改变全局变量。 【易错点】错误认为局部变量的赋值会持久修改同名全局变量的值。
第 6 题(单选题)
下面程序运行的结果是()。
void increaseA(int x) {
x++;
}
void increaseB(int* p) {
(*p)++;
}
int main() {
int a = 5;
increaseA(a);
cout << a << " ";
increaseB(&a);
cout << a;
}正确答案C
解析详情
【答案】C 【考点】值传递与指针传递 【解析】 1. increaseA(a) 是值传递,操作的是副本,a 的值保持 5。 2. increaseB(&a) 是指针传递,通过解引用直接修改了 main 中的 a。 3. 因此 a 的值自增为 6,两次输出分别为 5 和 6。 【易错点】混淆值传递与地址传递对实参的影响。
第 7 题(单选题)
关于结构体初始化,以下哪个选项中正确的是()。
struct Point { int x, y; };正确答案B
解析详情
【答案】B 【考点】结构体初始化语法 【解析】 C++ 中结构体是聚合类型,标准初始化方式是使用大括号 {} 列表。 Point p = {1, 2}; 按顺序为结构体成员 x 和 y 赋初值。 其他符号如 ()、new {}、<> 均不符合 C++ 结构体栈上初始化的语法。 【易错点】受其他编程语言语法干扰,选错初始化符号。
第 8 题(单选题)
运行如下代码会输出()。
struct Cat {
string name;
int age;
};
void birthday(Cat& c) {
c.age++;
}
int main() {
Cat kitty{"Mimi", 2};
birthday(kitty);
cout << kitty.name << " " << kitty.age;
}正确答案B
解析详情
【答案】B 【考点】结构体引用传递 【解析】 1. birthday 函数接收 Cat 对象的引用,c.age++ 直接修改实参。 2. kitty 被初始化为 {"Mimi", 2},调用函数后其 age 变为 3。 3. 输出 kitty.name ("Mimi") 和更新后的 age (3)。 【易错点】误以为函数内修改的是副本或混淆变量名与成员值。
第 9 题(单选题)
关于排序算法的稳定性,以下说法错误的是()。
正确答案C
解析详情
【答案】C 【考点】排序算法稳定性 【解析】 稳定性指相等元素排序前后的相对位置是否保持不变。 选择排序在每轮寻找最小值并交换到首位时,可能发生跨越式交换。 这种交换极易破坏相等元素的原始顺序,因此是不稳定的排序算法。 【易错点】记不清各基础排序算法的交换机制及其稳定性。
第 10 题(单选题)
下面代码试图实现选择排序,使其能对数组 nums 排序为升序,则横线上应分别填写()。
void selectionSort(vector<int>& nums) {
int n = nums.size();
for (int i = 0; i < n - 1; ++i) {
int minIndex = i;
for (int j = i + 1; j < n; ++j) {
if (___) { // 在此处填入代码
minIndex = j;
}
}
}
// 在此处填入代码
}nums[j] < nums[minIndex]
swap(nums[i], nums[minIndex])nums[j] > nums[minIndex]
swap(nums[i], nums[minIndex])nums[j] <= nums[minIndex]
swap(nums[j], nums[minIndex])nums[j] <= nums[minIndex]
swap(nums[i], nums[j])正确答案A
解析详情
【答案】A 【考点】选择排序实现逻辑 【解析】 1. 升序选择排序需在未排序部分寻找最小值,判断条件应为 nums[j] < nums[minIndex]。 2. 找到本轮最小值下标后,将其与当前起始位置 i 进行交换。 3. 对应的代码为 swap(nums[i], nums[minIndex])。 【易错点】在交换时误用循环变量 j,或判断条件方向写反。
第 11 题(单选题)
下面程序实现插入排序(升序排序),则横线上应分别填写()。
void insertionSort(int arr[], int n) {
for (int i = 1; i < n; i++) {
int key = arr[i];
int j = i - 1;
while (j >= 0 && _____) { // 在此处填入代码
arr[j + 1] = arr[j];
j--;
}
___; // 在此处填入代码
}
}arr[j] > key
arr[j + 1] = keyarr[j] < key
arr[j + 1] = keyarr[j] > key
arr[j] = keyarr[j] < key
arr[j] = key正确答案A
解析详情
【答案】A 【考点】插入排序实现逻辑 【解析】 1. 插入排序需将待插入值 key 与前面已排序元素比较,若 arr[j] > key 则后移。 2. 循环结束后,j 指向第一个不大于 key 的元素位置。 3. 最终将 key 插入到其后的空位,即 arr[j + 1] = key。 【易错点】在插入位置的索引计算上出错,忘记 j 在循环末尾已自减。
第 12 题(单选题)
关于插入排序的时间复杂度,下列说法正确的是()。
正确答案B
解析详情
【答案】B 【考点】插入排序时间复杂度 【解析】 1. 最好情况:数组已升序,每轮只需一次比较,总时间复杂度为 O(n)。 2. 最坏情况:数组全逆序,每个元素都要移动到最前,复杂度为 O(n²)。 3. 平均情况下,插入排序的时间复杂度也为 O(n²)。 【易错点】混淆插入排序与选择排序(选择排序最好最坏均为 O(n²))。
第 13 题(单选题)
小杨正在爬楼梯,需要 n 阶才能到达楼顶,每次可以爬 1 阶或 2 阶,求小杨有多少种不同的方法可以爬到楼顶,横线上应填写()。
int climbStairs(int n) {
if (n <= 2) return n;
int prev2 = 1;
int prev1 = 2;
int current = 0;
for (int i = 3; i <= n; ++i) {
// 在此处填入代码
}
return current;
}prev2 = prev1;
prev1 = current;
current = prev1 + prev2;current = prev1 + prev2;
prev2 = prev1;
prev1 = current;current = prev1 + prev2;
prev1 = current;
prev2 = prev1;prev1 = current;
prev2 = prev1;
current = prev1 + prev2;正确答案B
解析详情
【答案】B 【考点】爬楼梯递推模型 【解析】 1. 核心递推式:current = prev1 + prev2,代表当前阶法等于前两阶法之和。 2. 计算出 current 后,需更新状态:旧的 prev1 变为新的 prev2,current 变为新的 prev1。 3. 更新顺序必须先计算 current,再依次移动状态窗口,否则会丢失旧值。 【易错点】更新状态变量的先后顺序错误导致计算逻辑崩溃。
第 14 题(单选题)
假设有一个班级的成绩单,存储在一个长度为 n 的数组 scores 中,每个元素是一个学生的分数。老师想要找出 所有满足 scores[i] + scores[j] + scores[k] == 300 的三元组,其中 i < j < k。下面代码实现该功能,请问其时间复杂度是( )。
int cnt = 0;
for (int i = 0; i < n; i++) {
for (int j = i + 1; j < n; j++) {
for (int k = j + 1; k < n; k++) {
if (scores[i] + scores[j] + scores[k] == 300) {
cnt++;
}
}
}
}正确答案C
解析详情
【答案】C 【考点】时间复杂度分析 【解析】 1. 代码包含三层嵌套循环,每层循环的上限均与 n 线性相关。 2. 总执行次数约为 n * (n-1) * (n-2) / 6,主项为 n³。 3. 因此该算法在大 O 表示法下对应的复杂度为 O(n³)。 【易错点】忽略循环嵌套深度对复杂度阶数的决定性影响。
第 15 题(单选题)
关于异常处理,以下说法错误的是()。
正确答案D
解析详情
【答案】D 【考点】异常处理机制 【解析】 C++ 并不强制捕获所有可能抛出的异常,异常可以沿着调用栈向上层传递。 未捕获的异常最终会导致程序调用 std::terminate 并崩溃。 但“必须捕获”的说法过于绝对,开发者可以选择在最合适的层次处理。 【易错点】混淆“异常需要被妥善处理”与“必须在每个 try 块后捕获”。
判断题(每题 2 分)
第 1 题(判断题)
以下代码能正确初始化指针。
int a = 5;
int *p = a;正确答案错误
解析详情
【答案】错误 【考点】指针初始化规范 【解析】 指针变量必须存储内存地址,通常使用取地址符 & 获取变量地址。 int *p = a; 是将整数 5 错误地当作地址赋给指针,会导致语法错误。 正确做法应为 int *p = &a; 使 p 指向变量 a。 【易错点】混淆变量的值与变量在内存中的地址。
第 2 题(判断题)
执行下面C++代码将输出11。
int x = 10;
void f() {
int x = x + 1;
cout << x << endl;
}
int main() {
f();
}正确答案错误
解析详情
【答案】错误 【考点】局部变量屏蔽与初始化 【解析】 函数 f 内声明了局部变量 int x,这会屏蔽同名的全局变量。 语句 int x = x + 1; 中的右值 x 引用的是尚未初始化的局部变量。 使用未初始化的变量进行加法运算会产生随机结果,而非 11。 【易错点】错误地认为局部变量声明中的右值会去寻找全局变量。
第 3 题(判断题)
以下C++代码合法。
struct Student {
string name;
int age;
float score;
};
Student* students = new Student[20];正确答案正确
解析详情
【答案】正确 【考点】结构体动态内存分配 【解析】 Student 结构体定义正确。new Student[20] 是合法的语法。 它在堆上申请了 20 个 Student 对象大小的连续内存,并返回首地址。 指针变量 students 接收该地址,用于后续访问该数组。 【易错点】对 new 操作符在结构体数组上的应用缺乏认识。
第 4 题(判断题)
执行下面C++代码将输出10。
void func(int* p) {
*p = 10;
}
int main() {
int a = 5;
func(&a);
cout << a << endl;
return 0;
}正确答案正确
解析详情
【答案】正确 【考点】指针传递修改实参 【解析】 func(&a) 将变量 a 的地址传递给函数。 函数内部通过解引用 *p = 10 直接操作该地址对应的内存单元。 因此 main 中的 a 被成功修改为 10,输出正确。 【易错点】混淆值传递(副本)与指针传递(原件)的区别。
第 5 题(判断题)
下面代码将二维数组 arr 传递给函数 f,函数内部用 arr[i][j] 访问元素,函数参数声明为 int arr[][4] 是错误的。
void f(int arr[][4], int rows) {
// 访问 arr[i][j]
}
int main() {
int arr[3][4] = { /* 初始化 */ };
f(arr, 3);
}正确答案错误
解析详情
【答案】错误 【考点】二维数组传参规则 【解析】 C++ 二维数组传参时,第一维大小可省略,但第二维(列宽)必须明确。 编译器需要列宽来计算 arr[i][j] 的内存偏移量。 因此 int arr[][4] 是标准且正确的写法,题干描述为错误是错误的。 【易错点】记错数组维度省略的规则。
第 6 题(判断题)
递推是在给定初始条件下,已知前一项(或前几项)求后一项的过程。
正确答案正确
解析详情
【答案】正确 【考点】递推算法定义 【解析】 递推是典型的自底向上算法,从已知的基础状态(初始条件)出发。 利用明确的数学关系(递推公式)逐步求解更大规模的子问题。 这正是递推算法的核心定义和执行过程。 【易错点】容易将递推与递归(自顶向下)的概念混淆。
第 7 题(判断题)
虽然插入排序的时间复杂度为,但由于单元操作相对较少,因此在小数据量的排序任务中非常受欢迎。
正确答案正确
解析详情
【答案】正确 【考点】插入排序应用场景 【解析】 插入排序虽为 O(n²),但在小规模或基本有序的数据下表现优异。 它的常数项系数极小,且无需额外的辅助内存空间。 许多标准库排序算法在最后阶段会切换到插入排序以提升性能。 【易错点】过分迷信 O(n log n) 复杂度,忽视小数据量下的性能开销。
第 8 题(判断题)
对整数数组进行冒泡排序(将最大元素放到最后),执行一轮之后是。
正确答案错误
解析详情
【答案】错误 【考点】冒泡排序执行过程 【解析】 第一轮冒泡应将序列中最大的元素(5)交换到最后一位。 初始序列末尾是 2,经过一轮完整的比较与交换后,5 应该在末位。 题干给出的结果序列中,最大值 5 已定位到最后,但序列前端 1 仍在首位是不对的。 【易错点】手动模拟冒泡过程不细心,导致中间状态判断失误。
第 9 题(判断题)
以下代码只能捕获 int 类型异常。
int main() {
try {
throw 42;
} catch (...) {
cout << "Caught" << endl;
}
return 0;
}正确答案错误
解析详情
【答案】错误 【考点】C++ 万能捕获语法 【解析】 catch (...) 是 C++ 中的万能捕获语法。 它可以捕获 try 块中抛出的任何类型的异常,不仅限于 int。 题干中称其“只能捕获 int”显然是错误的描述。 【易错点】不熟悉省略号 (...) 在异常处理中的全匹配作用。
第 10 题(判断题)
以下代码将 Hello 写入文件 data.txt。
ofstream file("data.txt");
cout << "Hello" << endl;
file.close();正确答案错误
解析详情
【答案】错误 【考点】文件流与标准输出 【解析】 代码中虽然定义了文件流 file,但输出使用的是 cout << "Hello"。 cout 会将内容输出到屏幕标准输出,而不是写入 data.txt 文件。 若要写入文件,应使用 file << "Hello" 语句。 【易错点】忽视了输出流对象的具体指向,混淆了 cout 与自定义文件流。