CCF编程能力等级认证GESP—C++3级—20230611
单选题(每题 2 分,共 30 分)
1、高级语言编写的程序需要经过以下( )操作,可以生成在计算机上运行的可执行代码。
A. 编辑
B. 保存
C. 调试
D. 编译
正确答案:D
A选项:编辑(Editing):这是编写程序的第一步,程序员使用文本编辑器或集成开发环境来编写源代码。但是,编辑本身并不能将源代码转换为计算机可以执行的可执行代码。
B选项:保存(Saving):保存是将编辑好的源代码保存到文件系统中的操作。这同样不会生成可执行代码。
C选项:调试(Debugging):调试是程序开发过程中的一个重要环节,用于查找并修复程序中的错误。调试通常发生在编译之后,当程序运行不正常时,使用调试工具进行错误追踪和修复。因此,调试本身并不能生成可执行代码。
D选项:编译(Compilation):编译是将高级语言编写的源代码转换为计算机可以理解和执行的可执行代码的过程。编译器读取源代码文件,并生成一个或多个目标文件,这些目标文件包含了可以在特定机器上执行的机器代码。然后,链接器将这些目标文件与必要的库文件链接起来,生成最终的可执行文件。
2、二进制数 11.01 在十进制下是( )。
A. 3.01
B. 3.05
C. 3.125
D. 3.25
正确答案:D
整数部分:
11 在二进制下转换为十进制是 1 ∗ 2 1 + 1 ∗ 2 0 = 2 + 1 = 3 1 * 2^1 + 1 * 2^0 = 2 + 1 = 3 1∗21+1∗20=2+1=3
小数部分:
01 在二进制下转换为十进制是 0 ∗ 2 − 1 + 1 ∗ 2 − 2 = 0 + 0.25 = 0.25 0 * 2^{-1} + 1 * 2^{-2} = 0 + 0.25 = 0.25 0∗2−1+1∗2−2=0+0.25=0.25
将整数部分和小数部分相加,得到 11.01(二进制)等于 3.25(十进制)。
3、已知大写字符’A’的 ASCII 编码的十六进制表示为 0x41,则字符’F’的ASCII 编码的十六进制表示为( )。
A. 46
B. 47
C. 48
D. 49
正确答案:A
字母 | 十六进制数 |
---|---|
A | 0x41 |
B | 0x42 |
C | 0x43 |
D | 0x44 |
E | 0x45 |
F | 0x46 |
4、以下哪个不是 C++语言中的运算符?( )
A. &
B. &&
C. *
D. **
正确答案:D
A选项:在C++中,&是地址运算符,用于获取变量的地址。它也可以用作位与运算符。
B选项:在C++中,&&是逻辑与运算符,用于检查两个条件是否都为真。
C选项:在C++中,可以用作乘法运算符。
D选项:在C++中,不是有效的运算符。单个可以作为解引用或乘法运算符,但两个连续的并没有定义的意义。
5、如果字符串定义为 char str[] = “Hello”;,则字符数组str 的长度为( )。
A. 0
B. 5
C. 6
D. 7
正确答案:C
字符串"Hello"实际上包含了5个字符:‘H’, ‘e’, ‘l’, ‘l’, ‘o’。然而,C风格字符串在结尾还有一个额外的null终止符(‘\0’),用于标识字符串的结束。因此,字符数组str的总长度是5个字符加上1个null终止符,总共是6个字符。
6、一个数组定义为 double array[3];,则这个数组占用内存的大小为( )。
A. 24
B. 12
C. 6
D. 3
正确答案:A
在C++中,double类型通常占用64位(8字节)的内存空间。因此,一个double数组的每个元素都会占用8字节。
由于该数组包含3个元素,因此占用内存的大小为3 * 8 = 24字节
7、以下数组定义,符合 C++语言语法的是( )。
A. int a[];
B. int b['3'];
C. int c[3.0];
D. int[3] d;
正确答案:B
在C++中,数组的定义需要指定数组的类型和数组的大小,且数组的大小必须是一个常量表达式,其值在编译时已知且必须是非负整数。
在C++中每个字符都有对应的 ASCII 编码,当需要使用整数类型的值时,可以将字符通过对应的ASCII 编码转换为整数,所以 int b[’3’];等价于 int b[51];。
8、下列关于进制的叙述,不正确的是( )。
A. 正整数的二进制表示中只会出现 0 和 1。
B. 10 不是 2 的整数次幂,所以十进制数无法转换为二进制数。
C. 从二进制转换为 8 进制时,可以很方便地由低到高将每3 位二进制位转换为对应的一位 8 进制位。
D. 从二进制转换为 16 进制时,可以很方便地由低到高将每4 位二进制位转换为对应的一位 16 进制位。
正确答案:B
任意数字都可以在不同的进制之间转换,
9、下列关于 C++语言中数组的叙述,不正确的是( )。
A. 数组必须先定义后使用。
B. 数组的所有元素在内存中是连续存放的。
C. 除了字符数组,在定义数组时“[]”内必须有常数。
D. 不能对数组赋值,但可以对数组的每个基础类型的元素赋值。
正确答案:C
A选项:在 C++ 中,必须先声明(定义)数组,然后才能使用它。数组的声明告诉编译器数组的名称、类型以及它包含的元素数量。
B选项:数组在内存中的布局是连续的,这意味着数组的第一个元素在内存中的位置紧接着是第二个元素的位置,依此类推。
C选项:在 C++ 中,数组的大小在定义时必须是一个常量表达式,而不仅仅是常数。只要它在编译时是已知的且为非负整数。
D选项:在 C++ 中,你不能直接将一个数组赋值给另一个数组。但是,你可以逐个元素地为数组赋值。
10、一个 int 类型的值,做以下哪个操作,一定会变回原来的值?( )
A. 左移 3 位,再右移 3 位。
B. 右移 3 位,再左移 3 位。
C. 按位或 7,再按位与-8。
D. 按位异或 7,再按位异或 7。
正确答案:D
注意:
1.对于正数来讲,左移需要补0,右移需要补0;
2.对于负数来说,左移需要补0,右移需要补1。
说明:
1.对于A选项,左移3位相当于将该int值× 2 3 2^3 23,有可能存在越界情况(超出int范围),因此A选项不可以
-5的原码为:1000 0101, 反码为:1111 1010,补码为:1111 1011
选项 | 操作1补码 | 操作1原码 | 操作2补码 | 操作2原码 | 最终结果 |
---|---|---|---|---|---|
A | 1101 1000(左移3位) | 1010 1000 | 1111 1011(右移3位) | 10000 0101 | -5 |
B | 1111 1111(右移3位) | 1000 0001 | 1111 1000(左移3位) | 1000 1000 | -8 |
C | 1111 1111(按位或7) | 1000 0001 | 1111 1000(与-8) | 1000 1000 | -8 |
D | 1111 1100(异或7) | 1000 0100 | 1111 1011(异或7) | 1000 0101 | -5 |
11、如果 a 和 b 均为 int 类型的变量,下列表达式能正确判断“a 等于b”的是( )。
A. ((a / b) == 1)
B. ((a & b) == a)
C. ((a ^ b) == 0)
D. ((a | b) == b)
正确答案:C
A选项:这个表达式只能判断 a 是否是 b 的整数倍且 a 大于 b。如果 a 和 b 不相等,或者 a 不是 b 的整数倍,这个表达式就会返回 false。因此,这个表达式不能正确判断“a 等于 b”。
B选项:这个表达式用来判断 a 的所有为 1 的位是否都在 b 中为 1。如果 a 和 b 不相等,但是 a 的某些位上的 1 在 b 中也是 1,那么这个表达式仍然会返回 true。因此,这个表达式不能正确判断“a 等于 b”。(2 & 7)
C选项:异或运算符 ^ 的特点是,如果 a 和 b 相等,那么 a ^ b 的结果会是 0。因为相同位上的两个 1 或两个 0 进行异或运算的结果都是 0。所以,这个表达式能够正确判断“a 等于 b”。
D选项:这个表达式用来判断 a 中为 1 的位在 b 中是否为 1,或者 b 中本身为 1 的位是否保持不变。如果 a 和 b 不相等,但是 a 的某些位上的 0 对应的 b 的位是 1,那么这个表达式仍然会返回 true。因此,这个表达式不能正确判断“a 等于 b”。 (2 | 7)
12、如果 a 为 int 类型的变量,下列哪个表达式可以正确求出满足“小于等于a且是 4 的倍数”的整数中最大的?( )
A. (a & (~3))
B. ((a << 2) >> 2)
C. (a ^ 3)
D. ((a - 1) | 3) + 1
正确答案:A
选项 | a = 4 | a = 5 | a = 6 | a = 7 | 备注 |
---|---|---|---|---|---|
a & (~3) | 4 | 4 | 4 | 4 | ~3 = 4 |
(a << 2) >> 2 | 4 | 5 | 6 | 7 | <<左移,>>右移 |
a ^ 3 | 7 | 6 | 5 | 4 | ^异或 |
((a - 1) | 3) + 1 | 4 | 8 | 8 | 8 | |或 |
13、在下列代码的横线处填写( ),可以使得输出是“24 12”。
#include <iostream>
using namespace std;
int main(){
int a = 12, b = 24;
________; // 在此处填入代码
a = a ^ b;
b = a ^ b;
cout << a << " " << b << endl;
return 0;
}
A. a = a ^ b
B. b = a ^ b
C. a = a + b
D. b = a + b
正确答案:A
a = 12(1100), b = 24(11000)
过程\选项 | a = a ^ b | b = a ^ b | a = a + b | b = a + b |
---|---|---|---|---|
___ | a = 20(1 0100) | b = 20(1 0100) | a = 36(10 0100) | b = 36(10 0100) |
b = a ^ b | 12(1100) | 24(1 1000) | 60(11 1100) | 60(11 1100) |
a = a ^ b | 24(1 1000) | 20(1 0100) | 24(11000) | 48(11 0000) |
14、在下列代码的横线处填写( ),可以使得输出是“2”。
#include <iostream>
using namespace std;
int main(){
int array[5] = {3, 7, 5, 2, 4};
int min = 0;
for (int i = 0; i < 5; i++)
if (____) // 在此处填写代码
min = array[i];
cout << min << endl;
return 0;
}
A. min > array[i]
B. min < array[i]
C. min = array[i]
D. 以上均不对。
正确答案:D
为了使输出为“2”,代码应该找到数组中的最小值并将其存储在变量 min 中。当前初始化 min 为0,而数组中的最小值实际上是2,因此我们需要找到一种方式来更新 min 的值。
通常情况下,我们如果想求最小值,min的初值应该足够大,或者直接赋值为数组的第一个元素。
15、在下列代码的横线处填写( ),可以使得输出不是“31”。
#include <iostream>
using namespace std;
int main(){
int array[5] = {1, 2, 4, 8, 16};
int res = 0;
for (int i = 0; i < 5; i++)
________; // 在此处填写代码
cout << res << endl;
return 0;
}
A. res = res + array[i]
B. res = res & array[i]
C. res = res | array[i]
D. res = res ^ array[i]
正确答案:B
初始值:res = 0, array[5] = {1, 2, 4, 8, 16}
十进制数 | 二进制数 |
---|---|
0 | 00 0000 |
1 | 00 0001 |
2 | 00 0010 |
4 | 00 0100 |
8 | 00 1000 |
16 | 01 0000 |
32 | 10 0000 |
i | array[i] | res = res + array[i] | res = res & array[i] | res = res | array[i] | res = res ^ array[i] |
---|---|---|---|---|---|
0 | 1 | 1 | 0 | 1 | 1 |
1 | 2 | 3 | 0 | 3 | 3 |
2 | 4 | 7 | 0 | 7 | 7 |
3 | 8 | 15 | 0 | 15 | 15 |
4 | 16 | 31 | 0 | 31 | 31 |
判断题(每题 2 分,共 20 分)
1、一个算法可以用不同的形式来描述,但要求描述比较规范,因此不能用自然语言描述。
正确答案:错误
算法确实可以用不同的形式来描述,包括自然语言、流程图、伪代码和编程语言等。虽然自然语言可能不如其他形式精确,但它仍然是一种有效的描述方式。
2、域名是由一串用点分隔的名字来标识互联网上一个计算机或计算机组的名称,CCF 编程能力等级认证官方网站的域名是 gesp.ccf.org.cn,其中顶级域名是gesp。
正确答案:错误
域名是由两个或两个以上的词构成,中间用点号分隔开,最右边的那个词称为顶级域名,所以顶级域名是cn
3、数据编码方式只有原码、反码、补码三种。
正确答案:错误
数据编码的方式非常多,例如格雷码、哈夫曼编码等,它们适合使用的场景各不相同。
4、在 C++语言中,长度为 n 的数组,合理的下标范围是从0 到n,包括0 和n。
正确答案:错误
长度为n的数组,其下标范围是从0到n-1,不包括n。
5、字符常量’\0’常用来表示字符串结束,它和字符常量’0’是不同的。
正确答案:正确
字符常量’\0’是字符串和字符数组的结束标记,它的 ASCII 码为 0,字符常量’0’的 ASCII 码为 48,与’\0’是不同的字符常量。
6、在 C++语言中,可以使用字符(如’0’)作为数组下标。
正确答案:正确
在C++中每个字符都有对应的 ASCII 编码,当需要使用整数类型的值时,可以将字符通过对应的 ASCII 遍码转换为整数,'0’的 ASCII 编码为 48,所以int b[‘0’]等价于int b[48]
7、在 C++语言中,数组被定义时,它的大小就确定了。
正确答案:正确
在C++中,数组的大小在定义时就被确定了,并且之后不能改变。
8、计算机中存储的数据都是二进制形式。因此,在使用C++语言编写程序时,将所有十进制数改写为相同数值的二进制数,会使得程序运行效率更高。
正确答案:错误
无论编写程序时使用十进制还是二进制,编译器都会翻译为二进制机器指令运行,所以运行效率是一样的。
9、在 C++语言中,表达式(0xf == 015)的值为 true。
正确答案:错误
0xf 是 16 进制下的f,等于10 进制的 15;015 是 8 进制下的 15,等于 10 进制的 13。
10、如果 a 为 int 类型的变量,且表达式((a | 3) == 3)的值为true,则说明a 在从0到 3 之间(可能为 0、可能为 3)。
正确答案:正确
(a | 3) == 3说明 a 只在二进制的最低位和第二低位可能为 1,所以 0 ≤ a ≤ 3,所以本题正确。
编程题 (每题 25 分,共 50 分)
春游
【问题描述】
老师带领同学们春游。已知班上有N位同学,每位同学有从0 到N−1的唯一编号。到了集合时间,老师确认是否所有同学都到达了集合地点,就让同学们报出自己的编号。到达的同学都会报出的编号,不会报出别人的编号,但有的同学很顽皮,会多次报出。你能帮老师找出有哪些同学没有到达吗?
【输入描述】
输入包含 2 行。第一行包含两个整数N和M,表示班级有N位同学,同学们共有M次报出编号。约定 2 ≤ N, M ≤ 1000。
第二行包含M个整数,分别为M次报出的编号。约定所有编号都在合理范围内。
【输出描述】
输出一行。如果所有同学都到达,则输出N;否则由小到大输出所有未到达的同学编号,空格分隔。
【样例输入 1】
3 3
0 2 1
【样例输出 1】
3
【样例输入 2】
3 5
0 0 0 0 0
【样例输出 2】
1 2
【解题思路】
1、使用 arrive 数组来记录每个同学是否到达,初始为false,表示没有到达。
2、每有一个同学报出编号,就将 arrive 数组对应的编号改为true。
3、遍历 arrive 数组,将数组中对应位置为 false 的下标输出并特判所有人均到达的情况。
【考纲知识点】循环结构(一级),模拟法、一维数组(三级)__
#include <iostream>
using namespace std;
bool arrive[1000];
int main(){
int n = 0, m = 0;
cin >> n >> m;
// 初始化 arrive 数组为所有同学均未报到
for (int i = 0; i < n; i++)
arrive[i] = false;
// 依次报到 m 次
for (int i = 0; i < m; i++) {
int code = 0;
cin >> code;
arrive[code] = true;
}
// 依次检查 n 位同学是否到达
bool all = true;
for (int i = 0; i < n; i++) {
if (!arrive[i]) {
if (all) {
cout << i;
all = false;
} else {
cout << " " << i;
}
}
}
// 处理全部到达的特殊情况
if (all)
cout << n;
cout << endl;
return 0;
}
密码合规检测
【问题描述】
网站注册需要有用户名和密码,编写程序以检查用户输入密码的有效性。合规的密码应满足以下要求:
1、只能由 a-z 之间 26 个小写字母、A-Z 之间 26 个大写字母、0-9 之间10个数字以及!@#$四个特殊字符构成。
2、密码最短长度:6 个字符,密码最大长度:12 个字符。3、大写字母、小写字母和数字必须至少有其中两种,以及至少有四个特殊字符中的一个。
【输入描述】
输入一行不含空格的字符串。约定长度不超过 100。该字符串被英文逗号分隔为多段,作为多组被检测密码。
【输出描述】
输出若干行,每行输出一组合规的密码。
输出顺序以输入先后为序,即先输入则先输出。
【样例输入 1】
seHJ12!@,sjdkffH$123,sdf!@&12HDHa!,123&^YUhg@!
【样例输出 1】
seHJ12!@
sjdkffH$123
【样例解释 1】
输入被英文逗号分为了四组被检测密码:“seHJ12!@”、“sjdkffH$123”、“sdf!@&12HDHa!”、“123&^YUhg@!”。其中,“sdf!@&12HDHa!”长度超过12 个字符,不合规;“123&^YUhg@!”包含四个特殊字符之外的字符 “^”,不合规。
【样例输入 2】
2000 2004
【样例输出 2】
2
【解题思路】
1、首先遍历输入的字符串 line 并按照’,'进行分隔。
2、对于分隔出来的每一个密码,先判断密码长度是否符合要求,然后遍历所有的字符,并用 hasC,hasL,hasD,hasS 分别记录是否存在大写字母,小写字母,数字以及特殊字符,若存在以上四种字符外的其它字符则直接返回非法。
3、判断是否存在特殊字符,若不存在返回非法。
4、判断是否存在两种及以上的大写字母、小写字母和数字,若不存在返回非法。
5、以上情况都存在,返回合法并输出。
【考纲知识点】多层分支/循环结构(二级),模拟法、字符串(三级)__
#include <iostream>
using namespace std;
char line[101];
char pwd[101];
// 检查从 str 开始、长度为 l 的密码是否合规
bool check(char * str, int l) {
if (l < 6 || l > 12)
return false;
bool hasC = false, hasL = false, hasD = false, hasS = false;
for (int i = 0; str[i] != '\0'; i++) {
if ('A' <= str[i] && str[i] <= 'Z') {
hasC = true;
} else if ('a' <= str[i] && str[i] <= 'z') {
hasL = true;
} else if ('0' <= str[i] && str[i] <= '9') {
hasD = true;
} else if (str[i] == '!' || str[i] == '@' ||
str[i] == '#' || str[i] == '$') {
hasS = true;
} else
return false;
}
if (!hasS)
return false;
if (hasC + hasL + hasD < 2)
return false;
return true;
}
int main() {
cin >> line;
// 按逗号对输入进行切分,并依次判断
int len = 0;
for (int i = 0; line[i] != '\0'; i++) {
if (line[i] != ',') {
pwd[len] = line[i];
len++;
} else {
pwd[len] = '\0';
if (check(pwd, len))
cout << pwd << endl;
len = 0;
}
}
if (len > 0) {
pwd[len] = '\0';
if (check(pwd, len))
cout << pwd << endl;
}
return 0;
}