CCF-GESP 等级考试 2026年3月认证C++三级真题解析

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

第1题 如果字符变量 _1 的值是字符 1 ,那么 (int)_1 的值是?( )。

A. 1 B. -1 C. 49 D. +1 或者 -1

解析:答案C。字符类型变量存储的是字符对应的ASCII码值,字符1的ASCII码是49,转换为int时值为49,因此(int)_1 的值是49。故选C。

第2题 a,b是整型变量,各自有互不相同的初始值。下列程序实现了什么效果( )。

cpp 复制代码
a=a^b;
b=a^b;
a=a^b;

A. a,b 的值从始至终都没有改变。 B. a,b 的值实现了互换。

C. a,b 的值互换了以后,又还回去了,相当于没有变化。

D. a,b 的值最后和原值不一样,没有任何意义。

解析:答案B。知识点:异或(^)运算,某数异或同一数二次,则恢复原数。设a、m是两个不同的整形变量,则a^m^m==a成立。经第一行运算a成为原a与原b的异或结果,经第二行运算,b相当于是原a^原b^原b=原a,经第三行运算a相当于是原a^原b^原a=原b,实现了a与b的交换。故选C。

第3题 关于下列正确的程序段,说法正确的是( )。

cpp 复制代码
char str1[] = "Hello";
char str2[] ={'H','e','l','l','0'};

A. 字符数组 str1 和 str2 完全相同。

B.

cpp 复制代码
cout<<str1<<endl;
cout<<str2<<endl;

这段程序将输出不同的结果。

C. 字符数组 str1 和 str2 不相等。 D. 这两个赋值方式完全相同。

解析:答案C。‌str1‌ 的定义为:char str1[] = "Hello";,在 C++ 中,字符串字面量 "Hello" 实际上会自动在末尾添加一个空字符 '\0',因此 str1 实际上是 {'H','e','l','l','o','\0'},共 6 个字符,str1为字符串。‌str2‌ 的定义为:char str2[] = {'H','e','l','l','0'}; ,这里显式地定义了 5 个字符,没有自动添加 '\0'。所以 str2 是 {'H','e','l','l','0'},共 5 个字符。

选项‌A由于两个数组的长度不同,内容也不完全一致(str1有'\0'而str2没有),因此它们不相等,所以错误。选项‌B,cout << str1 << endl; 会正常打印 "Hello",而 str2 因为没有 '\0',其行为未定义,会打印到内存中出现的第一个'\0'为止,因此可能输出乱码或异常结果。但题目中未明确说明输出方式,因此不能确定是否"输出不同"。选项C正确。选项‌D字符串字面量赋值会自动添加 '\0',而字符数组初始化不会自动添加,所以错误。故选C。

第4题 关于以下程序段,说法正确的是( )。

cpp 复制代码
int x=10;
cout<<(x++) + (++x)<<endl;

A. C++11 标准中,这是未定义行为,不同的环境有可能出现不同的结果

B. 22 C. 21 D. 20

解析:答案B。知识点:后缀递增操作符(x++):表达式的值:表达式x++的值是变量x递增前的值,变量x在表达式求值之后递增1。前缀递增操作符(++x):表达式的值:表达式++x的值是变量x递增后的值,变量x在表达式求值之前递增1。+运算符是从左向右运算,(x++)的值为10,x=11,(++x)的值为12,x=12,所以(x++) + (++x)=10+12=22,所以输出结果为22。故选B。

第5题 8 位二进制下,十进制数-15 的补码是( )。

A. 11110000 B. 10001111 C. 10010000 D. 11110001

解析:答案D。知识点:二进制表示十进制,二进制最高位表示符号:0正1负,其他位表示数值。正数补码与原码相同,负数补码‌符号位保持不变,原码数值位按位取反后加1。-15=(10001111)₂原=(11110001)₂补,与项目D一致。故选D。

第6题 三进制数2102₍₃₎转换成十进制是:( )。

A. 63 B. 65 C. 67 D. 69

解析:答案B。2*3³+1*3²+0*3¹+2*3⁰=54+9+0+2=65,项目B正确。故选B。

第7题 二进制数 10110101 是某数的 8 位补码,该数的十进制是( )。

A. -73 B. -75 C. -77 D. 75

解析:答案D。高位为1,数据为负,0110101减1取反(或取反+1)为(1001011)₂=75,所以,该数的十进制是-75。故选D。

第8题 已知 unsigned char c = 0x0F; (十六进制 0F = 二进制 00001111 ),执行 c = c << 3; 后,c 的 十进制值是:( )。

A. 64 B. 72 C. 80 D. 120

解析:答案D。赋值从右向左运算,C++/C中<<为多位运算(左移),如数据没有溢出,则m<<n=m*2ⁿ,0x0F=15,15*2³=120,所以D正确。也可以这么思考:0x0F表示十六进制数,十六进制(0F)₁₆=(00001111)₂,左移3位结果为(01111000)₂=120。故选D。

第9题 补码的情况下,关于按位取反运算,用笔计算的情况下,以下说法错误的是:( )

A. ~5 的结果是 -6( int 类型,32 位) B. ~0 的结果是 0( int 类型,32 位)

C. ~(-3) 的结果是 2( int 类型,32 位) D. ~8 的结果是 -9( int 类型,32 位)

解析:答案B。~按位取反,即将表示数据的二进制简单地每一位取反。

选项A:~5=~(00000000 000000000 00000000 00000101)₂=(11111111 11111111 11111111 11111010)₂=-(00000000 000000000 00000000 00000110)₂=-6,正确。

选项B:~0=~(00000000 000000000 00000000 00000000)₂=(11111111 11111111 11111111 11111111)₂=-(0000000 00000000 00000000 00000001)₂=-1≠0,错误。

选项C:~(-3)=~(11111111 11111111 11111111 11111101)₂=(00000000 00000000 00000000 00000010)₂=2,正确。

选项D:~8=~(00000000 00000000 00000000 00001000)₂=(11111111 11111111 11111111 11110111)₂=-(0000000 00000000 00000000 00001001)₂=-9,正确。

故选B。

赋值从右向左运算,C++/C中<<为多位运算(左移),如数据没有溢出,则m<<n=m*2ⁿ,0x0F=15,15*2³=120,所以D正确。也可以这么思考:0x0F表示十六进制数,十六进制(0F)₁₆=(00001111)₂,左移3位结果为(01111000)₂=120。故选D。

第10题 执行以下 C++ 代码后, sub 的值是( )。

cpp 复制代码
string str = "GESP2026";
string sub = str.substr(4, 2);

A. 20 B. 02 C. 2026 D. 026

解析:答案A。C++的substr()为取子串方法,C++字符串中字符位置从左向右,位置编号从0开始,str.substr(m, n)表示从字符串str的m位开始取n位子串。str.substr(4, 2)="20",故选 A。

第11题 执行以下代码后,输出结果是:( )。

cpp 复制代码
int arr[] = {5, 10, 15, 20, 25, 30};
int count = sizeof(arr) / sizeof(arr[0]);
cout << count;

A. 4 B. 6 C. 24 D. 30

解析:答案B。第一行定义了一个整型数组,初始6个元素,在C++中,sizeof是一个‌编译期运算符‌,用于获取数据类型或对象在内存中所占的‌字节数,int类型占4字节,sizeof(arr) = 4 * 6 = 24,sizeof(arr[0]) = 4,所以count = 24 / 4 = 6。故选 B。

第12题 执行以下代码后,输出结果是:( )。

cpp 复制代码
char s[10] = "abcde";
int a = sizeof(s) / sizeof(s[0]);
int b = strlen(s);
cout << a - b;

A. 4 B. 5 C. 6 D. 10

解析:答案B。char类型占1字节,char数组一个下标占1字节。第一行定义一个C风格字符串,尾部会自动添加字符串结束标志'\0',所以存了6个字符,另4个下标(元素)自动初始化为ASCII码0(即'\0'),所以sizeof(s)=10,sizeof(a[0]) = 1,所以a = 10 / 1 = 10。strlen()函数为求字符串的实际长度,不包含尾部的'\0',所以b= strlen(s)=5,a-b=10-5=5。故选 B。

第13题 以下问题中,最不适合用枚举法解决的是:( )

A. 找出 1~100 之间所有能被 7 整除的数

B. 找出 100~200 之间的所有质数

C. 计算 1+2+3+...+1000 的和

D. 找出三位数中个位、十位、百位数字之和等于 10 的数

解析:答案C。枚举法是指从可能的集合中一一枚举各个元素,用题目给定的约束条件判定哪些是无用的,哪些是有用的。能使命题成立者,即为问题的解。特征是①枚举每一个可能元素,②计算约束条件是否使命题成立。

对选项A,枚举从1到100的数,计算这个数能否被7整除?如能被7整除,则找到此数,输出该数,继续找直到数超范围,符合枚举法特征,适合枚举法。

对选项B,枚举从100到200的数,计算这个数是否是质数?如是质数,则找到质数,输出该质数,继续找质数直到数超范围,符合枚举法特征,适合枚举法。

对选项C,枚举从1到1000的数,计算这个数与前数和的和,无判断,继续枚举直到数超范围,有点像枚举法,但不完全符合枚举法特征,不适合枚举法。

对选项D,枚举所有三位数,从100到999,计算这个数的个位、十位、百位数字之和,判断是否等于10?如等于10,则输出该数,继续找直到数超范围,符合枚举法特征,适合枚举法。

所以选项C最不适合用枚举法解决问题。故选 C。

第14题 用枚举法解决"鸡兔同笼问题:头共 35 个,脚共 94 只,求鸡和兔的数量",以下枚举逻辑最合理的是:( )

A. 枚举鸡的数量 x (0~35),兔的数量 y=35-x ,判断 2*x + 4*y == 94

B. 枚举兔的数量 y (0~94),鸡的数量 x=35-y ,判断 2*x + 4*y == 94

C. 枚举所有整数 x (0-100)和 y (0-100),判断 x+y==35 && 2*x+4*y==94

D. 枚举脚的总数 sum (0~94),判断 sum == 94

解析:答案A。分析:鸡、兔都只有1个,所以鸡数+兔数=头数,设鸡数x,兔数为y,则如枚举x(0~35),则兔数=头数-鸡数,即y=35-x。鸡只有2只脚,兔有4只脚,如2*x+4*y=94(脚数),就找到其中的一个问题解(可能有多个答案)。

所以选项A正确。

选项B,枚举兔数y,但y的范围也是0~35,而不是脚数0~94,所以错误。

选项C,x、y都超范围枚举,但也能得到结果,不是最佳方法,所以不太正确。

选项D,枚举脚数,判断脚数sum == 94,无法获得鸡数和兔数,所以错误。

故选 A。

第15题 模拟"字符串加密":规则为"每个字符 ASCII 码 + 3,若超过 z (122) 则从 a 重新开始",以下代码中正确的条件判断是:( )

cpp 复制代码
for (int i = 0; i < str.length(); i++) {
    // 需补充条件:
    _______________________
    else {
        str[i] += 3;
    }
}

A. if (str[i]> 122) str[i] = str[i] + 3 - 26;

B. if (str[i] > 122) str[i] = str[i] - 26;

C. if (str[i] + 3 > 122) str[i] = str[i] - 23;

D. if (str[i] + 3 > 'z') str[i] = 'a' + (str[i] + 3 - 'z') - 1;

解析:答案D。这里假设字符串中为小写字母,知识点:'a'=97,'z'=122。'a' + 3 - 'z' - 1=-23,'a' + (str[i] + 3 - 'z') - 1与str[i] - 23等价,122与'z'等价。

选项A用原字符串元素str[i]去判>122,str[i] + 3至少等于125不会减26,所以错误。

选项B,用原字符串元素str[i]去判>122,不符合"每个字符 ASCII 码 + 3,若超过 z (122) 则从 a 重新开始",所以错误。

选项C,if (str[i] + 3 > 122) str[i] = str[i] - 23; 符合题目要求,答案也正确,但这里直接减23并不能直观反映题目要求的加密规则,所以不太直观、规范。

选项D,if (str[i] + 3 > 'z') str[i] = 'a' + (str[i] + 3 - 'z') - 1; 正确且字符比较的方式,更加直观和准确地实现了题目要求的加密规则,所以正确。

故选 D。

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

第1题 定义 int arr[5] = {1,2,3}; ,则 arr[3] 的值为 0,arr[5] 是合法下标。

解析:答案错误(╳)。在 C++ 中,用int arr[5] = {1,2,3}; 初始化数组,未初始化的为0,所以arr[3] 的值为 0正确。但arr[5]表示有5个下标(元素),下标编号为0、1、2、3、4,arr[5]已越界,是不合法下标。故错误。

第2题 定义 double arr[10]; ,未手动初始化时,数组中所有元素的默认值为 0.0。

解析:答案错误(╳)。在 C++ 中,未初始化的数组元素默认值取决于数组存储的位置。对于在栈区声明的 double arr[10];,其元素值是未定义的(即随机垃圾值)。而全局或静态数组的元素默认值才是 0.0。故错误。

第3题 定义 int arr[] = {1,2,3}; ,则 sizeof(arr) 的结果为 12( int 占 4 字节)。

解析:答案正确(√)。C++中int arr[] = {1,2,3}定义了三个整型元素的数组,sizeof(arr)为arr占用内存字节数,即4*3=12,故正确。

第4题 下面的流程图是用来求 1+2+3+...+10 的和。请判断:这个流程图的逻辑正确还是错误?

解析:答案正确(√)。Sum初始值为0,i从1开始,条件框中条件i<=10,条件成立sum加i,i每次加1,这样10次循环,sum从0开始,分别加1、2、...、9、10,所以流程图是用来求 1+2+3+...+10 的和,这个流程图的逻辑正确,故正确。

第5题 下面流程图的功能是计算 5 对 2 取余数,输出结果为 1。

解析:答案正确(√)。A被减去多个b,直到小于a,其实就是计算a对b的余数。

a=5, b=2;第一轮a≥b即5≥2成立,a=a-b=5-2=3;第二轮a≥b即3≥2成立,a=a-b=3-2=1;第三轮a≥b即1≥2不成立,输出a即1。故正确。

第6题 已知大写字符 A 的ASCII编码的十六进制表示为 0x41 ,计算字符 m 的ASCII编码的八进制表示为 155(八进制)。

解析:答案正确(√)。大写字符A的ASCII编码的十六进制表示为0x41,则大写字符a的ASCII编码的十六进制表示为 0x61(相差32即0x20),a(第1)与m(第13)差12(0xC)个字母,所以字符m的ASCII编码的十六进制表示为0x61+0xC=0x6D=0b 0110 1101(4位一组)=0b 01 101 101(3位一级)=0o155。所以字符m的ASCII编码的八进制表示为155,故正确。

第7题 在 C++ 位运算中,各种不同的运算符有优先级的区分,使用括号能够解决优先级的问题。

解析:答案正确(√)。在 C++ 中,位运算符和其他运算符一样,具有明确的‌优先级 ‌和‌结合性 ‌。当表达式中包含多个不同优先级的运算符时,编译器会根据优先级规则来确定运算顺序。如果希望改变这种默认的运算顺序,可以使用‌圆括号 ‌来明确指定优先计算的部分。故正确。

第8题 由于在 0~255 范围内, char 类型和 int 类型可以互换,因此在这里 x 和 y 相等。

cpp 复制代码
char x='1';
int y=1;

解析:答案错误(╳)。在 C++ 中,char为字符型,存储的是字符的ASCII码,int为整型,存储的是数字本身(正数高位为0,负数高位来1,数值用补码表示),所以char x='1'; x的值为49,int y=1; y的值为1,所以x和y不相等。故错误。

第9题 在C++语言中,表达式 ((0xf0 + 0x15) == 255) 的值为 true 。

解析:答案错误(╳)。在 C++ 中,(0xf0 + 0x15)=0x105d≠0xff(255),所以表达式 ((0xf0 + 0x15) == 255) 的值为false。故错误。

第10题 如果 a 为 int 类型的变量,且 a 的二进制最低位为 0 ,则表达式 ((a & 3 & 1) == 0) 的值为 true 。

解析:答案正确(√)。C++中&为按位与,任何二进制位与0为0,与1为原值(此位为0则为0,此位为1则为1)。设a的二进制形式为xxx...xxxx0,其中的x表示不定 二进制位(0或1),...表示省略其中的位(C++ int 类型变量共32位二进制)‌,则:

a: xxx...xxxx0

a & 3: xxx...xxxx0 & 00...00011=000...000x0

((a & 3 & 1):000...000x0 & 000...00001=000...00000=0

所以题目表述成立。故正确。

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

3.1 编程题1
  • 试题名称:二进制回文串
  • 时间限制:1.0 s
  • 内存限制:512.0 MB

3.1.1题目描述

对于一个正整数𝑛,我们将其转换为不含前导零的二进制表示,如果这个二进制序列从左向右读与从右向左读完全相同,则称该数为二进制回文数。例如,9的二进制表示为(1001)₂,是二进制回文数;12的二进制表示为(1100)₂,不是二进制回文数。

你的任务是:给定一个正整数𝑛,计算在1到𝑛的范围内二进制回文数的数量。

3.1.2 输入格式

输入一行,包含一个正整数𝑛。

3.1.3 输出格式

输出一行,包含一个数,表示在1到𝑛的范围内二进制回文数的数量。

3.1.4 样例

3.1.4.1 输入样例

cpp 复制代码
15

3.1.4.2 输出样例

cpp 复制代码
6

3.1.5 样例解释

样例1中,1到𝑛范围内1、3、5、7 、9、15是二进制回文数。

3.1.6 数据范围

1≤𝑛≤10⁵。

3.1.7 编写程序

解析:本题解决二个问题:一是十进制转二进制问题,二是二进制回文检测问题。

思路:问题一:用除2取余法转二进制,每位余数存入数组,商继续用除2取余法,直到商为0。因为2¹⁶=65536,2¹⁷=131072>10⁵,所以10⁵的十进制数,二进制不超过17位,数组的长度(元素个数 )为17,留点余量可定义为20。

问题二:设转换后的二进制长度为j位,不论j是奇数还是偶数,都只需判j/2位就可以确定是否是回文。

当j是奇数时,以j=9为例,j/2=4:

只需判断4对数是否相等,如有一对数不相等就不是回文,否则全部相等就是回文。中间一位只是一位,不管是0还是1都不影响对回文的判断。

当j是时数时,以j=10为例,j/2=5:

只需判断5对数是否相等,全部相等就是回文,否则如有一对数不相等就不是回文。

根据二个问题的解决方案编写的参考代码如下:

cpp 复制代码
#include <iostream>
using namespace std;

int main() {
      int n, bin[20] = {0}, cnt = 0; // 1≤n≤10⁵, bin存二进制位,cnt计数值
      cin >> n;                      // 10⁵化为二进制最多17位,加点余量
      for (int i = 1; i <= n; i++) { // 枚举1~n
           int tmp = i, j = 0, k;     // 将tmp(即i)转换为二进制(存入字符数组)
           while (tmp) {
                 bin[j++] = tmp % 2;    // j累计二进制位数,tmp % 2为除2取余法
                 tmp /= 2;              // 余数存入数组bin,商继续运算直到为0
           }
           for (k = 0; k < j / 2; k++)
                 if (bin[k] != bin[j - k - 1]) // bin[j-k-1]从右向左读
                      break;      // 从左向右读与从右向左读不相等,则不是回文
           if (k == j / 2) cnt++; // 如没有中途跳出而正常结束循环,则是回文,+1
      }
      cout << cnt << endl;
      return 0;
}
3.2 编程题2
  • 试题名称:凯撒密码
  • 时间限制:1.0 s
  • 内存限制:512.0 MB

3.2.1题目描述

凯撒密码是一种替换加密技术,明文中的所有字母都在字母表上向后(或向前)按照一个固定数目进行偏移后被替换成密文。例如,当偏移量是3的时候,所有的字母𝐴将被替换成𝐷,𝐵被替换成𝐸,𝐶被替换成𝐹,以此类推,𝑊被替换成𝑍,𝑋被替换成𝐴,𝑌被替换成𝐵,𝑍被替换成𝐶。这个加密方法是以罗马共和时期凯撒的名字命名的,据称当年凯撒曾用此方法与其将军们进行联系。

但是和所有的利用字母表进行替换的加密技术一样,凯撒密码非常容易被破解,而且在实际应用中也无法保证通信安全。

现在给你一个已破解的凯撒密码明文与密文,与一个有相同偏移量的未破解凯撒密码密文,请你帮忙破解它。

3.2.2 输入格式

输入共三行:

第一行包含一个字符串,表示已破解的凯撒密码明文;

第二行包含一个字符串,表示已破解的凯撒密码密文;

第三行包含一个字符串,表示待破解的凯撒密码密文。

3.2.3 输出格式

输出一行,包含一个字符串,表示待破解的凯撒密码对应的明文。

3.2.4 样例

3.2.4.1 输入样例

cpp 复制代码
ABCDEFGVWXYZ
DEFGHIJYZABC
WKHTXLFNEURZQIRAMXPSVRYHUWKHODCBGRJ

3.2.4.2 输出样例

cpp 复制代码
THEQUICKBROWNFOXJUMPSOVERTHELAZYDOG

3.2.5 样例解释

样例 1 中,通过已破解的密码得出偏移量为 'D' - 'A' = 3 ,因此,对未破解部分进行逆向偏移:密文中的 W 对 应明文中的 T ( 'W' - 3 = 'T' ),密文中的 K 对应明文中的 H ( 'K' - 3 = 'H' ),以此类推。

3.2.6 数据范围

保证密码长度均不超过1000,所有字符串由大写字母组成。

3.2.7 编写程序

解析:本题是一个已知明文和密文破解新密文的题目,需要先破解密钥,然后用密钥破解密文。

思路:对凯撒密码密钥key为常数,只需计算密文与明文对应位置上字母间的距离(ASCII码之差),负数也不影响结果,key=3和key=-23等价。

设pt为明文字符串,ct为密文字符串,则key=ct[0]-pt[0]。

设ut为待解密文,解密为(ut[i]-'A'-key+26)%26+'A'。

加+26的目的是防止ut[i]-'A'-key为负数,+26不影响%26的结果(同余)。

方法一:

按此思路用C风格字符串编写的参考代码如下:

cpp 复制代码
#include <iostream>
#include <cstring>
using namespace std;

char pt[1005], ct[1005], ut[1005]; // 密文长度均不超过1000, 1005留点余量

int main() {
    cin >> pt >> ct >> ut;    // 输入明文、对应密文和待破解密文
    int n = strlen(ut);       // C风格字符串求字符串长度函数
    int key = ct[0] - pt[0];  // key正负不影响解密,故不调整
    for (int i = 0; i < n; i++)
        cout << (char)((ut[i] - 'A' - key + 26) % 26 + 'A'); // 结果为数值强制转换
    return 0;
}

方法二:

按此思路用C++字符串编写。对C++字符串string类型,32位系统 :通常为2³²-1(约4GB);64位系统:可能为2⁶⁴-1(理论值极大,但实际受内存限制),故存储1000字符没有问题。

参考代码如下:

cpp 复制代码
#include <iostream>
using namespace std;

string pt, ct, ut; // C++字符串超长,一般不小于2³²-1个字符

int main() {
      cin >> pt >> ct >> ut;    // 输入明文、对应密文和待破解密文
      int key = ct[0] - pt[0];  // key正负不影响解密,故不调整
      for (int i = 0; i < ut.length(); i++) // length()为C++测字符串长度方法
           cout << (char)((ut[i] - 'A' - key + 26) % 26 + 'A'); // 结果为数值强制转换
      return 0;
}
相关推荐
x_xbx2 小时前
LeetCode:1. 两数之和
数据结构·算法·leetcode
x_xbx2 小时前
LeetCode:49. 字母异位词分组
算法·leetcode·职场和发展
玲娜贝儿--努力学习买大鸡腿版2 小时前
hot 100 刷题记录(1)
数据结构·python·算法
123过去2 小时前
pixiewps使用教程
linux·网络·测试工具·算法·哈希算法
kyle~2 小时前
C++----函数指针与函数指针类型 返回值类型 (*类型名)(参数列表)
开发语言·c++
深圳市快瞳科技有限公司3 小时前
低空经济下,鸟类识别算法与无人机硬件的兼容性优化策略
算法·无人机
努力中的编程者3 小时前
二叉树(C语言底层实现)
c语言·开发语言·数据结构·c++·算法
鹤旗3 小时前
While语句,do-while语句,for语句
java·jvm·算法
qq_416018723 小时前
高性能密码学库
开发语言·c++·算法