简介:这是一份面向高校C语言课程与PTA平台理论考试备考者的试题答案文档,聚焦选择题、判断题等客观题的核对与查漏补缺。内容围绕变量与数据类型、运算符优先级、编译预处理、main函数与程序执行起点、语句与复合语句、输入输出格式控制、for循环与累加阶乘等核心考点展开;判断题覆盖头文件包含、主函数唯一性、分号结束语句、复合语句与空语句等细节,选择题侧重循环实现序列求和、阶乘计算及变量初始化。每道题附参考答案,并配有必要知识点详解,便于读者做错后迅速定位概念盲区,理解整数除法、赋值与比较混淆、scanf格式符匹配等易错点。压缩包共1个docx文件,约345KB,体积较小,可直接在Word中按题号或关键词检索,适合考前集中刷题、课堂练习核对。目前已有1897人学习下载,适合需要短期梳理C语言基础语法、提升客观题正确率的学生使用。
1. 判断题丢分最狠的地方,往往不是你选错,而是没看清它在问什么
PTA理论考这套 C 语言题库有个反直觉的特点:1 分的判断题占了绝大多数篇幅,但真正卡人的不是算不出来,而是没分清题目在问"语法合法"还是"运行结果"。同一份卷子里,x % 2配 double 是语法层面就不成立,1/n配 int 是语法没错但结果被截断,sum没初始化是语法过得去、结果却是随机值——三种错法对应三套判分逻辑,用同一套直觉去答必然翻车。
拿分的路子很明确:先把判断题的话术模板认全,再把 2 分选择题和程序阅读填空拆成固定套路。这套题库适合已经写过一点 C、但在判断题和选择题上反复踩坑的人,也适合把它当查漏清单,考前一遍遍扫语法死角的人。
2. 考点地图:三类题型的分数账本与语法底座
2.1 判断题、单选题、程序阅读填空的分值结构
翻一遍题库能看出三类题的分布:1 分判断题条数最多,覆盖预处理、程序结构、运算符、输入输出、字符、流程控制全部模块;2 分单选题集中在流程控制和输入输出,题干往往给四段代码让你挑"功能正确的那个";还有一类直接填数字的程序阅读题,一问 1 分,问的是循环执行次数、变量终值这类硬指标。
这个分布决定了复习策略不能用同一把尺子:
| 题型 | 单题分值 | 主要考法 | 建议单题耗时 | 拿分难度 |
|---|---|---|---|---|
| 判断题 | 1 分 | 语法是否合法、说法是否准确 | 30~40 秒 | 低,但陷阱密集 |
| 单选题 | 2 分 | 四段代码挑正确/挑错误、挑不等价 | 90~120 秒 | 中 |
| 程序阅读填空 | 1 分/空 | 执行次数、变量终值 | 60~90 秒 | 中,算错一步全错 |
判断题单位时间得分效率最高,但也是失分最集中的地方——因为错一道只扣 1 分,很多人不心疼,错十道就是 10 分。反过来,2 分选择题一旦看错"以下哪个是错误的",丢的是双倍。做题顺序上,先把判断题扫完并标记不确定的,再攻 2 分题,最后回头处理标记项,这个顺序比从头到尾硬推更稳。
还有一个隐性分值:程序阅读填空经常是同一段代码连着问四空。第一空算错,后面三空跟着错。这类题的正确做法不是顺着往下算,而是先把循环边界在草稿上列出来——起始值、终止条件、步长,三个参数写清楚再动笔。
2.2 语法底座:预处理、main、分号、声明顺序
判断题里最爱考的四条底座规则,几乎每份卷子都会碰。
第一条,预处理命令不以分号结尾。#include <stdio.h>是编译预处理命令,它作用于编译之前,按行识别,不参与语句层面的分号规则。写面上带一个分号看着无害,实际是把一个多余的分号塞进了源文件。这类题的判分口径就是"预处理命令需不需要分号",答案指向"不需要"。
第二条,程序入口是 main,不是第一行。C 程序从main()函数的第一条可执行语句开始执行,源文件顶部的宏定义、全局变量声明、函数原型都不算"执行"。看到"从源文件第一条语句开始执行"这种表述,直接判错。
第三条,不是所有语句都以分号结尾。if、for、while、switch这些控制结构的头部不带分号,复合语句{ }后面也不带,函数定义的花括号后面同样不带。但要注意两个例外:do-while的while(...)后面必须带分号,结构体/共用体定义结尾也要带分号。题库里"所有语句都必须以分号结束"这种绝对化表述,几乎必然是错的。
第四条,先声明后使用。下面这段是错的:
/* 错误示范:使用在前、声明在后 */ int main(void) { k = 1; /* 此刻 k 还不存在,编译器不知道它是什么类型 */ int k; /* 声明来得太晚 */ return 0; }编译器读到k = 1时,符号表里没有 k,直接报未声明标识符;即便后面的int k;补上了声明,也无法回溯修正前一行。正确写法只需把两行对调。C99 之后允许在块内任意位置声明变量,但"声明必须出现在使用之前"这一条从未松动。判断题里凡是"以下程序段符合 C 语言语法"配一段先使用后声明的代码,答案一律是错的。
顺带记一个常考的正面结论:定义的变量代表内存中的一个存储单元,这句话是对的;一对{}括起来的多条语句叫复合语句,在语法上被视为一条语句,这也是对的;单独一个分号构成空语句,什么也不做,同样是对的。这三条经常被出成"看着像错的其实是对的"的干扰项。
2.3 运算符与表达式:优先级、取模、整数除法的三处陷阱
运算符这块的失分点高度集中,就三处。
第一处,取模运算符只认整数。%的两个操作数必须是整型,double x; x % 2在语法层面就不成立。这类题常伪装成"若变量定义为 double x;,则 x % 2 是符合 C 语言语法的表达式",答案错。
第二处,整数除法向零截断。int n;且|n| > 1时,1/n的结果恒为 0——因为 1 和 n 都是整型,做的是整数除法,小数部分直接丢弃,不管 n 是 2 还是 -100。这条结论本身是对的,但很多人在"负数是向下取整还是向零取整"上犹豫,记住 C 的整数除法一律向零截断即可。
第三处,赋值运算符优先级低于算术运算符。题库里有一道很妙的题:假设赋值运算符优先级比算术运算符高,问int n; n = 10 + 2;执行后 n 的值是不是 10。按假设,先执行n = 10,n 变成 10,然后10 + 2的结果 12 无处可去,被丢弃,所以 n 确实是 10。这道题考的不是真实优先级,而是你能不能顺着假设推下去——真按实际优先级算,n 是 12,反而答错。
还有两个高频点必须刻进条件反射:x + y = 22不合法,赋值号左边必须是左值,x + y是个表达式结果,没有存储单元;fahr++与fahr + 1不等价,前者会改变 fahr 本身,后者只产生一个临时值。单目运算符只需要一个操作数,这条也常被反着问。
2.4 真题演练:五道最容易被"顺手选 T"的判断题
第一道,F1-14:若变量定义为 double x;,则 x % 2 是符合 C 语言语法的表达式。
答题思路:看到%先看两边类型变量声明。double 是浮点型,取模要求整型,语法层面直接不成立。这类题不要去想"能不能自动转换成 int",C 不会替你转。
第二道,F1-15:若变量定义为 int n;,当 n 的绝对值大于 1 时,则表达式 1/n 的值恒为 0。
答题思路:整型除以整型,结果仍是整型,且向零截断。|n| > 1 意味着除数绝对值至少是 2,1 除以任何绝对值 ≥2 的整数,商的整数部分都是 0。答案对。注意题干特意加了"绝对值大于 1",就是为了排除 n = ±1 的情况。
第三道,HW031-4:如果变量已经正确定义,则执行if (x = 20) { y = 1; } else { y = 0; }后,x 的值不变。
答题思路:if括号里是赋值不是比较。x = 20先把 20 赋给 x,整个表达式的值也是 20,非零为真,走 y = 1 分支。x 从原值变成了 20,所以"不变"是错的。凡是看到if (变量 = 常量)这种写法,第一反应就该是"这里少了等号"。
第四道,F1-18(循环体那条):int i, sum; for (i = 1; i <= 10; i++) { sum = sum + i; }执行后 sum 的值是 55。
答题思路:这题是整套题库里最值得留个心眼的类型。循环次数确实是 10 次,累加逻辑也没问题,但 sum 从头到尾没有赋初值,它的起始值是不确定的,结果自然不确定。严格按 C 的语义判,这句话不成立。题库里这类题的判分口径有时会在"看初始化"和"看循环次数"之间摇摆,稳妥策略是:只要变量没有显式初始化就参与累加/累乘,优先怀疑它是错的,这也是编译器的思路。
第五道,F1-22:以下程序段的功能是计算 20 的阶乘。
int i; double product; product = 0; for (i = 1; i <= 20; i++) { product = product * i; /* 第一次循环就已经是 0 * 1 = 0 */ }答题思路:累乘的初值必须是 1,写成 0 之后整个循环恒为 0。这一类"累加初值 0、累乘初值 1"的配对要在读题第一秒就条件反射地检查。另外题干说"计算结果不超过双精度范围"时说明它考的是初值,没说时还要顺带想一下溢出——20 的阶乘在 double 范围内是装得下的,这不是失分点,但换成 int 就装不下。
3. 输入输出与字符:格式符不匹配,是这套题最大的火药桶
3.1 scanf 的格式符与变量类型必须逐一对齐
scanf 相关的判断题几乎是送分题和送命题的分界线。规则只有一条:转换说明必须和实参类型严格对应,%d对int*,%f对float*,%lf对double*,%c对char*。
#include <stdio.h> int main(void) { int money, year; double rate; /* 三个转换说明与三个实参类型必须一对一:int / int / double */ if (scanf("%d %d %lf", &money, &year, &rate) != 3) { return 1; /* 输入项数不够,直接退出,避免用未初始化的值 */ } printf("%d#%d#%.3f\n", money, year, rate); return 0; }这段代码故意把题库里错配的那版改对了。原题给的是scanf("%d %lf %d ", &money, &year, &rate);——%lf配给了 int 型的 year,%d配给了 double 型的 rate,两处类型都对不上,输入1001 3 0.025不可能得到1001#3#0.025。参数说明上要留意:%lf里的 l 是长度修饰符,专门给 double 用的;scanf 里%f只能配 float 的地址,这一点和 printf 不同——printf 的%f对 float 和 double 都能用(float 会先提升为 double),这是最容易被混淆的一处。
再看三道具代表性的题。
double x; scanf("%d", &x);输入 10,能否输出 10.00?不能。%d要求 int 指针,传 double 的地址属于类型不匹配,行为未定义,输出大概率是垃圾值而不是 10.00。
double x; scanf("%f", &x);输入 20,能否输出 20.00?同样不能,%f要的是 float 的地址,double 必须用%lf。
double x; scanf("x=%lf", &x);输入 30,能否输出 30.00?不能。格式串里的x=是普通字符,要求输入流里也出现x=,用户只敲 30 会导致匹配在第一个字符就失败,x 保持未初始化状态。这类题考的是"格式串里的非转换字符必须原样输入",属于必考点。
还有一道容易忽略的:scanf("%d %lf %d ", &money, &year, &rate);格式串末尾多了一个空格。这个空格会让 scanf 一直等待更多空白字符,输入不结束就卡住。判断题里凡是格式串首尾多出空格的,都要多想一秒。
3.2 printf 的精度控制与输出形态
printf 这边的失分点集中在"输出长什么样",不在"输出对不对"。
%.2f表示保留两位小数,会自动四舍五入;%4d表示至少占 4 个字符宽,右对齐补空格;%6.1f表示总宽 6 位、其中 1 位小数。程序阅读填空经常给出printf("%4d%6.1f\n", fahr, celsius);让你算某一行的输出,其实不用真算宽度,题目只问执行次数,宽度只是干扰信息。
真正要当心的是%c和%d的混用。字符可以用 printf 输出,用%c即可;字符也可以用 scanf 读入,用%c即可。判断题里"不能用 printf 输出字符""不能用 scanf 输入字符"这两种绝对化说法都是错的。
3.3 字符的本质是 ASCII 码,连续性要分清三种情况
字符这块判断题的正确率往往不高,因为题干在"连续"二字上做文章。三条结论必须分清:
小写字母'a'到'z'的 ASCII 码升序连续,大写字母'A'到'Z'也升序连续,这两条都对。但把大写和小写拼在一起说"按升序连续排列"就是错的——'Z'是 90,'a'是 97,中间隔着 `[ \ ] ^ _ `` 六个字符,不连续。
数字字符'0'到'9'是升序连续,不是降序。这个方向搞反的人不少。
大小写之间的差值稳定为 32:'a' - 'A' = 32。由此可以推出'D' - 'A' == 'd' - 'a'(都是 3),这条是对的;也可以推出'a'不是'Z'加 1('Z'加 1 是'['),这条是错的。
最容易栽的是这一条:数字字符'1'的值不是数字 1,而是它的 ASCII 码 49。字符和整数在 C 里可以互转,但'1'和1是两个完全不同的值。做字符统计类题目时,判断"是不是数字字符"必须写成ch >= '0' && ch <= '9',写成ch >= 0 && ch <= 9会把一堆控制字符算进去。
3.4 真题演练:三个字符题的标准解法
第一道,关于putchar('S');的输出。
问:执行后屏幕显示'S'对不对?错。putchar 输出的是字符本身,屏幕上显示的是 S,不带单引号。单引号是 C 源码里表示字符常量的语法符号,不参与输出。这类题的陷阱就是把源码写法和屏幕显示混为一谈。
第二道,关于连续读三个字符。
/* 变量已正确定义 */ ch = getchar(); putchar(ch);问:顺序输入三个字符'Q'(即敲 QQQ),输出是不是 Q?是。getchar 从输入缓冲区取走第一个字符 Q,putchar 立刻把它打出来,后面两个 Q 留在缓冲区里没被处理。这道题考的是"getchar 每次只吃一个字符",不是"输入了几个就输出几个"。
第三道,关于scanf("%c%c%c", &ch1, &ch2, &ch3); printf("%c", ch2);。
问:顺序输入三个字符 k,输出是不是 k?是。三个%c依次吃掉三个 k,ch2 拿到第二个,输出 k。看着简单,但如果中间加了空格,比如格式串写成"%c %c %c",情况就变了——格式串里的空格会匹配任意数量的空白字符,输入k k k和输入kkk的结果不同。判断题里凡是%c附近出现空格的,都要按这个规则重算一遍。
第四道,测试用例数量的估算题。
题干给一段三分支的 else-if:字母分支、数字分支、其他分支,问至少需要设计多少组测试用例。答案是把每个分支的边界都覆盖到:26 个小写 + 26 个大写 = 52 个字母,10 个数字字符,再加 1 个其他字符,合计 63 组。这类题的解法是"按条件边界枚举",不是随便估个数字。同理,一个三分支的 else-if 若涉及区间(小于 0、0 到 15、大于 15),需要 5 组:小于 0 一个、0 一个、0 到 15 中间一个、15 一个、大于 15 一个——边界值必须单独成组。
4. 流程控制:if 配对、switch 穿透、循环计数
4.1 if-else 的配对规则与"赋值当条件"
else 的配对规则只有一句话:else 与它前面最近的、尚未配对的 if 配对,与缩进无关。
int a = 2, b = -1, c = 2; if (a < b) /* 外层 if,条件为假 */ if (b < 0) /* 内层 if,挂在外层下面 */ c = 0; else /* 这个 else 属于内层 if,不属于外层 */ c++; printf("%d\n", c); /* 输出 2 */缩进骗人,但编译器只看语法结构。外层a < b是2 < -1,假,整个 if 语句整体跳过,内层 if 和它的 else 都不执行,c 保持 2。这道题的正确率一直不高,因为视觉上 else 像是和外层 if 对齐的。
赋值当条件是另一个高频陷阱。if (x = 0)不是判断 x 是否等于 0,而是把 0 赋给 x,表达式值为 0,为假,走 else 分支。更要命的是副作用:x 本身被改成了 0。题干如果说"执行后 x 的值不变",那就是错的。
关于测试用例的题目也要留意一个细节:省略 else 的 if 语句,比如只有if (grade < 60) printf("Fail\n");,要覆盖两个分支(执行和不执行),至少需要 2 组用例,取小于 60 和大于等于 60 各一个。题干如果说"至少需要 3 组(小于、大于、等于 60)",那是把边界值单独拆开算的保守说法,判分时按题库口径走——涉及边界条件的三分支结构,边界值要单独成组,这道题按 3 组算是站得住的。
4.2 switch:break、default 与等价性判断
switch 的规则可以压缩成四句话:case 后面必须跟常量表达式,不能跟变量或关系表达式;同一个 switch 里 case 的值不能重复;default 可有可无,位置随意;没有 break 就顺序往下执行,一直执行到 switch 结束或遇到 break。
int x = 1, a = 0, b = 0; switch (x) { case 0: b++; /* x 不等于 0,跳过 */ case 1: a++; /* 从这里进入,a 变成 1 */ case 2: a++; b++; /* 没有 break,继续穿透,a 变成 2,b 变成 1 */ } printf("a=%d,b=%d\n", a, b); /* 输出 a=2,b=1 */这段代码的三个 case 一个 break 都没有,从 case 1 进入后一路往下,这就是 switch 的穿透行为。凡是看到"case 后没有 break"的题,都按"从匹配点一直执行到底"来算。
case choice == 1:这种写法是错的——case 后面要的是常量,choice == 1是个关系表达式,结果只有 0 或 1,而且它本身不是常量表达式。判断题里给一段四个 case 全写成choice == 1、choice == 2的 switch,答案必错。
等价性判断是 2 分选择题的常客。判断两段 switch 是否等价,抓三点:case 值集合是否相同、每个分支的动作是否相同、default 的处理是否相同。看这道:
/* 版本 A:带 default */ switch (choice) { case 1: price = 3.0; break; case 2: price = 2.5; break; case 3: price = 4.0; break; case 4: price = 3.5; break; default: price = 0.0; break; } /* 版本 C:没有 default,前面多一句 price = 0.0 */ price = 0.0; switch (choice) { case 1: price = 3.0; break; case 2: price = 2.5; break; case 3: price = 4.0; break; case 4: price = 3.5; break; }这两个版本其实是等价的:choice 不在 1 到 4 之间时,A 走 default 把 price 置 0,C 靠预先赋 0 保持 0。真正不等价的是那种既没有 default、也没有预先赋初值的版本——此时 price 保持原值,行为取决于上下文,不能算等价。
再看一题:把 default 放在最前面但带着 break,与放在最后面,是等价的。default 的位置不影响结果,只影响"没匹配上时从哪一行开始执行",带了 break 就只执行它自己那一段。这个点经常被拿来出干扰项。
还有一题容易错:用 if 判断 op 不等于+、-、*时输出 Error,否则再进 switch 处理三个运算符——这与直接写带 default 的 switch 是等价的。判断关键在于"未匹配时的行为是否一致",两条路径都是打 Error,就等价。
4.3 for 循环:三个表达式各自的执行时机
for 的一般形式是for (表达式1; 表达式2; 表达式3) 循环体,执行顺序固定:表达式 1 只在进入循环时执行一次;表达式 2 在每次循环体执行前求值,为假就结束循环;表达式 3 在每次循环体执行后求值。
int fahr; double celsius; for (fahr = 91; fahr <= 100; fahr++) celsius = 5.0 * (fahr - 32) / 9.0; /* 循环体只有这一条,不需要花括号 */ printf("%4d%6.1f\n", fahr, celsius); /* 缩进骗人,这行在循环外,只执行一次 */这段代码对应题库里的 4-2,四个空分别问:语句①执行几次、语句②执行几次、循环体执行几次、循环结束时 fahr 的值。
- 循环体从 fahr = 91 开始,到 100 结束,共 10 次,所以语句①(循环体那条赋值)执行 10 次。
- 语句②是 printf 那一行,它没有花括号包进循环体,只在循环结束后执行 1 次。
- 循环体执行 10 次。
- 循环结束时 fahr 又做了一次自增,从 100 变成 101,此时条件 101 <= 100 为假,退出。
最终答案依次是 10、1、10、101。这道题的全部难点都在"printf 有没有被大括号包进去"这一个视觉判断上。
再看一道累加的:int i; double sum = 0; for (i = 2; i <= 4; i = i + 2) sum = sum + 1/i;,问 sum 是不是 0.75。不是。i 取 2 和 4,但1/i是整型除以整型,两次都是 0,sum 最终是 0。要得到 0.75 必须写成1.0/i或(double)1/i。这类题的核心永远是"分子分母是不是整型"。
还有一道int i, sum; sum = 0; for (i = 1; i <= 2; i++) sum = sum + 1.0/i;,问 sum 是不是 1.5。不是。右侧算出 1.5 没错,但 sum 声明成 int,赋值时被截断成 1。累加变量的类型和每一项的类型必须一起看。
4.4 真题演练:三道流程控制选择题的推理路径
第一道,2-7:以下程序段中错误的是。
四个选项都在算分段函数:x > 0 时 y = 1,x = 0 时 y = 0,x < 0 时 y = -1。逐个走:
选项 A 用if (x > 0) / else if (x == 0) / else,三分支完整,正确。选项 B 先y = 0,再用if (x > 0) y = 1; else if (x < 0) y = -1;,x = 0 时保持 0,正确。选项 D 用嵌套 if,外层判断x >= 0,内层判断x > 0,配两个 else,结构完整,正确。选项 C 写的是y = 0; if (x >= 0); if (x > 0) y = 1; else y = -1;——注意if (x >= 0);后面那个分号,它构成一条空语句,导致 x = 0 时会落到后面那个 if 的 else 上,y 被赋成 -1,与定义不符。答案选 C。
答题方法:这类题别从头到尾读一遍就选,直接把 x = 0 这一个特殊值代进去跑四个选项,能最快筛出错的。
第二道,2-10:为使输出 t = 4,输入的 a 和 b 应满足什么条件。
int a, b, s, t; scanf("%d,%d", &a, &b); s = 1; t = 1; if (a > 0) s = s + 1; /* a > 0 时 s 变成 2 */ if (a > b) t = s + t; /* 分支一 */ else if (a == b) t = 5; /* 分支二 */ else t = 2 * s; /* 分支三 */要 t = 4,逐分支倒推。分支一:t = s + 1,若 s = 2 则 t = 3,若 s = 1 则 t = 2,都得不到 4,排除。分支二直接给 5,排除。分支三:t = 2s,s = 2 时 t = 4,符合。s = 2 意味着 a > 0;走分支三意味着 a < b(既不是 a > b 也不是 a == b)。合起来就是 0 < a < b,答案 C。
答题方法:从目标值倒推分支,比正向枚举快得多。这类题还常考scanf("%d,%d", &a, &b)里的逗号——输入时必须以逗号分隔,写成空格分隔会读失败,题干没提就别自己加戏。
第三道,测试用例数量的计算器题。
题干给一段四分支的 else-if,处理+、-、*、/,其中/分支内部再分除数是否为 0,最后还有一个 else 兜底。问至少需要几组测试用例。数一下需要覆盖的路径:加、减、乘、除(除数非 0)、除(除数为 0)、未知运算符,共 6 条,答案 6。答题方法:按"能走到的叶子节点数"数,别按 if 的个数数。
5. 易错点:五道反复有人踩的题,错在哪、为什么错、怎么答对
5.1 循环体没有大括号,却把后面的语句当成循环体
错在哪:看到 for 后面缩进整齐的 printf,就默认它在循环里,把语句②的执行次数算成 10 次。
为什么错:C 的循环体只认"紧跟其后的一条语句",没写{}就只包含第一条。缩进对编译器完全无意义,printf 实际上在循环外。
怎么答对:读题时先找 for 后面第一个分号或第一条完整语句,标出循环体范围;只要循环体需要两条以上语句,就必须有{}。判断题里"循环体包括一条以上语句时必须用大括号组成复合语句"这句话是对的。
5.2 把=当==用,还算出"值不变"
错在哪:if (x = 20)被读成"如果 x 等于 20",于是判断条件真假,忽略了 x 被改写。
为什么错:C 里赋值是表达式,有值也有副作用。值参与条件判断,副作用改变变量本身,两件事同时发生。
怎么答对:扫到 if/while 括号里出现单个=,立刻做两个判断——条件值是多少(这里恒为 20,永真),变量被改成什么(变成 20)。凡是题干说"变量值不变"的,直接判错。同理,else if (x = 0)会让条件恒假、x 被清零,也别被"等于 0"的读法带偏。
5.3 累加/累乘没初始化,或者初值给反
错在哪:看到for (i = 1; i <= 20; i++) product = product * i;就认定是阶乘,没注意 product 初值是 0。
为什么错:累乘的初值必须是 1,写 0 之后每一步都是 0;累加的初值必须是 0,写成 1 会整体偏大。更隐蔽的是压根不初始化,此时结果取决于那个存储单元里的残留值。
怎么答对:读循环前先只找一件事——累加/累乘变量有没有在循环之前被显式赋值。没赋值就判错,赋错值也判错。判断题里凡是给一段求和/求积代码而不写初始化的,优先怀疑它是错的。
5.4 整数除法和浮点除法混淆,一项写错全题皆错
错在哪:sum = sum + 1/i;里 i 是 int,1 也是 int,算出 0 却没察觉,最后把 0 当成 0.75 之类的答案。
为什么错:C 的除法类型由两个操作数共同决定,只要两边都是整型就做整数除法,跟接收结果的变量是什么类型毫无关系。把结果赋给 double 只能保住"0"这个值,救不回被截掉的小数。
怎么答对:看到除号,先看两边类型,任一侧是浮点才做浮点除法。要改就改在分子上:1.0/i。同时检查接收变量的类型,int sum接1.0/i会被截断,两处都得对。
5.5 switch 里 case 值重复、或者 default 被当成必填项
错在哪:认为"switch 必须有 default",或者认为"两个 case 写同一个值只是冗余,不影响正确性"。
为什么错:default 的作用是兜底,语法上完全可选;case 的值必须在同一 switch 内唯一,重复会直接编译报错,不是"后者覆盖前者"。另外 case 后面必须是常量表达式,写case choice == 1:是拿关系表达式当标签,语法上不成立。
怎么答对:看到 switch 先查三件事——case 值有没有重复、case 后面是不是常量、default 有没有都行。判断题里"必须使用 default"必错,"每个 case 的值可以相同"必错,"可以根据需要使用或不使用 break"是对的。
6. 答题节奏:一套可以照抄的过题顺序
真正拉开差距的不是会不会,而是顺序。我的做法是把整份卷子切成三轮。
第一轮,只做 1 分判断题,每题限时 40 秒。拿不准的直接在题号上画圈跳过,不纠缠。这一轮的目标是把"一眼能定"的分先收进口袋,通常能拿下七成以上。
第二轮,攻 2 分选择题。四段代码的题先看题干问的是"正确"还是"错误"——这一步每年都有人看反。然后把选项里的代码按"变量初始化、类型匹配、循环边界"三个检查点过一遍,谁在这三处出问题就排除谁。等价性判断类的题,先比 case 值集合,再比 default 行为,两关都过才算等价。
第三轮,回头处理画圈的题和程序阅读填空。填空类先在草稿上列出循环三要素:
| 要素 | 要写下来的内容 | 常见坑 |
|---|---|---|
| 初值 | 起始值、累加变量初值 | 未初始化、累乘写成 0 |
| 条件 | 终止表达式、是否取等号 | <=与<差一次 |
| 步长 | 每次变化多少、何时执行 | 退出前还会再加一次 |
最后那个"退出前还会再加一次"是循环终值题的唯一难点:for (fahr = 91; fahr <= 100; fahr++)结束后 fahr 是 101 而不是 100,因为自增在条件判断之前就执行了。
押题方向上,我押三类:一是 scanf/printf 的格式符错配(尤其%f与%lf在 double 上的区别),二是 switch 无 break 的穿透结果,三是循环体范围与最终变量值。这三类在题库里反复出现,而且每次换个数字就能再考一遍。
从那以后我每次拿到判断题,都强制先默念一遍"看它问的是语法还是结果",再动笔。这个习惯帮我挡掉了至少一半的顺手选 T。希望帮到你。
本文还有配套的精品资源,点击获取