CCF编程能力等级认证GESP—C++4级—20250322

单选题(每题 2 分,共 30 分)

1、关于下述代码,说法错误的是( )。

int multiply(int x, int y);
int main() {
	int a = 4;
	int b = 5;
	int result = multiply(a, b);
	std::cout << "The result is: " << result << std::endl;
	return 0;
}
int multiply(int x, int y) {
	return x * y;
}
A. 函数 multiply 的定义应该放到函数 main 之前。
B. 函数声明 int multiply(int x, int y); 中明确指定了函数 multiply() 的返回值为整数类型。
C. 在 main 函数中,函数 multiply 通过 multiply(a, b) 被调用,其中 a 和 b 是定义在 main 函数中的变量,它们作为实参传递给了 multiply 函数的形参 x 和 y。
D. 运行上述代码,将输出 The result is: 20

正确答案:A
考察知识点:函数声明与定义的分离。
函数可通过“声明在前,定义在后”的方式使用,无需将定义放在调用函数之前,这是模块化编程的基础,允许头文件与实现文件分离。
解析过程:
代码中multiply函数已在main前声明,定义在main后仍可正常调用,A选项错误;B/C/D选项描述正确(函数返回4*5=20)。选A。

2、执行下述代码将输出( )。

int x = 10;
void func() { int x = 20; std::cout << x; }
int main() {
	func();
	std::cout << x;
	return 0;
}
A. 2020
B. 2010
C. 1010
D. 编译错误

正确答案:B
考察知识点:局部变量与全局变量的作用域优先级。
局部变量在函数内优先于全局变量,理解作用域隔离可避免变量名冲突,是代码可读性和维护性的关键。
解析过程:
func中x=20是局部变量,输出20;main中x=10是全局变量,输出10,拼接为2010。选B。

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

int a = 10;
int* p = &a;
*p = 20
A. 10
B. 20
C. 随机值
D. 编译错误

正确答案:B
考察知识点:指针解引用修改变量值。
指针通过地址间接访问变量,解引用操作(*p)是修改变量值的直接方式,是C++内存操作的核心能力。
解析过程:
p指向a的地址,*p=20等价于a=20,a的值从10变为20。选B。

4、以下哪种参数传递方式可以避免拷贝大型对象?

A. 只能用值传递
B. 只能用引用传递
C. 只能用指针传递
D. 引用传递和指针传递均可

正确答案:D
考察知识点:引用传递与指针传递的效率优势。
值传递会拷贝整个对象(开销大),而引用和指针传递仅传递地址(O(1)开销),是处理大型对象的高效方式。
解析过程:
引用和指针均通过地址访问对象,避免拷贝,D选项正确;A选项值传递会拷贝,B/C选项“只能”表述错误。选D。

5、执行下述代码,将输出( )。

void swap(int a, int &b) {
	int temp = a;
	a = b;
	b = temp;
}
int main() {
	int x = 1, y = 2;
	swap(x, y);
	std::cout << x << y;
	return 0;
}
A. 12
B. 21
C. 22
D. 11

正确答案:D
考察知识点:值传递与引用传递的混合效果。
值传递参数的修改不影响实参,引用传递参数的修改会影响实参,混淆二者会导致逻辑错误。
解析过程:
swap函数中a是x的副本(值传递),修改a不影响x;b是y的引用,b=temp将y从2改为1。最终x=1,y=1,输出11。选D。

6、下面的描述中,( )正确定义一个名为 Person 的结构体并正确初始化了一个 Person 结构体的变量 p。

A. 
struct Person {
	string name;
	int age;
};
Person p("Yang", 10);
B.
struct Person {
	string name,
	int age;
};
Person p;
p.name = "Yang";
p.age = 10;
C.
struct Person {
string name;
int age;
};
Person p = { "Yang", 10 };
D.
struct Person {
string name;
int age;
};
Person p = new Person("Yang", 10);

正确答案:C
考察知识点:结构体的定义与初始化。
结构体初始化需匹配成员类型和顺序,C++11支持列表初始化,错误的初始化方式(如调用未定义的构造函数)会导致编译失败。
解析过程:
C选项使用列表初始化Person p = {“Yang”, 10},符合语法;A选项结构体无构造函数,B选项成员声明用逗号分隔错误,D选项new返回指针不能赋值给对象。选C。

7、给定如下代码,下面描述错误的是( )

struct Person {
	std::string name;
	int age;
	struct Address {
		std::string street;
		std::string city;
	};
	Address address;
};
A. 结构 Person 内嵌套结构 Address
B. Person 有一个 Address 类型的 address 成员
C. 一个 Person 类型的变量 p 的 address 的初始化可以写成: p.address.street = p.address.city = "Anytown";
D. 结构的嵌套可以减少命名冲突,因此可以不必控制嵌套层次

正确答案:D

8、假设 int arr[2][3] = {{1,2,3},{4,5,6}};,则 arr[1][2] 的值是( )。

A. 2
B. 3
C. 5
D. 6

正确答案:D
考察知识点:嵌套结构体的合理设计。
嵌套结构体可增强代码组织性,但过度嵌套会降低可读性和维护性,需控制层次以保证代码清晰。
解析过程:
D选项“不必控制嵌套层次”错误,过度嵌套会导致逻辑复杂;A/B/C选项描述正确(嵌套定义、成员访问)。选D。

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

A. int arr[3,4];
B. int arr[3][4];
C. int arr(3,4);
D. int a[3-4];

正确答案:B
考察知识点:二维数组的元素访问。
二维数组按行优先存储,arr[i][j]表示第i行第j列元素,索引从0开始,错误的索引会访问错误数据。
解析过程:
arr[1][2]对应第二行第三列元素(6),选D。

10、小杨正在爬楼梯,需要爬n阶才能到达楼顶。如果每次可以爬1个或2个台阶,下面代码采用递推算法来计算一共有多少种不同的方法可以爬到楼顶,则横线上应填写( )。

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

正确答案:B
考察知识点:递推算法解爬楼梯问题(斐波那契数列变种)。
爬楼梯问题的递推公式为f(n) = f(n-1) + f(n-2),迭代实现可将时间复杂度优化至O(n),是动态规划的经典应用。
解析过程:
初始化f1=1(n=1)、f2=2(n=2),循环从i=3开始,res = f1 + f2(当前台阶数),更新f1=f2、f2=res,符合递推逻辑。选B。

11、给定如下算法,其时间复杂度为( )。

bool f(int arr[], int n, int target) {
	for (int i = 0; i < (1 << 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;
}

A . O ( n 2 ) A. O(n^2) A.O(n2)
B . O ( n × 2 n ) B. O(n \times 2^n) B.O(n×2n)
C . O ( 1 ) C. O(1) C.O(1)
D . O ( n 3 ) D. O(n^3) D.O(n3)

正确答案:B
考察知识点:指数级时间复杂度的识别。
外层循环1<<n(即2ⁿ)次,内层循环n次,总操作次数为n×2ⁿ,时间复杂度为O(n×2ⁿ),指数级增长会导致算法在n较大时不可用。
解析过程:
外层循环2ⁿ次,内层n次,复杂度为O(n×2ⁿ),选B。

12、下面关于排序稳定性的描述,正确的是( )。

A. 稳定性指算法的时间复杂度恒定
B. 稳定排序保证相同元素的相对顺序不变
C. 选择排序是稳定排序
D. 插入排序不是稳定排序

正确答案:B
考察知识点:排序算法的稳定性定义。
稳定性是排序算法的重要性质,稳定排序可保证相等元素的相对顺序不变,在多关键字排序中至关重要(如先按成绩再按姓名排序)。
解析过程:
B选项正确描述稳定性定义;A选项混淆时间复杂度;C选项选择排序不稳定;D选项插入排序稳定。选B。

13、对数组 arr[]={5, 3, 8, 1} 进行升序排序,执行第一轮冒泡排序后数组 arr 中的内容为( )

A. 3, 5, 1, 8
B. 3, 1, 5, 8
C. 3, 5, 8, 1
D. 5, 3, 8, 1

正确答案:A
考察知识点:冒泡排序第一轮的执行过程。
冒泡排序通过相邻元素比较交换,将最大元素移至末尾,理解第一轮过程是掌握“逐层冒泡”逻辑的基础。
解析过程:
原数组[5,3,8,1],第一轮比较交换后,最大元素8移至末尾,中间元素调整为[3,5,1,8]。选A。

14、运行下面的代码,将出现( )。

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
考察知识点:异常的抛出与捕获匹配。
异常类型需与catch块类型匹配,runtime_error对象会被catch (const runtime_error &e)捕获,确保错误被正确处理。
解析过程:
hmean(10,-10)触发a == -b,抛出runtime_error,被第一个catch块捕获,输出错误信息。选A。

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

A. 
freopen("log.txt","w", stdout);
cout << "Happy Spring!" << endl;
fclose(stdout);
B.
std::ofstream outFile("log.txt");
outFile << "Happy Spring!" << endl;
outFile.close();
C.
std::ofstream outFile("log.txt");
cout << "Happy Spring!" << endl;
outFile.close();
D.
ofstream log_file("log.txt");
streambuf* org_cout = cout.rdbuf();
cout.rdbuf(log_file.rdbuf());
cout << "Happy Spring!" << endl;
cout.rdbuf(org_cout);

正确答案:C
考察知识点:文件重定向输出的实现方式。
输出重定向需将cout的缓冲区指向文件,或直接使用文件流对象,否则输出仍会发送到控制台,无法写入文件。
解析过程:
C选项仅创建outFile但未重定向cout,cout输出仍在控制台,无法写入文件;A/D选项通过rdbuf重定向,B选项直接使用文件流。选C。

判断题(每题 2 分,共 20 分)

1、函数是C++中的核心概念,用于封装可重用的代码块。

正确答案:正确
考察知识点:函数的核心作用。
函数封装可重用代码块,提高代码复用性和可读性,是结构化编程的核心。
解析过程:
函数是C++的核心概念,描述正确,正确。

2、在C++中,函数的返回类型可以省略,默认为 int 。

正确答案:错误
考察知识点:函数返回类型的语法要求。
C++函数必须显式指定返回类型,省略返回类型会导致编译错误(C语言允许默认int,但C++不支持)。
解析过程:
C++不允许省略返回类型,错误。

3、结构体的成员默认是 public 访问权限。

正确答案:正确
考察知识点:结构体成员的默认访问权限。
结构体默认访问权限为public(类默认private),理解访问权限是封装的基础。
解析过程:
结构体成员默认public,正确。

4、假设整数数组 arr[4]= {0, 1, 2, 3}; 的第一个元素在内存中的地址为 0x7ffee4065820 , 经过 int* p= arr; p += 1; 后,指针 p 的值是1。

正确答案:错误
考察知识点:指针的值(地址)与指向的变量值。
指针存储的是变量的地址(十六进制数),而非变量的值,混淆地址和值会导致内存操作错误。
解析过程:
p +=1后,指针p的值为arr[1]的地址(如0x7ffee4065824),而非值1,错误。

5、二维数组作为函数参数时,必须显式指定所有维度的大小。

正确答案:错误
考察知识点:二维数组作为函数参数的维度指定。
二维数组作为参数时,行大小可省略(由实参推导),但列大小必须显式指定,否则编译器无法计算内存布局。
解析过程:
二维数组参数可省略行大小(如void func(int arr[][4])),错误。

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

正确答案:正确
考察知识点:递推算法的定义。
递推通过初始值和递推公式迭代求解,是动态规划、数学建模的核心思想,正确理解其定义是设计高效算法的基础。
解析过程:
递推的核心是“逐步求解”,描述正确,正确。

7、考虑最坏情况下冒泡排序算法的时间复杂度,T(n)为待排序数字的数目为n的复杂度,则其递推关系式为T(n)=T(n-1)+n,T(0)=1。

正确答案:正确
考察知识点:冒泡排序最坏时间复杂度的递推关系式。
冒泡排序最坏情况需进行n-1趟,每趟比较n-i次,总次数为n+(n-1)+…+1 = n(n+1)/2,递推式为T(n)=T(n-1)+n。
解析过程:
递推式正确,正确。

8、插入排序在最好情况(已有序)下的时间复杂度是 O ( n 2 ) O(n^2) O(n2)

正确答案:错误
考察知识点:插入排序的最好时间复杂度。
插入排序在最好情况(已排序)下,只需比较n-1次,无需移动元素,时间复杂度为O(n),优于最坏情况的O(n²)。
解析过程:
最好情况复杂度为O(n),错误。

9、对数组 arr[]={4, 3, 1, 5, 2} 进行升序排序,执行第一轮选择排序后数组arr中的内容是 {1, 4, 3, 5,2}。

正确答案:错误
考察知识点:选择排序第一轮的执行过程。
选择排序第一轮需找出最小元素并交换至首位,错误的交换对象会导致排序结果错误。
解析过程:
数组[4,3,1,5,2]的最小元素是1(索引2),与首位4交换,结果应为[1,3,4,5,2],题目描述错误,错误。

10、未捕获异常会调用std::terminate终止程序。

正确答案:正确
考察知识点:未捕获异常的后果。
C++中未捕获的异常会触发std::terminate(),导致程序终止,这是异常处理机制的安全保障。
解析过程:
未捕获异常会终止程序,正确。

编程题 (每题 25 分,共 50 分)

荒地开垦

【问题描述】
小杨有一大片荒地,可以表示为一个n行m列的网格图。

小杨想要开垦这块荒地,但荒地中一些位置存在杂物,对于一块不存在杂物的荒地,该荒地可以开垦当且仅当其上下左右四个方向相邻的格子均不存在杂物。
小杨可以选择至多一个位置,清除该位置的杂物,移除杂物后该位置变为荒地。小杨想知道在清除至多一个位置的杂物的情况下,最多能够开垦多少块荒地。
【输入格式】
第一行包含两个正整数n, m,含义如题面所示。
之后n行,每行包含一个长度为m且仅包含字符 . 和 # 的字符串。如果为 . ,代表该位置为荒地,如果为 # ,代表该位置为杂物。
【输出格式】
输出一个整数,代表在清除至多一个位置的杂物的情况下,最多能够开垦的荒地块数。
【样例输入 1】

3 5
.....
.#..#
.....

【样例输出 1】
11
【样例解释】
移除第二行从左数第二块空地的杂物后:

.....
....#
.....

第一行从左数前4块荒地,第二行从左数前3块荒地,第三行从左数前4块荒地,均可开垦,4 + 3 + 4 = 11。
【数据范围】
对于全部数据,保证有 1 ≤ n , m ≤ 1000 1 \le n, m \le 1000 1n,m1000

二阶矩阵

【问题描述】
小 A 有一个n行m列的矩阵A。
小 A 认为一个 2 × 2 2 \times2 2×2的矩阵D是好的,当且仅当 D 1 , 1 × D 2 , 2 = D 1 , 2 × D 2 , 1 D_{1,1} \times D_{2,2} = D_{1,2} \times D_{2,1} D1,1×D2,2=D1,2×D2,1。其中 D i , j D_{i,j} Di,j表示矩阵D的第i行第j列的元素。
小 A 想知道 中有多少个好的子矩阵。
【输入格式】
第一行,两个正整数n, m。
接下来n行,每行m个整数 A i , 1 , A i , 2 , . . . , A i , m A_{i,1}, A_{i,2}, ..., A_{i,m} Ai,1,Ai,2,...,Ai,m
【输出格式】
一行,一个整数,表示A中好的子矩阵的数量。
【样例输入 1】
3 4
1 2 1 0
2 4 2 1
0 3 3 0
【样例输出 1】
2
【样例解释】
样例中的好的子矩阵如下:
在这里插入图片描述

【数据范围】
对于所有测试点,保证 1 ≤ n ≤ 500 , 1 ≤ m ≤ 500 , − 100 ≤ A i , j ≤ 100 1 \le n \le 500 ,1 \le m \le 500 ,-100 \le A_{i,j} \le 100 1n5001m500100Ai,j100

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

青岛少儿编程-王老师

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值