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