int a[5] = {10, 20, 30, 40, 50};,则 a[1] 的值是( )。
考点:下标从 0 开始(A1)。
(A1)考点:C++ 数组下标从 开始:a[0] 是第一个元素,a[1] 是第二个元素。
解析:五个元素 里, 排在第二位,下标是 ;"第几个"和"下标"差一,是数组最高频的口径坑。
排除法:选 的人把 a[1] 当成第一个元素;选 的人把下标当成了存的值;选 的人数到了第三位。
阅读程序:
01int a[5] = {1, 2, 3}; 02cout << a[3];
程序的输出是( )。
考点:声明与整体初始化(A2)。
(A2)考点:用列表初始化数组时,没给初值的位置自动补 :{1,2,3} 初始化长度 的数组,后两位是 ,a[3] 为 。
解析:这条"缺省补零"只对带初始化列表的声明生效;什么都不写(如 int a[5]; 局部声明)不会补零——那是 A3 的坑。
排除法:选 的人以为只有前三个有效;选随机值的人混淆了"局部未初始化"(A3);选 的人看错了位置。
在函数内声明 int a[100]; 后不做任何初始化就立刻输出 a[0],结果是( )。
考点:局部数组未初始化是随机值(A3)。
(A3)考点:函数内 int a[100]; 不初始化,内容是不确定的(编译器不清理,读到的是内存里残留的值)。
解析:安全做法是声明即初始化(= {} 全清零)或逐个赋值再使用;"能跑出结果"不代表结果正确。
排除法:选 的人把它当成了全局数组(A10 才默认清零);选 的人臆造了默认值;选"编译报错"的人——未初始化是合法的,错在使用未定义的值。
int a[10];,程序中访问 a[10]。下列说法正确的是( )。
考点:越界访问是未定义行为(A4)。
(A4)考点:a[10] 越界访问是未定义行为:编译器不检查、不报错,运行时可能读出垃圾值、可能恰好正常、可能崩溃——一切皆有可能。
解析:C++ 为了速度不做下标检查;a[N] 型错误要靠自己守边界(循环条件 < 长度),G 组专门练习各种越界形态。
排除法:选"编译器会报错"的人把 C++ 当成了带边界检查的语言;选"自动返回 "的人臆造了行为;选"一定立刻崩溃"的人——未定义行为的可怕正在于它不一定立刻崩,错误可能潜伏到别处爆发。
数组 int a[N] 合法的下标范围是( )。
考点:最大下标与长度差一(A5)。
(A5)考点:长度为 的数组,合法下标范围是 。
解析:数元素从 数、写下标从 起,两套口径差一;遍历写 i < N 恰好覆盖 个元素。
排除法:选 的人漏了 号、多了 号;选 的人多了 号(正是 G1 的越界事故);选 的人两头都偏了。
阅读程序:
01int a[6] = {1, 2, 3, 4, 5, 6}; 02int s = 0; 03for (int i = 0; i < 6; ++i) 04 s += a[i]; 05cout << s;
程序的输出是( )。
考点:遍历求和(A6)。
(A6)考点:累加器初值为 ,循环扫一遍把每个元素加上:。
解析:s += a[i] 是数组最基础的动作;循环变量从 到 (i < 6)恰好六个元素各加一次。
排除法:选 的人漏加了某个元素(常漏第一个或最后一个);选 的人只加了前五个;选 的人把元素个数当成了和。
数组 a = {5, 9, 2, 9, 7}(下标从 起)。下面的程序执行后 mx 是( )。
01int mx = a[0]; 02for (int i = 1; i < 5; ++i) 03 if (a[i] > mx) mx = a[i];
考点:找最值(A7)。
(A7)考点:打擂台求最大值:mx 初值取 a[0],逐个与擂主比较、更大者上位—— 是最大值。
解析:两个 都比 大,第二个 与擂主相等不满足严格大于,擂主保持 不变。
排除法:选 的人找成了最小值;选 的人没让循环跑起来(只用了初值);选 的人比错了方向。
求数组最大值时把 mx 初始化为 (而不是 a[0])。当数组所有元素都是负数(如 -3, -1, -7)时,结果是( )。
考点:最值初值取首元素(A8)。
(A8)考点:全负数组求最大值时,初值 比所有元素都大,"比 大"的条件永不成立,最大值被误判为 ——初值必须取 a[0](或理论极小值)。
解析: 谁也大不过 ,更新一次都不触发;这就是"初值取首元素"这条惯例的由来。
排除法:选 的人以为程序仍正确;选 的人算成了最小值;选"死循环"的人——循环照常结束,只是结果错。
阅读程序:
01int a[5] = {4, 0, 3, 1, 2}; 02cout << a[a[0]];
程序的输出是( )。
考点:下标即数据(A9)。
(A9)考点:数组元素可以再当下标:a[0] 是 ,所以 a[a[0]] 就是 a[4],值是 。
解析:从里往外算——先算出 a[0] = 4,再取 a[4];"值当下标"是桶计数、位置数组等惯用法的地基。
排除法:选 的人只算了里层就停;选 的人算成了 a[0] 的邻居;选 的人把两层下标混在一起。
全局声明 int g[100];(在所有函数之外),未写初始化。g[50] 的值是( )。
考点:全局数组默认清零(A10)。
(A10)考点:全局数组(定义在所有函数外)不写初始化也自动全 ;局部数组没有这个待遇(A3)。
解析:全局区(静态存储区)在程序启动时清零,局部区(栈)不清;竞赛里"开全局大数组"的习惯正因此省事又安全。
排除法:选随机值的人把全局当局部;选 的人臆造了默认值;选"编译报错"的人——不初始化是合法的。
关于 int a[n];(n 是运行时读入的变量),正确的说法是( )。
考点:数组长度须编译期常量(A11)。
(A11)考点:标准 C++ 要求数组长度是编译期常量;int a[n](n 运行时读入)是变长数组(VLA)扩展,超范围使用可能崩溃——应改用全局大数组或 vector。
解析:竞赛惯例"按数据范围上限开全局数组"或 vector<int> a(n),两者都合法且安全。
排除法:选"任何情况都不合法"的人——很多编译器确实支持 VLA 扩展;选"所有评测机行为一致"的人恰恰相反,VLA 是出了名的行为不一致;选"不超过 就绝对安全"的人,安全性取决于栈空间而非具体数字。
int a[8]; 在 main 函数内,sizeof(a) / sizeof(a[0]) 的值是( )。
考点:sizeof 求元素个数(A12)。
(A12)考点:sizeof(a) 是整个数组的字节数(),sizeof(a[0]) 是单个元素字节数(),相除得元素个数 。
解析:这是"数组自己知道自己多长"的唯一原生办法;但它只在数组本体可见处有效——传参后失效(A13)。
排除法:选 的人忘除了元素大小;选 的人只取了分母;选 的人把两个 sizeof 当成相等了。
阅读程序:
01void f(int b[]) { 02 cout << sizeof(b); 03} 04int main() { 05 int a[10]; 06 cout << sizeof(a) << " "; 07 f(a); 08}
在 int 占 字节、指针占 字节的机器上,输出是( )。
考点:数组传参后 sizeof 失效(A13)。
(A13)考点:数组传给函数时退化为指针:函数内的 sizeof(b) 是指针大小 ,不再是原数组的 字节。
解析:main 里 sizeof(a) = 10 × 4 = 40;进函数后只剩首地址——所以数组长度必须当参数一起传,这是 C++ 数组与后续 vector 的核心区别。
排除法:选 40 40 的人以为大小跟着传进去了;选 8 8 的人高估了 main 里的退化;选 40 4 的人把指针当成了 int。
阅读程序:
01int a[4] = {1, 2, 3, 4}; 02for (int i = 3; i >= 0; --i) 03 cout << a[i] << " ";
程序的输出是( )。
考点:倒序遍历输出(B1)。
(B1)考点:从最后一个下标()倒着循环到 ,输出 4 3 2 1。
解析:倒序遍历的三个要素:起点 、终点 (包含)、--i;数组本身没动,只是换个方向读。
排除法:选 1 2 3 4 的人忘了倒着走;选 4 3 2 1 0 的人把下标混进了输出;选 1 4 2 3 的人两头乱序。
把数组 a = {1, 2, 3, 4, 5} 原地反转(不用新数组)的写法是( )。
考点:原地反转(B2)。
(B2)考点:原地反转只交换对称的两端: 从 到 ,swap(a[i], a[n-1-i])—— 个元素只换 对,正中间不动。
解析:选项写 a[5-i] 的在 时就越界(下标 );选项边赋值边覆盖的会把前半段的值提前冲掉;"循环到 "更是重复交换回原样。
排除法:选 i < 5 全交换版的人交换了三对半——最后一对把自己换回去的同时已经越界;选单向赋值版的人丢了一半数据;选从 起版的人下标整体偏一且越界。
有序数组 a = {2, 4, 6, 8, 10}(长度 ),要删除下标 处的元素,应把( )。
考点:删除元素后段前移(B3)。
(B3)考点:删除下标 的元素:把 之后的元素依次前移一位(a[1]=a[2]、a[2]=a[3]、a[3]=a[4]),再把长度减一。
解析:数组的删除是"后面排队往前补位",代价是 次移动——这正是数组和链表的核心差异之一。
排除法:选"a[1]=0 即可"的人留了个洞,遍历会多出一个 ;选"前段后移"的人方向反了,会把前面的元素冲掉;选"只减长度"的人——数据还堆在前面,错位一位。
在长度为 的数组下标 处插入新元素 x(保持其余相对次序),正确的操作顺序是( )。
考点:插入元素后段后移(B4)。
(B4)考点:插入必须从最后往前逐位后移(腾出 位),最后放入新元素、长度加一。
解析:从后往前移保证不覆盖还没搬的元素;从前往后移会在第二步就把 a[p+1] 原值冲掉。
排除法:选"从前往后前移"的人既搞反了方向又搞反了目的;选"直接 a[p]=x"的人把原元素直接顶掉了;选"追加到末尾"的人没有保持插入位置。
有序数组 a = {1, 1, 2, 3, 3, 3, 5}()。用"保留段 + 双下标"去重:b[0]=a[0],对每个 a[i],若它与 b 的最后一个保留元素不同则存入 b。去重后 b 的长度是( )。
考点:有序数组相邻去重(B5)。
(B5)考点:有序数组里重复值必相邻——逐个与"保留段最后一个"比较,不同才保留: 去重得 ,长度 。
解析:有序是前提!无序数组的相同值不相邻,此法失效;这正是排序后去重一气呵成的原因。
排除法:选 的人没去重;选 的人把 的三次出现全删了(应保留一个);选 的人漏删了某个重复。
把升序数组 a = {1, 4, 6} 与 b = {2, 3, 5} 合并成升序数组 c(长度 )。合并后 c 是( )。
考点:合并两个有序数组(B6)。
(B6)考点:双下标各指两数组头部,每轮取较小者放入结果——两序列 、 归并得 。
解析: 取 ; 取 ;再 、、、 依次入列;这是归并排序的核心动作(2019 年完善程序真题同款思想)。
排除法:选 1 4 6 2 3 5 的人把拼接当成了归并;选 1 2 4 3 6 5 的人每轮比较后放错了位置;选倒序版的人方向反了。
个人围成圈,下标 。程序里从当前下标 i 前进一步(到下一个人)的写法是( )。
考点:环形下标取模(B7)。
(B7)考点:环形结构里"前进一格"用取模:i = (i + 1) % n——到 再前进回到 (2021 年 Josephus 真题的核心一行)。
解析:模 把 之外的值折回来;i+1 直接写会在末尾越界跳出环。
排除法:选 i+1 直加版的人在末尾越界;选除法版 (i+1)/n 只能得到 或 ;选 i%n+1 版的人先模后加, 会变 越界。
模拟约瑟夫问题时用 bool out[N] 记录每个人是否已出圈,这种"下标即编号、值为真假"的数组称为标记数组。判断某人还在圈内的条件是( )。
考点:标记数组(B8)。
(B8)考点:out[i] 为真表示 已出圈;判断"还在圈内"就是取反:!out[i](等价 out[i] == false)。
解析:标记数组把"某个编号是否有某种状态"变成 查询——约瑟夫、筛法、去重都靠它。
排除法:选 out[i] == true 的人把"已出圈"当成了"还在";选 out[i] > 0 的人 bool 比较(sizeof)虽同义但写法含混且若 out 是 int 会误判负值;选 out[i] == out[0] 的人——比较的是两个格子的相等,与状态无关。
阅读程序:
01int a[8] = {3, 1, 3, 2, 1, 3, 2, 1}; 02int cnt[4] = {0, 0, 0, 0}; 03for (int i = 0; i < 8; ++i) 04 cnt[a[i]]++; 05cout << cnt[3];
程序的输出是( )。
考点:桶计数频次(B9)。
(B9)考点:cnt[a[i]]++ 把"值 出现的次数"累进下标 的格子: 出现了 次,cnt[3] 是 (2019 年完善程序计数排序真题的核心动作)。
解析:数组 {3,1,3,2,1,3,2,1} 里 三次、 两次、 三次;桶下标与值一一对应。
排除法:选 的人把总元素数当成了频次;选 的人数的是别的桶;选 的人数的是 的频次(张冠李戴)。
把 cnt 数组按桶下标从小到大输出(值 v 重复 cnt[v] 次),即可把原数组排序。数组 {2, 0, 2, 0, 1}(值域 )按此方法输出的序列是( )。
考点:按桶序输出(B10)。
(B10)考点:从小到大扫桶、值 重复输出 cnt[v] 次,即完成排序: 输出 0 0 1 2 2。
解析: 有两桶、 一桶、 两桶;这就是计数排序的输出阶段——"值即下标"让顺序免费获得。
排除法:选原序 2 0 2 0 1 的人没做输出阶段;选 0 1 2 的人每桶只输出一次(去重不是排序);选倒序版的人扫桶方向反了。
阅读程序:
01int a[5] = {5, 9, 2, 9, 7}; 02int mx = a[0], pos = 0; 03for (int i = 1; i < 5; ++i) 04 if (a[i] > mx) { mx = a[i]; pos = i; } 05cout << pos;
程序的输出是( )(数组有两个 )。
考点:同时记录最值与位置(B11)。
(B11)考点:更新擂主时连位置一起换:mx 与 pos 同步更新。两个 中,第二个 不满足严格大于,擂主仍是下标 的第一个 。
解析:想要"最后一个最大值"就把 > 改成 >=——问哪个 由比较符号决定,这是本题埋的认知点。
排除法:选 的人用了 >= 语义(最后出现位置);选 的人输出成了最大值本身;选 的人没进过更新分支。
不借助 swap 函数,交换 a[i] 与 a[j] 的正确三步是( )。
考点:交换三次赋值(B12)。
(B12)考点:借助临时变量三步交换:先存 a[i],再用 a[j] 覆盖 a[i],最后把临时值还给 a[j]。
解析:顺序错了就丢数据:先 a[i]=a[j] 会把 a[i] 原值直接冲掉,两格变同一个值。
排除法:选两步直覆版的人两格变成同一个值;选第一步就赋错方向的两版顺序都冲掉了原值。
用一个数组和下标变量就能实现栈或队列:数组作存储区,下标变量指示操作位置。下列对应关系正确的是( )。
考点:数组实现栈与队列(B13)。
(B13)考点:栈=一个栈顶下标 top,进出都在 top 端(后进先出);队列=head、tail 两个下标,tail 进 head 出(先进先出)。
解析:数组是"存储池",下标变量是"规则执行者"——结构差异完全由下标怎么动体现(实现细节在栈与队列卷展开)。
排除法:选栈用头指针、队列用栈顶版的人把两套术语配反了;选"两者都必须两个下标"的人——栈一个下标就够;选"数组不能模拟队列"的人——两个下标即可,环形队列再配取模(B7)。
阅读程序:
01int a[5] = {2, 0, 3, 1, 2}; 02int p[4]; 03for (int i = 0; i < 5; ++i) 04 p[a[i]] = i; 05cout << p[2];
程序的输出是( )。
考点:值当下标反向映射(B14)。
(B14)考点:p[a[i]] = i 建立反向索引:"值 最后出现在哪"。 先出现在下标 、后出现在下标 ,后写覆盖前写,p[2] = 4。
解析:同一个值出现多次时,反向映射只保留最后一次写入——想保留第一次就得先判空再写。
排除法:选 的人以为存的是值本身;选 的人保留了第一次出现;选 的人数错了位置。
int g[3][4]; 定义的二维数组,正确的理解是( )。
考点:定义与行列含义(C1)。
(C1)考点:int g[3][4] 是 行 列、共 个元素的二维数组,g[r][c] 表示第 行第 列。
解析:第一个方括号是行数、第二个是列数;行列之争的判定法——g[i][j] 里第一个下标在"第几个大组"里移动。
排除法:选" 行 列(共 个元素)"的人行列看反;选"共 个元素"的人把行列相加当成了相乘;选"两个不相干的一维数组"的人否定了它连续存储的整体性。
阅读程序:
01int g[2][3] = {{1, 2}, {4}}; 02cout << g[0][2] << " " << g[1][1];
程序的输出是( )。
考点:初始化列表(C2)。
(C2)考点:二维初始化按行分组,组内缺的位置补 :{{1,2},{4}} 即 {{1,2,0},{4,0,0}},g[0][2] 与 g[1][1] 都是 。
解析:与一维"缺省补零"同源;每行一个花括号,行内不足自动补,整体输出 0 0。
排除法:选 2 4 的人以为不足位置"顺延填下一个初值";选随机值的人又混淆了未初始化;选 3 5 的人臆造了填充。
01for (int i = 0; i < 2; ++i) 02 for (int j = 0; j < 3; ++j) 03 cout << g[i][j] << " ";
若 g = {{1,2,3},{4,5,6}},输出是( )。
考点:双重循环遍历次序(C3)。
(C3)考点:外层行、内层列的遍历按行优先输出:先整行 $1~3$,再整行 $4~6$,得 1 2 3 4 5 6。
解析:外循环走一行、内循环走完一整行——若外层是列,输出变成 1 4 2 5 3 6(按列读)。
排除法:选 1 4 2 5 3 6 的人按列读了;选倒序版的人循环方向反了;选 1 2 4 5 6 3 的人内层没走完整行。
二维数组在内存里按行优先连续存放:g[0][0], g[0][1], g[0][2], g[1][0], ...。因此紧跟在 g[0][2] 后面的元素是( )。
考点:行优先内存布局(C4)。
(C4)考点:二维数组按行优先连续存放:第 行存完紧接着存第 行——紧跟 g[0][2](第 行末尾)的是 g[1][0]。
解析:内存里没有"行列",只有一条连续序列;g[i][j] 的实际地址 = 起点 + (i × 列数 + j) × 元素大小(C10 展开讲)。
排除法:选 g[0][3] 的人忘了行只有 列(下标 );选 g[2][0] 的人跳过了整段;选 g[1][2] 的人把"下一行的末尾"当成了紧邻。
int g[5][7];,数组元素的总个数是( )。
考点:二维元素个数(C5)。
(C5)考点:二维数组的元素总数 = 行数 × 列数 = 。
解析:开数组算容量用乘法;配合 sizeof 可写 sizeof(g)/sizeof(g[0][0]) 直接验证。
排除法:选 的人行列相加了;选 的人把 和 拼成了两位数;选 的人只数了行。
矩阵 g = {{1,2,3},{4,5,6},{7,8,9}},转置后(行列互换)g[1][2] 位置的值是( )。
考点:矩阵转置(C6)。
(C6)考点:转置即行列互换:新矩阵 T[i][j] = g[j][i]。T[1][2] = g[2][1] = 8。
解析:原矩阵第 行是 ,;转置后它来到 位置——"行列下标对调"即可互查。
排除法:选 的人算成了原位置的 g[1][2](没转置);选 的人把两个下标都用在了原矩阵上;选 的人取了对角线元素。
矩阵的主对角线(左上到右下)上的元素满足( )。
考点:主对角线(C7)。
(C7)考点: 矩阵主对角线(左上到右下)上的元素满足行下标 = 列下标(i == j)。
解析:从 走到 ,行列同步增长;求对角线和就一个循环 s += g[i][i]。
排除法:选"行列和为 "的人描述的是副对角线;选"行 = 列加 "的人描述的是紧贴对角线的斜线(行比列多 );选"行下标为 "的人描述的是第一行。
矩阵的副对角线(右上到左下)上的元素是( )。
考点:副对角线(C8)。
(C8)考点: 矩阵副对角线(右上到左下)满足 i + j == n-1,四个元素是 g[0][3], g[1][2], g[2][1], g[3][0]。
解析:行列一增一减、和恒为 ;四个位置一个不少——副对角线同样有 个元素。
排除法:选主对角线版的人找错了对角;选"共 个"的人少数了端点;选混合版的人位置凑错了。
要只访问 矩阵的最外圈元素(第 行、第 行、第 列、第 列),遍历条件应为(下标从 起)( )。
考点:边界一圈遍历(C9)。
(C9)考点:最外圈 = 第 行 或 第 行 或 第 列 或 第 列:四个条件用 || 连接。
解析:四个"或"覆盖四条边、角点被两个条件同时覆盖也只访问一次(循环里每个格子只判一次)。
排除法:选两条件版的人只圈住了两条边;选 && 连接版的人只命中左上角一个点;选 <= 版的人条件恒真,全矩阵都通过。
把二维数组传给函数 void f(int g[][10]),方括号里列数必须写、行数可以空着,原因是( )。
考点:二维传参必须给列数(C10)。
(C10)考点:函数里寻址 g[i][j] 需要"每行多少个元素"算偏移:地址 = 起点 + (i × 列数 + j) × 元素大小;行数不参与寻址所以可以空着。
解析:这就是 void f(int g[][10]) 里 必须写的原因——列数是编译器翻译下标的必要信息。
排除法:选"行数自动推断"的人——推断不了,也没人需要它;选"当成一维数组"的人参数类型就错了;选"只是书写习惯"的人把硬性语法当成了风格。
用 char map[8][8] 存 迷宫地图,地图第 行内容为 .#..#..#。则 map[2][1] 的值是( )。
考点:棋盘地图存字符(C11)。
(C11)考点:char map[R][C] 每格存一个字符;地图第 行(行下标 )".#..#..#" 的第 个字符(列下标 )是 '#'。
解析:字符矩阵是迷宫、棋盘类题的标准载体——行下标、列下标、字符内容三层信息分开数。
排除法:选 '.' 的人列下标数偏了;选 '3' 的人把行号当成了格子里存的字符;选 2(数字)的人——存的是字符 '#' 不是数字。
程序:
01for (int i = 1; i <= 3; ++i) { 02 for (int j = 1; j <= i; ++j) cout << '*'; 03 cout << '\n'; 04}
输出的图形是(从上到下每行的 * 个数依次是)( )。
考点:字符图形输出(C12)。
(C12)考点:外层控制行、内层控制每行星号个数:第 行打印 个 *,三行依次 。
解析:j <= i 让内层长度随行号增长;外层每行结束补换行——"行数、行长"两个变量分开控制是字符画的总纲。
排除法:选 的人内层条件写反(如 j >= i);选 的人内层与 无关;选 的人内层只跑一轮。
阅读程序:
01char c = 'A'; 02cout << c + 1;
程序的输出是( )。
考点:char 是小整数(D1)。
(D1)考点:字符参与算术时被提升为 int:'A' + 1 的值是 ,cout 按整数输出 66。
解析:想输出字符须转回来:cout << (char)(c + 1) 才打印 B——"算完变 int、要字符得转回"是字符运算第一律(D13 展开)。
排除法:选 B 的人以为结果还是 char;选 的人忘了加一;选 A1 的人把加法当成了字符串拼接。
阅读程序:
01char c = 'b'; 02c = c + 1; 03cout << c;
程序的输出是( )。
考点:字符加一(D2)。
(D2)考点:c = c + 1 先按整数算出 ,存回 char 变量时变回字符——输出 c。
解析:与 D1 的区别在"存回 char"这一步:赋值动作完成了 int→char 的回落,所以打印的是字母不是数字。
排除法:选 b 的人以为加法没生效;选 98 的人忽略了存回 char(那是 D1 的形态);选"编译错误"的人——char 与 int 可隐式互转。
小写字母与其对应大写字母的 ASCII 码相差 (如 'a' = 97、'A' = 65)。表达式 'd' - 'A' 的值是( )。
考点:大小写相差 32(D3)。
(D3)考点:ASCII 表里对应大小写字母相差 :'d' = 100、'A' = 65,'d' - 'A' = 35。
解析:;注意 'd' - 'a' 才是字母序距 ——跨大小写相减时, 的差混在其中,别与序号混淆。
排除法:选 的人算的是 'd' - 'a'(同大小写序距);选 的人忘了减;选 的人用了大写字母间错误的距离。
把小写字母 c 转成对应大写字母的表达式是( )。
考点:手写转大写(D4)。
(D4)考点:小写转大写:先减 'a' 得到字母序距(),再加 'A' 落到大写区:c - 'a' + 'A'。
解析:写法不依赖"差 "这个具体数字,而是以两个锚点字母表达"同一序号、换到另一区"——可读且不易错。
排除法:选 c + 'a' - 'A' 的人把方向写反(这是大转小);选 c - 32 + 32 的人一来一回等于没变;选 c * 2 的人没有任何依据。
字符变量 ch 中是数字字符 '7',把它转成数值 的表达式是( )。
考点:数字字符转数值(D5)。
(D5)考点:数字字符 '7' 的码值是 ,减去 '0'()得数值 :ch - '0' 是唯一的转换口诀。
解析:'0'~'9' 在 ASCII 表连续排列,减去 '0' 即"回到数值本身";逐字符读大数(如读入超 long long 的大整数)全靠这一步。
排除法:选 ch 直接用的人——那是字符 '7' 不是数 ;选 ch - 7 的人减错了基准(得到 );选 (int)ch 的人只换了类型、值仍是 。
整数变量 d 的值是 ,把它转成数字字符 '5' 存入字符变量的表达式是( )。
考点:数值转数字字符(D6)。
(D6)考点:数值转数字字符方向相反:——,即字符 '5'。
解析:与 D5 互逆;数位拆解后若要以字符形式输出或存进字符串,就要走这一步。
排除法:选 d 直接用的人——int 不能隐式当字符用;选 d + '5' 的人基准加错(得 '<' 一类的乱字符);选 char(d) 的人只换类型、值仍是数字 对应的控制字符。
表达式 '9' < 'A' 的值是( )('9' 的 ASCII 码是 ,'A' 是 )。
考点:字符比较即码值比较(D7)。
(D7)考点:字符比较就是 ASCII 码值比较:'9' 是 、'A' 是 , 成立,表达式为真。
解析:数字字符区 < 大写字母区 < 小写字母区,这条区间序是很多判断(如 c >= '0' && c <= '9')的底层依据。
排除法:选"假()"的人以为 9 > A 按某种"数值"比;选"无法比较"的人——char 完全可以比;选"取决于编译器"的人——ASCII 序是确定的。
ASCII 表中所有大写字母排在小写字母之前('Z' = 90 < 'a' = 97)。因此表达式 'Z' < 'a' 与 'a' < 'b' 的值分别是( )。
考点:大写在小写之前(D8)。
(D8)考点:ASCII 表中全部大写()在全部小写()之前:'Z' < 'a' 为真;同区内字母有序:'a' < 'b' 为真。
解析:两个都真;特别注意 'Z' < 'a'——"Z 是字母最后一个却小于 a"最容易违反直觉,也是大小写混排比较出错的根源。
排除法:选"假、假"或"假、真"的人都错在第一问——大写区整体靠前;选"真、假"的人错在第二问——同区字母码值递增。
下列关于转义字符的说法正确的是( )。
考点:转义字符(D9)。
(D9)考点:'\n' 是单个换行符、'\0' 是码值为 的结尾符、'\\' 是单个反斜杠——反斜杠开启转义,把后面的字符转成另一种含义。
解析:想表示反斜杠本身须写两个;空格是 ' '(码值 ),与 '\0' 完全两回事(D11 展开)。
排除法:选"两个字符"的人忽略了转义机制;选"'\0' 是空格"的人混淆了结尾符与空格;选"只能出现在字符串里"的人——'\n' 单独作字符完全合法。
判断字符 c 是小写字母的条件是( )。
考点:手写字母判断(D10)。
(D10)考点:判断小写字母:大于等于 'a' 且小于等于 'z',两个条件用 && 连接。
解析:区间判断的三要素:左闭 <= 方向、右闭 <=、逻辑与;把 && 写成 || 后条件几乎恒真(D 组经典错误)。
排除法:选 || 版的人让任意字符都能钻进某个分支;选大写区版的人判的是大写;选 'a' <= c && c >= 'z' 的人右边界方向写反(几乎恒假)。
关于 ' '(空格字符)与 '\0'(结尾符),正确的是( )。
考点:空格字符与 0 的区别(D11)。
(D11)考点:空格 ' ' 的 ASCII 码是 ,是"占着一个位置"的普通字符;结尾符 '\0' 的码是 ,标记字符串到此为止。
解析:"a b" 长度是 (空格计入),"a\0b" 的 strlen 只有 (读到 就停)——两个"看不见"的字符性质完全不同。
排除法:选"都是 "和"都是 "的人把两者混为一谈;选"同一字符不同写法"的人忽略了码值差异。
凯撒加密:小写字母后移 位(超过 z 回绕到 a)。字符 c 加密后的表达式是( )。
考点:凯撒位移取模(D12)。
(D12)考点:字母环上后移 位:(c - 'a' + k) % 26 + 'a'——先回到 的序号、加 取模回绕、再加回锚点(2020 年真题加密程序的数学内核)。
解析:c + k 会在 z 之后冲出字母区;(c + k) % 26 对码值取模毫无意义;取模对象必须是"序号"而不是码值。
排除法:选 c + k 直加版的人 'z' + 2 会变成 { 一类的符号;选 (c + k) % 26 的人对整段码值取模,结果落进乱码区;选 c % 26 + k 的人起点就错了。
阅读程序:
01char a = '5', b = '3'; 02cout << a - b << " " << a;
程序的输出是( )。
考点:字符算术结果是 int(D13)。
(D13)考点:a - b 即 '5' - '3' = 53 - 48 = 2,按 int 输出 2;而 a 单独输出仍是字符 5——参与运算才提升,单独输出保持字符。
解析:一条输出语句里两种形态并存:减法结果 2 5 中空格前是数、空格后是字符;想都按字符输出就要显式转回 char。
排除法:选 53 50 的人把两个都按码值输出了;选 2 53 的人把单个字符也当成了 int;选 5 2 的人把两项看反了。
阅读程序:
01char s[] = "aB"; 02for (int i = 0; s[i]; ++i) 03 if ('a' <= s[i] && s[i] <= 'z') s[i] -= 32; 04 else s[i] += 32; 05cout << s;
程序的输出是( )。
考点:大小写互换(D14)。
(D14)考点:逐字符判断当前区、向另一区跳:小写减 变大写、大写加 变小写——"aB" 互换得 "Ab"。
解析:加减 是大小写区的"摆渡船"(D3);关键是先判当前在哪个区,方向别搞反。
排除法:选 ab 或 AB 的人只做了一个方向的转换;选 Ba 的人把两个字符的转换方向各自弄反了。
char s[10] = "hi"; 在内存中,s[2] 的值是( )。
考点:字符数组与结尾符(E1)。
(E1)考点:字符串 "hi" 装进字符数组时,结尾自动带一个 '\0':占 s[0]、s[1] 之后,s[2] 就是 '\0'。
解析:结尾符是 C 风格字符串的"句号"——所有函数(strlen、cout、strcpy)都靠它判定字符串到哪里结束。
排除法:选 'i' 的人下标数错;选空格的人把结尾符当成了空格(D11);选随机值的人——初始化列表覆盖到 s[2],它是确定的 '\0'。
scanf("%s", s) 读入字符串 hello world(中间一个空格),s 中存下的是( )。
考点:scanf 读串遇空白断(E2)。
(E2)考点:scanf("%s", s) 以空白(空格、换行)为分隔,读到第一个空格就收工——只存下 hello。
解析:%s 读的是"一个词";world 留在输入流里等下一次读取(这正是 G4 陷阱的根源)。
排除法:选 hello world 的人以为 %s 收整行;选 helloworld 的人以为空格被丢弃后拼接;选 world 的人读反了方向。
char s[] = "china";,strlen(s) 的值是( )。
考点:strlen 不含结尾符(E3)。
(E3)考点:strlen 数到 '\0' 为止、不含结尾符:"china" 五个字母,长度 (占用空间其实是 )。
解析:长度 = 有效字符数;容量、sizeof、含零长度三个口径要分清(E4 展开对比)。
排除法:选 的人把结尾符也数了进去;选 的人少数了字母;选"不确定"的人——确定的,数到 '\0' 即停。
char s[20] = "abc";,sizeof(s) 与 strlen(s) 分别是( )。
考点:sizeof 与 strlen 之差(E4)。
(E4)考点:sizeof(s) 是数组容量(声明多大就是多大):;strlen(s) 是当前串长:。
解析:sizeof 编译期定死、不关心内容;strlen 运行期数到结尾符——"房子多大"与"住了几人"之别。
排除法:选 和 的人把 sizeof 当成了串长;选 和 的人两问都拧了;选 和 的人把容量当成了串长。
不调用库函数求字符串长度的程序:
01int n = 0; 02while (s[n] != '\0') n++;
循环结束时 n 等于( )。
考点:手写求长度(E5)。
(E5)考点:从下标 起逐格检查,遇到 '\0 停——循环结束时的 n 恰是字符个数(不含结尾符)。
解析:n 停在结尾符的下标上,而结尾符下标 = 有效字符数(前面每个字符各占一格)。
排除法:选"最后字符下标"的人——最后一个有效字符下标是 ;选"长度加 "的人多算了结尾符;选"数组容量"的人——容量与内容无关。
两个字符数组 s1、s2 各存一个字符串,判断二者内容是否相等的正确写法是( )。
考点:strcmp 与等号陷阱(E6)。
(E6)考点:比较两个字符串内容必须用 strcmp(s1, s2) == 0;== 比较的是两个数组的首地址。
解析:strcmp 返回 表示相等、正负表示字典序大小;s1 == s2 永远比较地址(G3 专门展开)。
排除法:选 s1 == s2 的人比较的是地址不是内容;选 s1 = s2 的人写成了赋值;选"返回 表示相等"的人—— 表示第一串大。
阅读程序:
01char a[20] = "abc", b[20]; 02strcpy(b, a); 03b[0] = 'X'; 04cout << a;
程序的输出是( )。
考点:strcpy 复制(E7)。
(E7)考点:strcpy(b, a) 把 a 的内容(含结尾符)复制到 b——两数组各自独立,改 b[0] 不影响 a,输出仍是 abc。
解析:复制产生两份独立数据;与"引用同一个串"的 string 拷贝语义对照(string 赋值同样是内容复制,也各自独立)。
排除法:选 Xbc 的人以为两数组共享内存;选"编译错误"的人——strcpy 正是干这个的;选 Xbcabc 的人臆造了拼接。
阅读程序:
01char a[20] = "12", b[] = "34"; 02strcat(a, b); 03cout << a;
程序的输出是( )。
考点:strcat 拼接(E8)。
(E8)考点:strcat(a, b) 把 b 追加到 a 的结尾符处:"12" + "34" 得 "1234",结果放在 a 里。
解析:前提是 a 的容量装得下拼接结果(这里 足够);b 保持不变。
排除法:选 123434 的人以为 b 也被改写并再拼一次;选 3412 的人拼接方向反了;选 12 34 的人以为会自动加空格。
统计字符串中小写字母个数的程序:
01int cnt = 0; 02for (int i = 0; s[i] != '\0'; ++i) 03 if ('a' <= s[i] && s[i] <= 'z') cnt++;
若 s = "Ab1c",cnt 是( )。
考点:遍历到结尾符停(E9)。
(E9)考点:遍历 C 风格字符串的标准终点是 s[i] != '\0':"Ab1c" 里只有 b、c 是小写,计数 。
解析:条件 s[i](非零为真)是同一写法的简写——读到结尾符()自然停;用固定长度会连垃圾一起数。
排除法:选 的人把 A 或 1 也当成了小写;选 的人数的是总长度;选 的人只数了 b。
输入一行 big data(中间一个空格)。下列哪种读法能把整行(含空格)读进字符串( )。
考点:读整行与读单词(E10)。
(E10)考点:读整行(含空格)要用 cin.getline(s, 100)(字符数组版)或 getline(cin, str)(string 版);>> 和 %s 都只读一个词。
解析:getline 读到换行符为止、把整行收入;两个"读单词"的入口会在空格处刹车(E2/G4)。
排除法:选 cin >> s 或 scanf 版的人都会只拿到 big;选"再读一次拼起来"的人遇到多空格立刻失灵且繁琐。
char s[] = "level"; 用首尾下标判断回文:i 从 起、j 从 strlen(s)-1 起,向中间比较。比较的轮数(s[i] 与 s[j] 比较的次数)是( )。
考点:字符数组判回文(E11)。
(E11)考点:"level" 长 ,首尾夹逼: 一轮、 一轮,中间 i=2 时 i < j 不成立——共比较 轮。
解析:轮数 = ;长度 时中间那个字符无需和谁比。
排除法:选 的人让中间字符也比了一遍;选 的人按"每轮两字符"硬算;选 的人把相遇轮也计入了。
阅读程序:
01char s[] = "banana"; 02int cnt = 0; 03for (int i = 0; s[i]; ++i) 04 if (s[i] == 'a') cnt++; 05cout << cnt;
程序的输出是( )。
考点:逐字符统计(E12)。
(E12)考点:for (int i = 0; s[i]; ++i) 以 '\0' 为天然终点,逐字符比对目标:"banana" 里有 个 'a'。
解析:单目标统计一个计数器就够;多目标升级成桶(H1 的字母频次表)。
排除法:选 的人数的是总长;选 的人数的是 'n' 的个数;选 的人只数了开头。
阅读程序:
01char a[10] = "cat"; 02string t = "cat"; 03a[0] = 'b'; 04t[0] = 'b'; 05cout << a << " " << t;
程序的输出是( )。
考点:单字符修改(E13)。
(E13)考点:字符数组与 string 都支持按下标改单字符:a[0]='b'、t[0]='b' 各自生效,输出 bat bat。
解析:区别不在"能不能改单字符",而在长度管理与运算符支持(F13 对比);本题两行修改互不干扰。
排除法:选 cat cat 的人以为下标修改无效;选 bat cat 或 cat bat 的人以为两者只有一种可改。
下列定义 string 对象的语句正确且含义明确的是( )。
考点:定义与初始化(F1)。
(F1)考点:string 由双引号字符串字面量初始化:string s = "hello";。
解析:单引号是字符('a'),不能直接初始化 string;花括号塞两个串、用小数构造都不合法。
排除法:选 'a' 版的人混淆了字符与字符串;选 s(5.3) 版的人臆造了构造;选花括号双串版的人把初始化列表错用到了 string。
阅读程序:
01string s = "hello"; 02cout << s.size() << " " << s.length();
程序的输出是( )。
考点:求长度(F2)。
(F2)考点:s.size() 与 s.length() 完全等价,都返回字符个数:"hello" 长度 。
解析:两个名字是历史遗留的同义词,返回类型是无符号整数(与 int 混比有坑,规范在后续章节展开)。
排除法:选 4 5 与 5 6 的人以为两者语义有别;选 6 6 的人把结尾符也算了——string 不靠 '\0' 计数。
阅读程序:
01string s = "abcdef"; 02cout << s[2] << s.at(0);
程序的输出是( )。
考点:下标访问(F3)。
(F3)考点:s[2] 是第三个字符 'c'、s.at(0) 是首字符 'a',拼接输出 ca。
解析:string 下标同样从 起;at 与 [] 语义相同(越界行为不同:at 抛异常、[] 未定义——竞赛惯用 [])。
排除法:选 bc 的人下标从 起数;选 ab 的人取错了两位;选 ba 的人两处都数偏。
阅读程序:
01string a = "12", b = "34"; 02a += b; 03a += "5"; 04cout << a;
程序的输出是( )。
考点:拼接(F4)。
(F4)考点:+= 可以接 string 也可以接字符串字面量:"12" += "34" 再 += "5" 得 "12345"。
解析:string 的拼接是内容级追加、长度自动增长——这是它相对字符数组最直观的便利(E8 要小心容量,这里不用)。
排除法:选带空格版的人以为会自动加间隔;选 15 的人以为做了数值加法;选 1234 的人漏了最后一次追加。
想把整数 拼接到字符串末尾,正确的写法是( )。
考点:数字拼接需转换(F5)。
(F5)考点:整数拼进字符串必须先转字符串:s += to_string(2026);——+= 没有整数重载。
解析:to_string 是 int/long long/double 到 string 的标准桥;反过来 string 到数值是 stoi/stoll。
排除法:选 s += 2026 的人——不能编译;选"与加字符串等价"的人恰恰忽略了这个不等价;选 s = s + int(2026) 的人只是换了种不合法的写法。
阅读程序:
01string s = "abcdefg"; 02cout << s.substr(2, 3);
程序的输出是( )。
考点:子串截取(F6)。
(F6)考点:s.substr(pos, len) 从下标 pos 起取 len 个字符:"abcdefg".substr(2, 3) 取下标 三个字符 cde。
解析:两个参数都是"从 0 数"的下标口径;substr(2) 一参数版则取到串尾。
排除法:选 bc 的人从下标 起取了;选 cdef 的人长度多取了一位;选 ab 的人取反了方向。
阅读程序:
01string s = "banana"; 02int p = s.find("na"); 03cout << p << " " << (int)s.find("xy");
程序的输出是( )。
考点:查找与未找到(F7)。
(F7)考点:s.find("na") 返回首次出现的下标 ;找不到返回特殊值 npos,转成 int 打印是 。
解析:"banana" 的下标 起正是 "na";判"没找到"的标准写法是 s.find(x) == string::npos,转 int 恰为 只是它的表象。
排除法:选 起始版的人数错了首次位置;选未找到为 的人把"没找到"当成了"在开头";选 的人把串长当成了返回值。
string a = "apple", b = "apply";,表达式 a < b 的值是( )。
考点:字典序直接比较(F8)。
(F8)考点:string 支持 < == 等内容级字典序比较:"apple" 与 "apply" 前四位相同,第 位 'e'(101) < 'y'(121),所以 a < b 为真。
解析:逐字符按码值比、先分出大小即停——不需要 strcmp,这正是 string 对字符数组的一大优势(E6 的对照)。
排除法:选"假、得用 strcmp"的人把字符数组的规矩搬来了;选"假、e 比 y 大"的人码值记反;选"编译错误"的人——运算符重载早就备好。
阅读程序:
01string s = "a1b2"; 02int letter = 0, digit = 0; 03for (char c : s) 04 if (c >= '0' && c <= '9') digit++; 05 else letter++; 06cout << letter << " " << digit;
程序的输出是( )。
考点:范围 for 遍历(F9)。
(F9)考点:for (char c : s) 逐个取出字符:"a1b2" 里字母 个、数字 个,输出 2 2。
解析:范围 for 是 string/数组遍历的现代写法,不碰下标就没有越界机会;计数逻辑与 E 组逐字符统计同构。
排除法:选 1 3、3 1 的人分类条件写反或漏判;选 4 0 的人全归了一类。
阅读程序:
01string s; 02s.push_back('x'); 03s.push_back('y'); 04s.clear(); 05cout << s.empty();
程序的输出是( )。
考点:追加清空判空(F10)。
(F10)考点:push_back 追加单字符、clear 清空、empty 判空——清空后 empty() 返回真,打印 。
解析:bool 打印默认是 ;clear 后长度归零,但对象还在,可继续使用。
排除法:选 的人以为没清干净;选 xy 的人看错了输出对象;选"编译错误"的人——三个成员函数都是常规操作。
函数只接收 const char* 参数(如 printf("%s", ...)),string 对象 s 传参时应写( )。
考点:转 C 字符串(F11)。
(F11)考点:string 面向 C 接口(如 printf("%s", ...))要调 s.c_str() 拿到 const char*。
解析:返回的是只读视图(指向内部缓冲)——想修改内容要复制出来改,直接写它不行。
排除法:选"直接传 s"的人类型不匹配;选 s.c_str[] 与 s.char() 的人发明了不存在的语法。
输入一行 big data,程序:
01string s; 02getline(cin, s); 03cout << s;
输出是( )。
考点:getline 读整行(F12)。
(F12)考点:getline(cin, s) 读入整行(含空格):big data 原样进入 s、原样输出。
解析:与 cin >> s 只读一个词相对(G4);getline 以换行为界并把换行符丢弃。
排除法:选 big 的人用成了 >>;选 data 的人以为只留后半;选空行的人以为换行符也被存了进去。
对比 string 与字符数组,正确的说法是( )。
考点:string 与字符数组对比(F13)。
(F13)考点:string 长度可变、+ += < == 直接用;字符数组定长、拼接比较要调 strcat/strcmp 且操心容量。
解析:string 的运算符重载把 C 串函数库的活全包了;字符数组胜在贴近底层、无额外管理开销——两者要都会用(真题两种载体都出现)。
排除法:选"两者长度都不可变"的人不了解 string;选"string 用 strcat"的人把两套工具配反了;选"字符数组自动扩容"的人——定长正是它的特征。
string s = "";,下列说法正确的是( )。
考点:空串与结尾符(F14)。
(F14)考点:空串 "" 的 size() 是 、没有可访问的字符;但 c_str() 给 C 侧看时,指向的是一个 '\0'(空 C 串的合法表示)。
解析:string 自身不依赖结尾符计数;s[0] 对空串是越界访问,不保证拿到 '\0'——"空"与"有一个零字符"是两回事。
排除法:选"s[0] 是 '\0' 可安全访问"的人把 C 串规则套到了 string;选"长度为 "的人数了假想的结尾符;选"内容随机"的人——空串是确定的空,不是未初始化。
int a[5] = {1, 2, 3, 4, 5}; 求和写成 for (int i = 0; i <= 5; ++i) s += a[i];。这个程序( )。
考点:循环边界差一(G1)。
(G1)考点:i <= 5 让循环跑了 轮,第六轮访问 a[5]——越界, 之外多加一个垃圾值,且越界本身已是未定义行为。
解析:五个元素的遍历条件是 i < 5;<= 与 < 一字之差就是"多跑一轮",这是数组错误的第一大来源。
排除法:选"正确输出 "的人没发现多加的一项;选"编译报错"的人高估了编译器;选"死循环"的人——循环照样正常结束。
阅读程序:
01int g[2][3] = {{1, 2, 3}, {4, 5, 6}}; 02int s = 0; 03for (int i = 0; i < 3; ++i) 04 for (int j = 0; j < 2; ++j) 05 s += g[i][j]; 06cout << s;
程序的结果是( )。
考点:二维下标写反(G2)。
(G2)考点:数组是 行 列,循环却按 行 列跑:g[2][*] 越出行界(行合法下标 )——未定义行为,编译器不拦。
解析:行列写反时部分越界访问"碰巧"落在整块内存之内,程序可能"看起来能跑",这正是它隐蔽的原因。
排除法:选 的人以为横竖都能求对——越界读到的值不保证是本矩阵的;选 的人臆造了部分和;选"编译错误"的人——维度检查不在编译期做。
char a[10] = "abc", b[10] = "abc";,表达式 a == b 的值是( )。
考点:字符数组等号比较(G3)。
(G3)考点:a == b 中两数组名退化为首地址,比较的是"两块内存是否同一块"——不同数组地址必不同,值为假。
解析:内容相等重要不了地址;要比内容用 strcmp(E6);这与 string 的 ==(比内容,F13)形成鲜明对照。
排除法:选真的人以为在比内容;选"编译错误"的人——地址比较完全合法;选"随机真假"的人——地址在编译链接期已定,不是随机。
程序用 cin >> s; 读入,用户输入 hello world 后回车。想得到完整一行却只拿到 hello,原因是( )。
考点:读串遇空格截断(G4)。
(G4)考点:>> 以空白为界,hello world 只取回 hello,world 留在流里等下次读取;要整行用 getline。
解析:这不是 bug 是语义——"按词读"恰恰是很多输入格式(先读 n 再读词)需要的;错的是"想读行却用了词读法"。
排除法:选缓冲区太小的人——多大的缓冲都改变不了切分规则;选"回车吞空格"的人臆造了机制;选"s 太短"的人——截断与长度无关。
阅读程序:
01int a[4] = {3, 1, 4, 1}; 02int s = 0; 03for (int i = 0; i < 4; ++i) 04 s += a[i] - a[i - 1]; 05cout << s;
程序的结果是( )。
考点:下标减一越负界(G5)。
(G5)考点:a[i - 1] 在 时是 a[-1]——负下标同样越界(合法范围 ),未定义行为。
解析:凡"看前一个"的循环(差分、比较相邻)都要从 起或单独处理 号;负下标越界与正下标越界同罪。
排除法:选 、选 、选 的三个选项都建立在"越界也有确定值"的误解上——未定义行为没有确定结果,合法范围之外读到的什么都不可信。
局部数组 int a[3] = {0}; int b[3] = {7, 7, 7}; 紧挨着存放,程序执行 a[3] = 99;(越界写)。可能的后果是( )。
考点:越界写覆盖邻居(G6)。
(G6)考点:越界写比越界读更危险:a[3] = 99 可能恰好落进相邻变量(如 b[0])的内存——程序不崩、数据悄悄变脏,极难排查。
解析:未定义行为下"恰好写到哪"取决于内存布局;实战里"神秘变值"十有八九是某处越界写。
排除法:选"一定崩溃"的人——最危险的恰是它常常不崩;选"编译器报错"与"自动忽略"的人都把检查责任交给了不存在的机制。
char c = '5'; int d = 5;,下列值为假的表达式是( )。
考点:字符五与数值五(G7)。
(G7)考点:'5' 的码值是 :c == d 即 ,为假;c - '0' == d()与 c == 53 都为真。
解析:字符与数值之间唯一的桥是加减 '0'(D5/D6);直接 == 比的是码值不是字面。
排除法:其余三个表达式都真——只有跨类型的直接相等是假;本题选"值为假"的那一个。
for (int i = 0; i < strlen(s); ++i) 在字符串很长、循环很大时的隐患是( )。
考点:循环内重复求长度(G8)。
(G8)考点:strlen(s) 每次调用都要从头扫到结尾符——放在循环条件里每轮重扫一遍,长串上复杂度从 涨到 ;应先 int len = strlen(s); 存下来。
解析:这是"函数调用不是免费"的第一课;string 的 size() 是 (直接读记录),无此顾虑。
排除法:选"结果随循环变化"的人——串没变长度就不变,错的是效率不是正确性;选"编译器禁止"与"没有问题"的人一个太严一个太松。
两个数组 int a[5], b[5]; 都已有数据,想把 b 的内容整体复制到 a,正确做法是( )。
考点:数组不能整体赋值(G9)。
(G9)考点:数组名不是"可以整体赋值的对象":a = b 非法;要复制逐元素循环(或 memcpy(a, b, sizeof(a)))。
解析:数组名在赋值语境退化为地址;string 赋值 t = s 才是内容级复制(F13 对照)。
排除法:选两个"整体赋值"写法的人撞语法墙;选 copy(a, b) 的人发明了不存在的接口。
把字符数组 t 里的 个有效字符倒序复制到 r 后直接 cout << r;,输出末尾粘了乱码。最可能的原因是( )。
考点:手工构串忘结尾符(G10)。
(G10)考点:手工往字符数组里搬字符构造字符串,必须在末尾补 '\0',否则输出越过有效字符继续读垃圾内存,直到碰巧遇到 才停——表现为"粘乱码"。
解析:cout 与所有 C 串函数只认结尾符;搬运几个字符就补一个 '\0',一步都不能省。
排除法:选"cout 坏了"的人方向反了;选"数组太大"的人——大小与乱码无关;选"倒序复制不合法"的人——方向不影响合法性。
阅读程序:
01string s = "abracadabra"; 02int cnt[26] = {0}; 03for (char c : s) 04 if ('a' <= c && c <= 'z') cnt[c - 'a']++; 05cout << cnt['b' - 'a'];
程序的输出是( )。
考点:字母频次统计(H1)。
(H1)考点:cnt[c - 'a'] 把字母映射到 的桶:"abracadabra" 里 'b' 出现 次(下标 、)。
解析:字母桶是桶计数(B9)与字符运算(D 组)的标准结合——查表输出 cnt[1] 即 'b' 的频次。
排除法:选 的人少数了一次;选 的人数的是 'a' 的频次;选 的人把总长当成了频次。
一行由小写字母和空格组成的句子(单词间恰一个空格,句首句尾无空格),统计单词个数的最简判断是( )。
考点:单词计数(H2)。
(H2)考点:单词间恰一个空格、首尾无空格时,单词数 = 空格数 ——三个空格分出四个单词。
解析:这是"分隔符切分"最朴素的形态;更一般场景(多空格、混标点)要按"上一位是空格且当前是字母"统计单词开头。
排除法:选"空格数"的人漏了最后一个单词(它后面没有空格);选"句子长度"的人把字符数当成了词数;选"字母数"的人数的是字母不是词。
数组 a = {1, 1, 2, 2, 2, 1, 1},求"连续相等的最长一段"的长度,结果是( )。
考点:最长连续段(H3)。
(H3)考点:扫一遍维护"当前连续长度":与前一位相等则 、否则重置为 —— 里三个 连成最长段,长度 。
解析:两段 各长 、一段 长 ,擂主取 ;"当前段、历史最长"两个变量分工明确。
排除法:选 的人把两段 隔空相加了(中间隔着 ,不连续);选 的人只看到了 的段;选 的人把整串当成了连续相等。
数组 a = {3, 1, 3, 2, 1},按原次序保留每个值第一次出现(后面重复出现的丢弃)后输出的序列是( )。
考点:去重保序(H4)。
(H4)考点:按原次序保留每个值第一次出现: 首见保留、 首见保留、 重复跳过、 保留、 重复跳过——得 3 1 2。
解析:需要"见没见过"的快速判断——布尔标记数组按值打勾(值域小)或双重循环向前查(通用)。
排除法:选 1 2 3 的人做成了"排序去重",丢掉了原次序;选 3 1 2 1 的人只删了部分重复;选 1 3 2 的人次序与保留规则都错了。
阅读程序:
01int n = 407, d[10], k = 0; 02while (n > 0) { 03 d[k++] = n % 10; 04 n /= 10; 05} 06for (int i = 0; i < k; ++i) cout << d[i];
程序的输出是( )。
考点:各位数字拆解(H5)。
(H5)考点:n % 10 取末位、n /= 10 去末位,循环到 —— 依次拆出 、、,按拆解序输出 704(个位在前)。
解析:拆解序是个位到高位;要得到人们习惯的高位在前(),得倒过来输出——这正是"先收集进数组、再倒序输出"的价值(2020 年真题的数组用法)。
排除法:选 407 的人以为拆解直接得高位序;选两种带空格版的人输出格式与程序不符(程序无空格拼接)。
把十进制数 转二进制:不断除 取余数存入数组,再倒序输出数组。输出是( )。
考点:进制收集余数(H6)。
(H6)考点:除 取余依次得 (低位在前),倒序输出才是正确二进制 1101。
解析:余数序 = 低位到高位,收集与倒序两步缺一不可——数组在这里扮演"先存后翻"的容器(与 H5 同构、与 02 卷进制算法卷衔接)。
排除法:选 1011(忘倒序)的人正好把数读反;选 1110 的人倒序也做错了;选 13 的人没做转换。
用查表法加密:enc[26] 存每个小写字母的密文字符。明文 s 加密的核心一行是( )。
考点:映射表加密(H7)。
(H7)考点:查表加密:明文字母减 'a' 得下标,从 enc 表取密文字符——t[i] = enc[s[i] - 'a'](2020 年真题 encoder/decoder 的骨架)。
解析:映射表把"任意替换规则"变成一次数组访问;对称的解密表可由 dec[enc[i]] = i 反向构建。
排除法:选 s[i] + enc 的人把字符和整个数组相加(类型不通);选 enc[i] 的人用位置当明文,与内容无关;选 enc[s[i]] - 'a' 的人用字符直接当下标(越界到 之外)且方向写反。
判断字符串是否回文:i = 0, j = s.size() - 1,while (i < j) 中比较后应执行( )。
考点:回文综合判断(H8)。
(H8)考点:首尾夹逼的标准步:不等即假返回,否则 i++、j-- 向中间靠拢。
解析:j++ 会让两指针背道而驰;不比较就移动则根本没在判回文;步进 会跳过该比的字符对。
排除法:选"j 加、i 加"版的人第二指针方向错;选"不比较"版的人逻辑空心;选"跳 "的人漏比一半字符。
矩阵 g = {{1,2,3},{4,5,6},{7,8,9}},顺时针打印最外圈(从 g[0][0] 起:上边从左到右、右边从上到下、下边从右到左、左边从下到上),输出是( )。
考点:矩阵顺时针打印(H9)。
(H9)考点:外圈四段:上边 (左到右)、右边 (除首)、下边 (右到左)、左边 (除首尾)——拼成 1 2 3 6 9 8 7 4。
解析:每段的首或尾已在上段输出过,起止下标各让一位避免重复;中心 不在外圈。
排除法:选含 的两版把中心或次序弄错了;选 1 4 7 ... 起头的人从左边竖着走(逆时针);选 1 2 3 4 ... 的人按行直读没绕圈。
下列说法错误的是( )。
考点:综合判断(H10)。
(H10)考点:选错误项:strlen 数有效字符、sizeof 数占用空间——两者只在"恰好填满且不含结尾符"时才碰巧相等,不一定相同。
解析:其余三项均真:下标 (A5)、string 支持 +=(F4)、'0' 的码值是 不是 (D11)。
排除法:选 A 的人忘了下标从 起;选 C 的人否定了 string 的基础能力;选 D 的人把 '0' 与 '\0' 混为一谈。
1 #include <cstdio> 2 using namespace std; 3 int n, m; 4 int a[100], b[100]; 5 6 int main() { 7 scanf("%d%d", &n, &m); 8 for (int i = 1; i <= n; ++i) 9 a[i] = b[i] = 0; 10 for (int i = 1; i <= m; ++i) { 11 int x, y; 12 scanf("%d%d", &x, &y); 13 if (a[x] < y && b[y] < x) { 14 if (a[x] > 0) 15 b[a[x]] = 0; 16 if (b[y] > 0) 17 a[b[y]] = 0; 18 a[x] = y; 19 b[y] = x; 20 } 21 } 22 int ans = 0; 23 for (int i = 1; i <= n; ++i) { 24 if (a[i] == 0) 25 ++ans; 26 if (b[i] == 0) 27 ++ans; 28 } 29 printf("%d\n",ans); 30 return 0; 31 }
假设输入的 和 都是正整数, 和 都是在 范围内的整数,完成下面的判断题和单选题。
当 时,输出的值一定小于 。( )
执行完第 行的 ++ans 时,ans 一定是偶数。( )
a[i] 和 b[i] 不可能同时大于 。( )
若程序执行到第 行时,x 总是小于 y,那么第 行不会被执行。( )
若 个 x 两两不同,且 个 y 两两不同,则输出的值为( )。
若 个 x 两两不同,且 个 y 都相等,则输出的值为( )。
(矩阵变幻)有一个奇幻的矩阵,在不停地变幻,其变幻方式为:数字 变成矩阵 ,数字 变成矩阵 。最初该矩阵只有一个元素 ,变幻 次后,矩阵会变成什么样?
例如,矩阵最初为:;矩阵变幻 次后:;矩阵变幻 次后:。
输入一行一个不超过 的正整数 。输出变幻 次后的矩阵。
试补全程序。
提示:
<< 表示二进制左移运算符,例如 << ;
而 ^ 表示二进制异或运算符,它将两个参与运算的数中的每个对应的二进制位一一进行比较,若两个二进制位相同,则运算结果的对应二进制位为 ,反之为 。
1 #include <cstdio> 2 using namespace std; 3 int n; 4 const int max_size = 1 << 10; 5 6 int res[max_size][max_size]; 7 8 void recursive(int x, int y, int n, int t) { 9 if (n == 0) { 10 res[x][y] = ①; 11 return; 12 } 13 int step = 1 << (n - 1); 14 recursive(②, n - 1, t); 15 recursive(x, y + step, n - 1, t); 16 recursive(x + step, y, n - 1, t); 17 recursive(③, n - 1, !t); 18 } 19 20 int main() { 21 scanf("%d", &n); 22 recursive(0, 0, ④); 23 int size = ⑤; 24 for (int i = 0; i < size; ++i) { 25 for (int j = 0; j < size; ++j) 26 printf("%d", res[i][j]); 27 puts(""); 28 } 29 return 0; 30 }
①处应填( )。
②处应填( )。
③处应填( )。
④处应填( )。
⑤处应填( )。
(计数排序)计数排序是一个广泛使用的排序方法。下面的程序使用双关键字计数排序,将 对 以内的整数,从小到大排序。
例如有三对整数 、、,那么排序之后应该是 、、。
输入第一行为 ,接下来 行,第 行有两个数 a[i] 和 b[i],分别表示第 对整数的第一关键字和第二关键字。
从小到大排序后输出。
数据范围 ,。
提示:应先对第二关键字排序,再对第一关键字排序。数组 ord[] 存储第二关键字排序的结果,数组 res[] 存储双关键字排序的结果。
试补全程序。
1 #include <cstdio> 2 #include <cstring> 3 using namespace std; 4 const int maxn = 10000000; 5 const int maxs = 10000; 6 7 int n; 8 unsigned a[maxn], b[maxn], res[maxn], ord[maxn]; 9 unsigned cnt[maxs + 1]; 10 11 int main() { 12 scanf("%d", &n); 13 for (int i = 0; i < n; ++i) 14 scanf("%d%d", &a[i], &b[i]); 15 memset(cnt, 0, sizeof(cnt)); 16 for (int i = 0; i < n; ++i) 17 ①; // 利用 cnt 数组统计数量 18 for (int i = 0; i < maxs; ++i) 19 cnt[i + 1] += cnt[i]; 20 for (int i = 0; i < n; ++i) 21 ②; // 记录初步排序结果 22 memset(cnt, 0, sizeof(cnt)); 23 for (int i = 0; i < n; ++i) 24 ③; // 利用 cnt 数组统计数量 25 for (int i = 0; i < maxs; ++i) 26 cnt[i + 1] += cnt[i]; 27 for (int i = n - 1; i >= 0; --i) 28 ④; // 记录最终排序结果 29 for (int i = 0; i < n; ++i) 30 printf("%d %d\n", ⑤); 31 return 0; 32 }
①处应填( )。
②处应填( )。
③处应填( )。
④处应填( )。
⑤处应填( )。
设 是 个实数的数组,考虑下面的递归算法:
XYZ(A[1..n]) 1 if n = 1 then return A[1] 2 else temp ← XYZ(A[1..n-1]) 3 if temp < A[n] 4 then return temp 5 else return A[n]
请问算法 XYZ 的输出是什么?( )
1 #include <cstdlib> 2 #include <iostream> 3 using namespace std; 4 5 char encoder[26] = {'C', 'S', 'P', 0}; 6 char decoder[26]; 7 8 string st; 9 10 int main() { 11 int k = 0; 12 for (int i = 0; i < 26; ++i) 13 if (encoder[i] != 0) ++k; 14 for (char x = 'A'; x <= 'Z'; ++x) { 15 bool flag = true; 16 for (int i = 0; i < 26; ++i) 17 if (encoder[i] == x) { 18 flag = false; 19 break; 20 } 21 if (flag) { 22 encoder[k] = x; 23 ++k; 24 } 25 } 26 for (int i = 0; i < 26; ++i) 27 decoder[encoder[i] - 'A'] = i + 'A'; 28 cin >> st; 29 for (int i = 0; i < st.length(); ++i) 30 st[i] = decoder[st[i] - 'A']; 31 cout << st; 32 return 0; 33 }
输入的字符串应当只由大写字母组成,否则在访问数组时可能越界。( )
若输入的字符串不是空串,则输入的字符串与输出的字符串一定不一样。( )
将第 行的 i < 26 改为 i < 16,程序运行结果不会改变。( )
将第 行的 i < 26 改为 i < 16,程序运行结果不会改变。( )
若输出的字符串为 ABCABCABCA,则下列说法正确的是( )。
若输出的字符串为 CSPCSPCSPCSP,则下列说法正确的是( )。
1 #include <iostream> 2 using namespace std; 3 4 long long n, ans; 5 int k, len; 6 long long d[1000000]; 7 8 int main() { 9 cin >> n >> k; 10 d[0] = 0; 11 len = 1; 12 ans = 0; 13 for (long long i = 0; i < n; ++i) { 14 ++d[0]; 15 for (int j = 0; j + 1 < len; ++j) { 16 if (d[j] == k) { 17 d[j] = 0; 18 d[j + 1] += 1; 19 ++ans; 20 } 21 } 22 if (d[len - 1] == k) { 23 d[len - 1] = 0; 24 d[len] = 1; 25 ++len; 26 ++ans; 27 } 28 } 29 cout << ans << endl; 30 return 0; 31 }
假设输入的 是不超过 的正整数, 都是不超过 的正整数,完成下面的判断题和单选题。
若 ,则输出 ans 时,len=n。( )
若 ,则输出 ans 时,len 一定小于 。( )
若 ,则输出 ans 时, 一定大于 。( )
若输入的 等于 、 为 ,则输出等于( )。
若输入的 等于 (即 )、 为 ,则输出等于( )。
若输入的 等于 、 为 ,则输出等于( )。
(Josephus 问题)有 个人围成一个圈,依次标号 至 。从 号开始,依次 交替报数,报到 的人会离开,直至圈中只剩下一个人。求最后剩下人的编号。
试补全模拟程序。
1 #include <iostream> 2 3 using namespace std; 4 5 const int MAXN = 1000000; 6 int F[MAXN]; 7 8 int main() { 9 int n; 10 cin >> n; 11 int i = 0, p = 0, c = 0; 12 while (①) { 13 if (F[i] == 0) { 14 if (②) { 15 F[i] = 1; 16 ③; 17 } 18 ④; 19 } 20 ⑤; 21 } 22 int ans = -1; 23 for (i = 0; i < n; i++) 24 if (F[i] == 0) 25 ans = i; 26 cout << ans << endl; 27 return 0; 28 }
①处应填( )
②处应填( )
③处应填( )
④处应填( )
⑤处应填( )
1 #include <algorithm> 2 #include <iostream> 3 #include <limits> 4 5 using namespace std; 6 7 const int MAXN = 105; 8 const int MAXK = 105; 9 10 int h[MAXN][MAXK]; 11 12 int f(int n, int m) 13 { 14 if (m == 1) return n; 15 if (n == 0) return 0; 16 17 int ret = numeric_limits<int>::max(); 18 for (int i = 1; i <= n; i++) 19 ret = min(ret, max(f(n - i, m), f(i - 1, m - 1)) + 1); 20 return ret; 21 } 22 23 int g(int n, int m) 24 { 25 for (int i = 1; i <= n; i++) 26 h[i][1] = i; 27 for (int j = 1; j <= m; j++) 28 h[0][j] = 0; 29 30 for (int i = 1; i <= n; i++) { 31 for (int j = 2; j <= m; j++) { 32 h[i][j] = numeric_limits<int>::max(); 33 for (int k = 1; k <= i; k++) 34 h[i][j] = min( 35 h[i][j], 36 max(h[i - k][j], h[k - 1][j - 1]) + 1); 37 } 38 } 39 40 return h[n][m]; 41 } 42 43 int main() 44 { 45 int n, m; 46 cin >> n >> m; 47 cout << f(n, m) << endl << g(n, m) << endl; 48 return 0; 49 }
当输入为 7 3 时,第 行用来取最小值的 min 函数执行了 次。( )
输出的两行整数总是相同的。( )
当 m 为 时,输出的第一行总为 n。( )
算法 g(n,m) 最为准确的时间复杂度分析结果为( )。
当输入为 20 2 时,输出的第一行为( )。
当输入为 100 100 时,输出的第一行为( )。
1 #include <iostream> 2 #include <vector> 3 #include <algorithm> 4 using namespace std; 5 6 int f(string x, string y) { 7 int m = x.size(); 8 int n = y.size(); 9 vector<vector<int>> v(m+1, vector<int>(n+1, 0)); 10 for (int i = 1; i <= m; i++) { 11 for (int j = 1; j <= n; j++) { 12 if (x[i-1] == y[j-1]) { 13 v[i][j] = v[i-1][j-1] + 1; 14 } else { 15 v[i][j] = max(v[i-1][j], v[i][j-1]); 16 } 17 } 18 } 19 return v[m][n]; 20 } 21 22 bool g(string x, string y) { 23 if (x.size() != y.size()) { 24 return false; 25 } 26 return f(x + x, y) == y.size(); 27 } 28 29 int main() { 30 string x, y; 31 cin >> x >> y; 32 cout << g(x, y) << endl; 33 return 0; 34 }
f 函数的返回值小于等于 min(n,m)。( )
f 函数的返回值等于两个输入字符串的最长公共子串的长度。( )
当输入两个完全相同的字符串时,g 函数的返回值总是 true。( )
将第 行中的 v[m][n] 替换为 v[n][m],那么该程序( )。
当输入为 csp-j p-jcs 时,输出为( )。
当输入为 csppsc spsccp 时,输出为( )。
试补全程序。
1 #include <iostream> 2 #include <vector> 3 4 using namespace std; 5 6 int find_missing(vector<int>& nums) { 7 int left = 0, right = nums.size() - 1; 8 while (left < right) { 9 int mid = left + (right - left) / 2; 10 if (nums[mid] == mid + ①) { 11 ②; 12 } else { 13 ③; 14 } 15 } 16 return ④; 17 } 18 19 int main() { 20 int n; 21 cin >> n; 22 vector<int> nums(n); 23 for (int i = 0; i < n; i++) cin >> nums[i]; 24 int missing_number = find_missing(nums); 25 if (missing_number == ⑤) { 26 cout << "Sequence is consecutive" << endl; 27 } else { 28 cout << "Missing number is " << missing_number << endl; 29 } 30 return 0; 31 }
①处应填( )
②处应填( )
③处应填( )
④处应填( )
⑤处应填( )
试补全程序。
1 #include <iostream> 2 #include <string> 3 #include <vector> 4 using namespace std; 5 6 int min(int x, int y, int z) { 7 return min(min(x, y), z); 8 } 9 10 int edit_dist_dp(string str1, string str2) { 11 int m = str1.length(); 12 int n = str2.length(); 13 vector<vector<int>> dp(m + 1, vector<int>(n + 1)); 14 15 for (int i = 0; i <= m; i++) { 16 for (int j = 0; j <= n; j++) { 17 if (i == 0) 18 dp[i][j] = ①; 19 else if (j == 0) 20 dp[i][j] = ②; 21 else if (③) 22 dp[i][j] =④; 23 else 24 dp[i][j] = 1 + min(dp[i][j - 1], dp[i - 1][j], ⑤); 25 } 26 } 27 return dp[m][n]; 28 } 29 30 int main() { 31 string str1, str2; 32 cin >> str1 >> str2; 33 cout << "Minimum number of operations: " 34 << edit_dist_dp(str1, str2) << endl; 35 return 0; 36 }
①处应填( )
②处应填( )
③处应填( )
④处应填( )
⑤处应填( )
1 #include <iostream> 2 #include <vector> 3 using namespace std; 4 5 int compute(vector<int>& cost) { 6 int n = cost.size(); 7 vector<int> dp(n+1, 0); 8 dp[1] = cost[0]; 9 for (int i = 2; i <= n; i++) { 10 dp[i] = min(dp[i-1], dp[i-2]) + cost[i-1]; 11 } 12 return min(dp[n], dp[n-1]); 13 } 14 15 int main() { 16 int n; 17 cin >> n; 18 vector<int> cost(n); 19 for (int i = 0; i < n; i++) { 20 cin >> cost[i]; 21 } 22 cout << compute(cost) << endl; 23 return 0; 24 }
当输入的 cost 数组为 {10, 15, 20} 时,程序的输出为 15。( )
如果将 dp[i-1] 改为 dp[i-3],程序可能会产生编译错误。( )
程序总是输出 cost 数组中最小的元素。( )
当输入的 cost 数组为 {1, 100, 1, 1, 1, 100, 1, 1, 100, 1} 时,程序的输出为( )。
如果输入的 cost 数组为 {10, 15, 30, 5, 5, 10, 20},程序的输出为( )。
若将代码中的 min(dp[i-1], dp[i-2]) + cost[i-1] 修改为 dp[i-1] + cost[i-2],输入 cost 数组为 {5, 10, 15} 时,程序的输出为( )。
1 #include <algorithm> 2 #include <cstdio> 3 #include <cstring> 4 #define ll long long 5 int f[5007][5007]; 6 int a[5007], b[5007]; 7 int n; 8 int main(){ 9 scanf("%d", &n); 10 for (int i = 1; i <= n; ++i) { 11 scanf("%d", &a[i]); 12 } 13 for (int i = 1; i <= n; ++i) { 14 scanf("%d", &b[i]); 15 } 16 for (int i = 1; i <= n; ++i) { 17 for (int j = 1; j <= n; ++j) { 18 f[i][j] = std::max(f[i][j], std::max(f[i - 1][j], f[i][j - 1])); 19 if (a[i] == b[j]) { 20 f[i][j] = std::max(f[i][j], f[i - 1][j - 1] + 1); 21 } 22 } 23 } 24 printf("%d\n", f[n][n]); 25 return 0; 26 }
当输入为 4 1 2 3 4 1 3 2 2 时,输出为 。( )
当程序运行完毕后,对于所有的 ,都一定有 。( )
将第 行的 f[i][j] = std::max(f[i][j], std::max(f[i - 1][j], f[i][j - 1])); 删去后,并不影响程序运行结果。( )
输出的答案满足的性质有( )。
如果在第 行的循环前加上以下两行:
1 std::sort(a + 1, a + n + 1); 2 std::sort(b + 1, b + n + 1);
则答案会( )。
如果输入的 a = {1, 2, ..., n},而且 b 数组中数字均为 中的正整数,则上述代码等价于下面哪个问题?( )