简介:针对PTA理论考试整理的C语言知识点试题与答案,以Word文档形式提供,可直接搜索关键词快速定位,适合正在备考PTA或系统学习C语言基础的学生使用。文档收录了HW02、HW03等章节的判断题与选择题,覆盖编译预处理命令、main函数位置、语句结束符、变量声明、运算符优先级、自增自减、scanf/printf格式化输入输出、for循环与累加/阶乘等核心考点。每道题不仅给出T/F答案,还配有详细知识点讲解,例如单目运算符只需要一个操作数、赋值运算符优先级低于算术运算符、整数除法会舍去小数等,能帮助读者理解易混淆概念并避免常见错误。资源共1个docx文件,包体约345KB,轻量易下载。目前已有1895人学习,是C语言理论部分考前自测、复习和查漏补缺的实用资料。
1. 开场先说实话:PTA理论考不是考你会不会写代码
PTA 理论考表面上是判断对错和选择题,实际考的是“你能不能识破 C 语言里的反例”。比如那道经典题:#include <stdio.h>;是编译预处理命令。你要只记得“#include 是预处理命令”就会判 T,可仔细一看,后面多了个分号——预处理命令行根本不以分号结束。整场考试的逻辑就是这样:把“看起来对”的写法藏在题干里,让粗心的人丢分。拿分的关键不是多写程序,而是把常见陷阱背成条件反射。这份题库覆盖了编译预处理、变量定义、运算符、输入输出、for 循环、if-else、switch、ASCII 码,几乎把入门阶段所有判断题考点都过了一遍。适合正在刷 PTA 理论题准备期末考、补考的人,也适合面试前快速过一遍 C 语法边界。
2. 基础语法判断题:预处理命令、main 与表达式合法性
2.1 预处理命令和 main():三道必考的边界题
第一道高频题是#include <stdio.h>;是不是编译预处理命令。答案是 F。理由很简单:#include <stdio.h>这条预处理命令的结尾不需要分号,题干里那个分号是拿来钓鱼的。写成#include <stdio.h>;时,分号会成为一条多余的空声明,虽然某些编译器能放过它,但理论考试按教材标准判,预处理命令行不以分号结束,这题就是 F。
第二道是“任何一个程序都必须有而且只能有一个 main() 函数”。这题判 T。C 程序的入口就是 main,链接时也靠 main 定位;没有 main 的程序不能独立运行,多个 main 会直接报重定义错误。注意题干说的是“程序”,不是“函数库”,所以 T 没悬念。
第三道是“C 语言程序是从源文件的第一条语句开始执行的”。判 F。程序从 main 函数的第一条语句开始执行,不是源文件第一行。源文件开头往往是 #include、宏定义、全局变量声明,这些在编译阶段就处理完了,根本谈不上“执行”。这题就是送分题,但每次考试总有人把“编译”和“运行”搞混。
2.2 表达式合法性:声明顺序、隐式乘号、% 与整数除法
这组判断题最容易丢分,因为每一道都踩在一个具体的语法边界上。
k = 1; int k;符合 C 语言语法吗?答案是 F。变量必须先声明后使用。虽然 C99 之后允许在块中间声明变量,但“先使用后声明”依然不合法,因为编译器在处理k = 1时还没看到int k的声明。考试就按这个标准判。
int fahr;时,5(fahr-32)/9是符合语法的表达式吗?这也是 F,而且是高频翻车题。C 语言没有数学里的“隐式乘号”,5(fahr-32)会被解析成调用函数5,而 5 不是函数名,编译直接报错。正确写法是5 * (fahr - 32) / 9。看到数字后紧跟左括号,第一反应就应该是“缺乘号”。
double x;时,x % 2合法吗?F。取模运算符%只能用于整型操作数,double 是浮点型,必须写成fmod(x, 2)才对。这是运算符适用类型的经典考点。
还有一个容易被忽略的:int n;且 |n| > 1 时,1/n的值恒为 0。这题判 T,因为整数除法直接舍去小数部分,1/2得 0,1/(-2)也得 0。注意前提是 n 的绝对值大于 1,所以结果确实是 0 而不是什么“约等于”。
2.3 真题演练:赋值优先级、单目运算符与变量存储
来看三道判断题,考试经常连在一起出:单目运算符需要 2 个操作数吗?F。单目运算符只需要 1 个操作数,++、--、!、-都是单目。会选错的人是把“双目运算符”和“单目运算符”记反了,送分题变送命题。
若变量定义为 int x, y;,则 x + y = 22 是符合 C 语言语法的表达式,这题判 F。赋值号左边必须是变量,也就是“左值”,x + y是表达式的结果,不是可写的存储位置。考试里只要看到赋值号左边不是单个变量,直接判 F。
假设赋值运算符的优先级比算术运算符高,执行下面这段程序后 n 的值为 10,这也是 F。题干用了“假设”两个字,但 C 语言的真实规则是:赋值运算符的优先级低于算术运算符,所以n = 10 + 2先算加法再赋值,n 是 12。题目说“假设”,就是为了诱导你按错误优先级推出 n = 10。
最后注意C 程序中定义的变量,代表内存中的一个存储单元,这题判 T。变量的本质就是一段有名字的内存,声明变量就是向编译器申请存储空间。判断题里遇到这种“定义式”描述,只要没有绝对化限定词,通常就是 T。
3. 输入输出与 for 循环:格式串匹配、循环次数与初始化
3.1 类型不匹配的格式化输入:%d 写 double 会怎样
这一组题全是 scanf/printf 的格式串陷阱,考试出现率极高。先看第一道:
double x; scanf("%d", &x); printf("%.2f", x);输入 10,真的会输出 10.00 吗?答案是 F。%d期望的地址是int *,但&x是double *,类型不匹配。在内存层面上,scanf 按%d只写 4 个字节,而 double 占 8 个字节,printf 按%.2f读 8 个字节,读出来的数完全看内存脸色,根本不是 10.00。这类题叫“类型错位”,只要你看到格式说明符和变量类型对不上,直接判 F。
再看一个进阶版:
double x; scanf("%f", &x);输入 20,输出 20.00 吗?答案还是 F。很多人以为%f是“浮点数”,double 也是“浮点数”,就判了 T。但 C 语言里%f对应的是 float,double 必须用%lf。scanf 的%f只写 4 字节到 double 的前半段,输出时按 8 字节解读,结果照样是垃圾值。记住一句口诀:scanf 里 double 必须配%lf,printf 里%f和%lf都可以输出 double,但理论考试就按“严格匹配”判。
3.2 格式串里的普通字符:x=%lf 不是摆设
还有个特别容易翻车的题:
double x; scanf("x=%lf", &x);题干说“输入 30,输出 30.00”,对还是错?错。scanf 格式串里的x=不是提示符,而是要求你在键盘上原样敲出x=30这种输入。只输入 30 时匹配失败,x 保持未初始化状态,输出必然不是 30.00。这类题考的其实不是格式化输出,而是 scanf 的“普通字符必须原样输入”规则。
再看这一题:
int money, year; double rate; scanf("%d %lf %d", &money, &year, &rate);输入1001 3 0.025,会输出1001#3#0.025吗?F。格式串第三个%d对应的是 double 类型的 rate,类型错位导致读入的数据全部乱套:第一个%d读 1001 给 money,第二个%lf读 3 写入 year 的地址(覆盖 8 字节),第三个%d再读 0.025 只能读进去 0。输出结果和题干描述的完全对不上。判断这类题的技巧很简单:把格式串里的每个说明符和后面的变量逐个对齐,有一个对不上就是 F。
3.3 for 循环的初始化陷阱:没初始化就是随机数
这组题看起来是算数,实际考的是“循环之前的初始化”。
int i, sum; for (i = 1; i <= 10; i++) { sum = sum + i; }执行完 sum 是 55 吗?F。sum 根本没有初始化,它的初值是内存里的垃圾值,在这个垃圾值上累加,结果不可能是 55。正确写法是循环前加一句sum = 0。判断题里只要看到累加器没初始化,直接判 F,不用算。
再看阶乘题:
int i; double product; product = 0; for (i = 1; i <= 20; i++) { product = product * i; }这是计算 20 的阶乘吗?F。product 初始化为 0,任何数乘以 0 都是 0,循环结束后 product 还是 0。阶乘的初始化必须是 1,不是 0。这类题强调的是“初始值决定结果方向”,0 是累加的初始值,1 是累乘的初始值,混了就全错。
还有两道关于隐式类型转换的题,很阴险。第一道:
int i, sum; sum = 0; for (i = 1; i <= 2; i++) { sum = sum + 1.0 / i; }sum 的值是 1.5 吗?F。1.0/i算出来是 double,但赋值给 int 型 sum 时小数部分直接截断:第一次 1.0 截断成 1,第二次 0.5 截断成 0,sum 最终是 1,不是 1.5。这题坑在于你只关注了“1.0 能算出小数”,忘了左边的 sum 是 int。
第二道:
int i; double sum; sum = 0; for (i = 2; i <= 4; i = i + 2) { sum = sum + 1 / i; }sum 是 0.75 吗?F。1/i两个操作数都是 int,整数除法直接得 0,sum 加的是 0,最终结果就是 0。要算出 0.75 必须写1.0/i。记住:只要除号两边全是整数,结果就是整数,和赋值给谁没关系。
3.4 真题演练:循环次数与两道经典选择题
有一道填空题专门考循环次数,原题是:
int fahr; double celsius; for (fahr = 91; fahr <= 100; fahr++) celsius = 5.0 * (fahr - 32) / 9.0; /* 语句① */ printf("%4d%6.1f\n", fahr, celsius); /* 语句② */问语句①执行几次、语句②执行几次、循环体共执行几次、循环结束时 fahr 的值。答案是:10 次、1 次、10 次、101。关键在于:语句①是循环体,跑了 10 次;语句②在循环体外,只跑 1 次;循环结束时 fahr 先自增到 101,再判断 101 <= 100 为假退出。这种题只要不把 printf 看成循环体,基本不会错。
另一道高频选择题是前 N 项和,四个选项里只有一个是正确的:
int i, n; double sum; scanf("%d", &n); sum = 0; for (i = 1; i <= n; i++) { sum = sum + 1.0 / i; }正确选项要同时满足三个条件:sum 是 double(否则小数被截断)、sum 初始化成 0(否则累加垃圾值)、求和项写成1.0/i(否则整数除法全变 0)。三个条件缺一不可,看到哪个选项同时满足就选哪个。
阶乘选择题同理:
int i, n; double product; scanf("%d", &n); product = 1; for (i = 1; i <= n; i++) { product = product * i; }product 必须是 double(防溢出)且初始化成 1(不能是 0)。用 int 的选项、没初始化的选项、初始化成 0 的选项,全部排除。
4. 易错点集中营:else 配对、赋值误用与 switch 穿透
4.1 else 和谁配对:缩进骗不了编译器
C 语言规定:else 总是和之前最近的、不带 else 的 if 配对,缩进只是给人看的,编译器不看缩进。这个规则几乎每年必考,最经典的题长这样:
int a = 2, b = -1, c = 2; if (a < b) if (b < 0) c = 0; else c++; printf("%d\n", c);输出是几?很多人看到缩进以为 else 匹配外层 if(a < b),a < b 为假,所以 c 变成 1。但实际else匹配的是内层if(b < 0),if(a < b)为假时整个内层 if-else 都不执行,c 保持 2,输出 2。这题的坑就是缩进故意写成对齐外层,诱导你答错。
顺便记一个配对口诀:从内往外找,else 找离它最近的没配对的 if。考场上如果看到多层 if 嵌套,先把每对 if-else 用括号标出来,再跑程序。
4.2 if(x = 20):赋值当判断是命门
另一类高频易错题是把赋值号写在 if 条件里:
if (x = 20) { y = 1; } else { y = 0; }问执行后 x 的值变不变。答案是变。x = 20是赋值语句,不是比较,它把 20 赋给 x,然后整个表达式的值就是 20,非 0 即为真,直接进 then 分支。x 从原来的值变成了 20。判断题里只要看到 if 括号里是单等号,先判断“条件恒真”,再判断“变量被改值”。同理:
x = 4; if (x < 0) { y = -1; } else if (x = 0) { y = 0; } else { y = 1; }执行后 x 也不是原来的 4,而是被x = 0改成了 0,并且else if条件为假(0 为假),继续走到最后的 else,y = 1。所以“x 的值不变”是错的。这种题在 PTA 里重复率极高,看到条件里的=就要反应:这不是判断,是改写。
4.3 switch 分支穿透:没有 break 就一路到底
switch 的易错点集中在“穿透”和“case 语法”两件事上。先看穿透:
int x = 1, a = 0, b = 0; switch (x) { case 0: b++; case 1: a++; case 2: a++; b++; } printf("a=%d,b=%d\n", a, b);输出是 a=2,b=1。x 等于 1,从 case 1 开始执行:a 变成 1,然后没有 break,继续执行 case 2 的 a++、b++,a 变成 2,b 变成 1。这就是“穿透”:一旦命中某个 case,后续所有 case 的语句段都会执行,直到遇到 break 或 switch 结束。判断题里“case 语句后如没有 break,顺序向下执行”就是 T。
case 语法也是重点:case 后面必须是整型常量表达式,不能是变量,更不能是关系表达式。像case choice == 1:这种写法是非法的,因为choice == 1的结果是 0 或 1,但 case 要求的是编译期就能确定的常量,不是运行时比较。判断题“case 常量表达式的值可以相同”判 F,两个 case 值相同会导致编译冲突;“switch 必须使用 default”判 F,default 是可选的;“break 只能用于 switch 语句”判 F,break 还能用于循环。
4.4 真题演练:等价 switch 怎么判断
有一类选择题专门考“下面哪个 switch 语句与其它不等价”,核心看三点:第一,有没有 default;第二,default 缺省时有没有预先赋值;第三,case 分支的映射和 break 是否一致。
例如选项 A 是完整的 switch 带 default 给 price 赋 0.0;选项 B 把 default 放到了最前面,但 switch 匹配时 default 只在“所有 case 都不匹配”时执行,位置不影响结果,所以 A 和 B 等价;选项 C 没有 default 也没有提前赋初值,当 choice 不在 1~4 时 price 保持垃圾值,和 A 不等价;选项 D 先写price = 0.0;再写 switch,即使没有 default,不匹配时 price 也有兜底值 0.0,与 A 等价。所以答案是缺 default 的那一项。
这类题不要一上来硬跑,先看“不匹配时的默认行为”。如果 switch 外面有赋初值,等价于 default;如果既没有 default 也没有赋初值,那它和别的选项一定不等价。再看 break:去掉一个 case 的 break 会让该 case 穿透到下一个,行为立刻改变。
还有一道符号函数的分支题值得单独说:
y = 0; if (x >= 0); if (x > 0) y = 1; else y = -1;前面那个if (x >= 0);末尾多了个分号,整个 if 语句变成了“条件成立就执行空语句”,后面那对 if-else 和它没有任何关系。当 x = 0 时,先 y = 0,然后第二个 if 判断 x > 0 为假,执行 else y = -1,最终 y = -1,而函数要求 x = 0 时 y = 0。这题的教训是:看到 if 后面紧跟分号,先想“这分号是不是把 if 架空了”。
5. 字符与 ASCII:三个记忆锚点与分支测试用例题
5.1 记住三个锚点:'0'=48,'A'=65,'a'=97
字符型判断题的核心是记住 ASCII 码的三个锚点,再配合“连续性”来判断对错。先看这个记忆表:
| 字符 | ASCII 码 | 说明 |
|---|---|---|
| '0' | 48 | 数字字符起点 |
| '9' | 57 | 数字字符终点 |
| 'A' | 65 | 大写字母起点 |
| 'Z' | 90 | 大写字母终点 |
| 'a' | 97 | 小写字母起点 |
| 'z' | 122 | 小写字母终点 |
基于这张表,判断题可以直接秒答:数字字符 '0'~'9' 的 ASCII 码按升序连续排列,所以“按降序排列”判 F;大写字母 'A'~'Z' 按升序连续排列,判 T;大写 'M' 的 ASCII 码比小写 'm' 小,判 F,因为所有大写字母(65~90)都小于所有小写字母(97~122)。
最容易出错的题是“大小写字母连起来按升序连续排列”,判 F。因为 'Z' 的 90 和 'a' 的 97 中间还隔着 91~96 六个字符([、\、]、^、_、`),并不是紧挨着的。同理,“小写 'a' 是大写 'Z' 加 1”也是 F,实际是加 7。至于“数字字符 '1' 的值就是数字 1”,判 F,'1' 的 ASCII 码是 49,不是 1。记住:字符常量的值是它的 ASCII 码,不是它看起来的数字。
还有一道很刁的题:'D' - 'A' == 'd' - 'a'的值是真是假?T。左边等于 3,右边也等于 3。只要两个字母在大写集合和小写集合里的相对偏移一致,差值就相等。
5.2 字符输入输出:%c、putchar、getchar
字符的输入输出也是判断题常客。第一类:不能用 printf 输出字符、不能用 scanf 输入字符,都判 F,%c就是干这个的。第二类:putchar('S') 在屏幕上显示的是 'S',判 T,putchar 就是单字符输出函数,和 printf("%c", 'S') 效果一致。
第三类是 getchar 的读取:
ch = getchar(); putchar(ch);顺序输入三个字符 'Q',输出的是哪个?答案是第一个 Q。getchar 一次只读一个字符,后面输入的两个字符还在缓冲区里没被读取。这道题考验的是对“getchar 每次读一个”的理解,输入三个不代表全部被消费。
类似的还有:
scanf("%c%c%c", &ch1, &ch2, &ch3); printf("%c", ch2);输入三个 'k',输出 k。这个就是按顺序读入三个字符,然后 printf 输出第二个字符,一个萝卜一个坑。判断题里只要格式串的 %c 数量和变量数量对齐,顺序对上,答案就是 T。
5.3 分支测试用例:每个分支至少一组,不是越多越好
这一组题问的是“为了检查分支,至少需要设计几组测试用例”。核心原则是分支覆盖:每个分支至少被一组测试用例走到,边界值要不要单独测,要看题目有没有要求“边界测试”。
单分支的 if 语句最少要 2 组:一组走路进分支的条件,一组走不进分支的条件。所以“检查 if(grade < 60) 至少要 3 组(小于、大于、等于 60)”判 F,大于等于 60 都走同一个分支,两组就够了。
三分支的嵌套 if 或 else-if,最少 3 组:每个分支一组。所以“嵌套 if 三分支至少 3 组”判 T,而“else-if 三分支至少 5 组”判 F——5 组是把边界值 x=0、x=15 都单独列出来了,但“至少”只需要 3 组。
最夸张的是字母数字判断那道题,三个分支分别是字母、数字、其他,至少 3 组用例就够了,题干说“至少 63 组”,判 F。这类题的套路是:先数分支数,再判断题干给的数字是否等于或大于分支数。大于分支数且题面强调“至少”,基本就是 F。
6. 冲刺答题模板:T/F 四步法与选择题代入法
6.1 遇到判断题,按四步走
我自己刷题的经验是,把判断题当成“找反例”游戏,固定走四步:先看题面有没有绝对化词,像“所有”“必须”“只能”“恒为”“至少”,这些词越多,是 F 的概率越大;再看语法细节,比如分号是不是多余、乘号有没有漏、判断用的是=还是==、字符串用的是双引号还是单引号;然后跑一遍执行流程,特别是循环次数和 switch 穿透,不要凭感觉;最后如果题里有“假设”两个字,先怀疑假设是否成立,像“假设赋值优先级比算术高”这种说法直接判 F。
遇到计算题,第一反应不是算,而是检查变量初始化。累加器没初始化,算出来的答案就是垃圾;阶乘初始化为 0,结果一定是 0;除号两边都是整数,小数直接被截断。这三个检查点能挡住大部分陷阱。
6.2 选择题先排除再代入
选择题的套路和判断题不同,优先用排除法。像“计算前 N 项和”的选项,先排除 sum 类型是 int 的,再排除 sum 没初始化的,最后排除1/i写成整数除法的,剩下的就是正确答案。阶乘题同理,一个选项同时错在“product 初始化为 0”,直接划掉。
switch 等价类选择题,固定看三个点:有没有 default、缺省 default 时有没有预赋值、case 分支有没有 break。三个点都一致才等价,有一个不一致就是答案。这类题不需要跑每个分支,只需要对比“匹配之外的默认行为”。
6.3 考前一天怎么过
我当年刷理论题库有个习惯:先把所有判断题做一遍,做完不看对错,而是把每道题当例题重新讲一遍理由,讲不出来的就标红;第二遍只看标红的题,把反例背熟。选择题只练两类,一类是“计算前 N 项和/阶乘”这种程序填空,一类是“switch 等价”这种对比题,这两类是题库里最稳定的考点。
从那以后,我每次考前都会强制自己走一遍“找绝对词、查语法细节、跑流程、验假设”四步,理论考试基本没再翻过车。理论考不难,难的是你总觉得自己会。把这套判断流程练熟,做题速度和对率都会明显上一个台阶,希望帮到你。
本文还有配套的精品资源,点击获取