试卷解析 · 理解每一步
2025年06月 C++ 四级
2025-06-Level-4
试卷解析总览,可直接查看每题答案与解析。
第 1 题(单选题,2 分)
在C++中,声明一个指向整型变量的指针的正确语法是()。
正确答案A
解析详情
在 C++ 中,声明指针的语法为“类型* 变量名;”。int* ptr; 表示声明一个指向 int 类型变量的指针。星号(*)紧跟在类型之后或变量名之前均可,但位置必须在两者之间。
第 2 题(单选题,2 分)
下面的函数接收一个3行4列的二维数组并输出其中元素,则横线上不能填写()。
void printArray(____) {
for (int i = 0; i < 3; ++i)
for (int j = 0; j < 4; ++j)
std::cout << arr[i][j] << " ";
}正确答案D
解析详情
二维数组作为函数参数时,必须指定第二维(列数)的大小,以便编译器计算内存偏移量。int** arr 是二级指针,指向指针的指针,与二维数组在内存中按行连续存储的物理布局不兼容。
第 3 题(单选题,2 分)
在C++中,int arr[3][4] 和 int* arr = new int[12] 均可模拟一个3行4列的二维数组。关于这两种方式,下面说法错误的是()。
正确答案D
解析详情
静态数组 int arr[3][4] 在栈上分配,作用域结束由系统自动释放。而使用 new 申请的动态内存位于堆上,必须使用 delete[] 显式手动释放,否则会导致程序运行期间出现内存泄漏。
第 4 题(单选题,2 分)
关于以下 C++代码,说法正确的是()。
int main() {
greet();
return 0;
}
void greet() {
cout << "Hello!" << endl;
}正确答案B
解析详情
C++ 遵循“先声明后使用”的原则。在代码中,greet() 的定义出现在 main 函数调用之后,且在调用前没有提供函数原型声明,编译器在处理 main 时无法识别该标识符,导致编译错误。
第 5 题(单选题,2 分)
在 C++ 中,如果希望通过函数修改传入的结构体对象的内容,应该使用哪种参数传递方式?
正确答案C
解析详情
值传递会创建对象的副本,函数内部对副本的修改无法反馈给原始对象。若要修改原始结构体,必须传递对象的地址(指针传递)或别名(引用传递),使函数能够直接操作原始内存空间。
第 6 题(单选题,2 分)
以下哪个选项正确描述了 C++ 中形参和实参的区别?
正确答案B
解析详情
形参是函数定义时在括号内声明的变量,仅作为占位符使用,只有在调用时才分配内存;实参是函数调用时传递给函数的具体常量、变量或表达式的值,用于初始化形参。
第 7 题(单选题,2 分)
运行如下代码会输出()。
int value = 100;
void print1() {
int value = 50;
cout << value << " ";
cout << ::value << " ";
}
void print2() {
cout << value << " ";
}
print1();
print2();正确答案C
解析详情
print1 中局部变量 value(50) 屏蔽了同名全局变量,故首个输出为 50;紧接着使用 ::value 强制访问全局作用域中的变量,输出 100。print2 中无局部同名变量,直接访问全局变量输出 100。序列为 50 100 100。
第 8 题(单选题,2 分)
小杨在整理一副扑克牌的所有红心扑克牌,使其从小到大排列。他的做法是:最开始抓到第1张扑克牌被认为已经排好序;然后抓第2张扑克牌,将其插入至有序部分的正确位置;不断循环步骤,每次将新抓到扑克牌插入至有序部分,直至抓完所有扑克牌,这样抓牌结束时就完成了扑克牌的排序。小杨这种整理扑克牌的方式与()排序的方式最接近。
正确答案B
解析详情
小杨的操作是先视第一张牌有序,后续每抓一张牌都将其插入到前面已排序序列的正确位置。这完全符合“插入排序”每一步将一个待排序元素按值大小插入到已排序部分适当位置的核心逻辑。
第 9 题(单选题,2 分)
以下哪种情况是使用插入排序的合适场景?
正确答案C
解析详情
插入排序在数据“几乎有序”的情况下,每个待插入元素只需进行极少次比较和移动即可归位,此时时间复杂度接近 O(n),效率极高。对于大规模乱序数据,其表现通常不如 O(n log n) 级别的算法。
第 10 题(单选题,2 分)
以下关于递推算法基本思想的描述,正确的是()。
正确答案B
解析详情
递推算法是从已知的初始条件(边界情况)出发,利用确定的关系式(递推公式)由前向后、由小到大逐一推导出后续各项值的过程。选项 A 是分治思想,C 是枚举思想,D 是贪心思想。
第 11 题(单选题,2 分)
给定如下算法,其时间复杂度为()。
bool f(int arr[], int n, int target) {
for (int i = 0; i < 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;
}正确答案B
解析详情
外层循环 for(i=0; i<n; i++) 执行 n 次,内层循环 for(j=0; j<n; j++) 同样执行 n 次。循环体内位运算和加法均为 O(1) 基本操作。总基本操作次数与 n * n 成正比,故时间复杂度为 O(n²)。
第 12 题(单选题,2 分)
下述斐波那契数列计算的时间复杂度是()。
int fibonacci(int n) {
if (n == 0) return 0;
if (n == 1) return 1;
return fibonacci(n - 1) + fibonacci(n - 2);
}正确答案D
解析详情
该实现为朴素递归,计算 fib(n) 会产生两个子递归 fib(n-1) 和 fib(n-2),形成一个深为 n 的递归调用树。由于存在大量重复计算,调用节点的总数随 n 指数级增长,复杂度为 O(2ⁿ)。
第 13 题(单选题,2 分)
关于下面 C++ 程序的描述,( )最准确。
ifstream in("data.txt");
string line;
while (getline(in, line)) {
cout << line << endl;
}正确答案C
解析详情
代码逻辑:首先通过 ifstream in("data.txt") 打开名为 data.txt 的文件。接着 while(getline(in, line)) 会逐行读取文件内容直到末尾,并将读到的每一行通过 cout 打印到屏幕。对应选项 C。
第 14 题(单选题,2 分)
在C++中,异常处理机制(try-catch块)的主要目的是()。
正确答案B
解析详情
异常处理(try-catch)旨在捕获程序在运行期间发生的意外错误(如除零、文件丢失等),并将错误检测逻辑与错误处理逻辑分离。通过这种结构化方式,程序可以尝试从错误中恢复或安全退出,提高健壮性。
第 15 题(单选题,2 分)
为了提高冒泡排序的效率,如果某轮“冒泡”中没有执行任何交换操作,说明数组已经完成排序,可直接返回结果,则两条横线上分别应该填写()。
void bubbleSortWithFlag(vector<int> &nums) {
for (int i = nums.size() - 1; i > 0; i--) {
bool flag;
// 1
for (int j = 0; j < i; j++) {
if (nums[j] > nums[j + 1]) {
swap(nums[j], nums[j + 1]);
// 2
}
}
if (!flag) {
break;
}
}
}flag = false;
flag = false;flag = false;
flag = true;flag = true;
flag = false;flag = true;
flag = true;正确答案B
解析详情
标志位优化的核心是检测本轮是否发生交换。在每轮外层循环开始前,需将 flag 重置为 false(假设有序)。若内层循环中发生了 swap 交换,则设 flag 为 true。若一轮结束 flag 仍为 false,说明整轮无交换,数组已完全有序。
判断题
第 1 题(判断题,2 分)
下面 C++ 代码正确声明了一个返回 int 类型、接受两个 int 参数的函数。
int add(int, int);正确答案正确
解析详情
在 C++ 中,函数声明(原型)只需指明返回类型、函数名以及参数类型列表。参数的具体变量名在声明阶段是可选的。因此,int add(int, int); 是完全符合语法规范的函数原型。
第 2 题(判断题,2 分)
下面 C++ 代码的输出是 15。
void foo(int x) {
x += 5;
}
int main() {
int a = 10;
foo(a);
cout << a << endl;
}正确答案错误
解析详情
该代码采用值传递(Pass by Value),函数 foo 内修改的是实参 a 的副本 x。函数返回后,main 函数中的变量 a 本身没有受到任何影响。因此 cout << a 输出的值仍为 10。
第 3 题(判断题,2 分)
下面 C++ 代码在一个结构体中又定义了别的结构体。这种结构嵌套定义的方式语法不正确。
#include <string>
#include <vector>
using namespace std;
struct Library {
struct Book {
struct Author {
string name;
int birthYear;
};
string title;
int year;
Author author;
};
};正确答案错误
解析详情
C++ 语法完全允许在结构体内部嵌套定义另一个结构体。这种方式通常用于表示明确的层级或从属关系,使得数据组织更加严密。代码中的三层嵌套结构在语法上是合法的。
第 4 题(判断题,2 分)
在C++中,相比于值传递,使用引用传递作的优点可以直接操作和修改原始变量,避免数据拷贝,提高效率。
正确答案正确
解析详情
引用传递直接向函数传递实参变量的别名,不产生对象副本,避免了拷贝大型结构体带来的时空开销。同时,它允许函数内部通过引用直接访问并修改实参的内存单元,描述准确。
第 5 题(判断题,2 分)
下面这段代码不合法,因为每一行都必须显式初始化 3 个元素。
int arr[2][3] = {{1, 2}, {3}};正确答案错误
解析详情
在 C++ 中,二维数组初始化时如果提供的初始值数量少于数组容量,编译器会自动为剩余位置补 0。int arr[2][3] = {{1, 2}, {3}}; 是合法的,未明确给出的位置(如 arr[0][2] 等)都会被置 0。
第 6 题(判断题,2 分)
以下程序中使用了递推方式计算阶乘(),计算结果正确。
int factorial(int n) {
int res = 1;
for (int i = 0; i < n; ++i) {
res *= i;
}
return res;
}正确答案错误
解析详情
代码中的循环变量 i 从 0 开始。在第一次迭代执行 res *= i; 时,由于 0 乘以任何数都得 0,变量 res 会立刻变成 0 并保持到结束。正确的阶乘累乘应当从 i = 1 开始或使乘数不包含 0。
第 7 题(判断题,2 分)
无论初始数组是否有序,选择排序都执行次比较
正确答案正确
解析详情
选择排序的算法逻辑决定了每一轮都必须扫描完剩余的所有元素以确定最小值的位置。无论输入数据是已经有序、逆序还是随机,它的比较次数始终是固定的 n(n-1)/2 次,时间复杂度恒定为 O(n²)。
第 8 题(判断题,2 分)
以下C++代码,尝试对有n个整数的数组arr进行排序。这个代码实现了选择排序算法。
for (int i = 0; i < n - 1; ++i) {
int minIndex = i;
for (int j = i + 1; j < n; ++j) {
if (arr[j] < arr[minIndex])
minIndex = j;
}
if (minIndex != i)
swap(arr[i], arr[minIndex]);
}正确答案正确
解析详情
代码逻辑:外层循环遍历位置 i,内层循环寻找后续序列中最小元素的下标 minIndex,并在每轮结束时执行一次 swap 将最小值归位。这正是选择排序的标准流程,逻辑完全正确。
第 9 题(判断题,2 分)
如果一个异常在 try 块中抛出但没有任何 catch 匹配,它将在编译时报错。
正确答案错误
解析详情
异常是在程序运行时抛出的。如果抛出的异常没有匹配的 catch 块,程序最终会调用 std::terminate() 强制终止。这是一个运行时崩溃行为,编译器通常无法在编译阶段检测出所有未捕获的路径。
第 10 题(判断题,2 分)
下面 C++ 代码实现将 Hello 写入 data.txt。
ofstream out("data.txt");
out << "Hello";
out.close();正确答案正确
解析详情
代码逻辑:通过 ofstream 对象创建并打开 data.txt。使用插入操作符 << 将字符串内容写入流,最后调用 close() 刷新缓冲区并释放文件资源。流程规范,能成功实现文件写入。