简介:这份《C语言考试题库》面向高校准备C语言期末复习的学生,也可供自学者检验语法基础。题库共305道并配详细解析,涵盖50道选择题以及填空题、判断题、读程序写结果和压轴编码大题,围绕函数与main入口、标识符命名规则、顺序、选择、循环结构、整型实型字符型、算术运算与条件表达式等高频考点展开;解析会点明易错概念,如大小写敏感、求余运算、强制类型转换与隐式类型提升,方便读者按题型定位薄弱环节。资源为单个PDF文件,大小约1.56MB,结构紧凑,便于打印或在手机、电脑上随时刷题。目前已有428人学习下载,适合考前集中查漏补缺、熟悉题型分布并训练程序阅读与编码书写能力。
1. C 语言期末复习的知识地图:305 道题拆开只有六个考点域
C 语言期末备考最容易走偏的一步,是把一份详解题库当成 305 道彼此独立的题去背。把答案和解析反推一遍就会发现:50 道选择、50 道填空、100 道判断,加上读程序写结果和压轴编程题,考察点高度集中在六个域——词法地基(标识符、数据类型、运算符与类型转换)、数组与字符串、函数与存储类别、结构体与自定义类型、指针与内存管理、编译流程与文件常识。这六块之间的关系不是并列关系:词法地基决定表达式类题能不能算对,数组与字符串决定一半判断题的对错,指针则是把前面几块串起来的枢纽。这份笔记适合已经上完课、想在一两周内把零散印象整理成系统结构的人,也适合每次做题总在同样几个地方丢分、却说不出原因的人。
2. 词法地基:标识符、数据类型与运算符的踩分点
词法部分是整份题库里最不应该丢分、又最容易因为粗心丢分的地方。它由三类题组成:判断一个字符串能不能当标识符、判断某种数据类型存不存在、判断一个表达式算出来是几。这三类题看起来分散,实际共用一套底层规则,把这套规则背下来,比做五十道同类题划算。
2.1 标识符判定:一条链走完所有变体
题库里关于标识符的选择题至少有七八道,形式各不相同,判定路径其实只有固定四步:先看是不是关键字,再看首字符是不是字母或下划线,再看后续字符是不是只含字母、数字、下划线,最后看有没有和库函数重名。按这个顺序走,任何选项都能在两秒内判掉。
| 候选写法 | 判定 | 卡在哪一步 |
|---|---|---|
a2_i | 合法 | 全部通过 |
_3d | 合法 | 下划线开头,C 允许 |
print | 合法 | 不是关键字,只是常见函数名 |
-a1 | 非法 | 首字符是减号,不是字母或下划线 |
3ax | 非法 | 数字开头 |
a[i] | 非法 | 含方括号 |
int | 非法 | int是关键字 |
case | 非法 | 多分支关键字 |
union | 非法 | 共用体关键字 |
while | 非法 | 循环关键字 |
%x | 非法 | %不属于合法字符集 |
a+b | 非法 | +是运算符,不是标识符字符 |
123 | 非法 | 全是数字 |
My->book | 非法 | 含->成员访问符 |
line# | 非法 | #属于预处理符号 |
His.age | 非法 | 含点号 |
I\am | 非法 | 含反斜杠 |
start$it | 非法 | 含美元符 |
有一类选项是「整组字符串都可以作标识符」,这时只要组里有一个关键字(比如while)就整组作废,不需要逐个检查。还有一类是pow、printf这种库函数名,语法上合法,但用作自定义标识符会遮蔽库声明,考试里一般算作「可用但不建议」。
#include <stdio.h> int main(void) { int a2_i = 1; /* 合法:字母开头,只含字母数字下划线 */ int _3d = 2; /* 合法:下划线开头,C 允许 */ /* int 3ax = 3; 非法:数字开头,编译期直接报错 */ /* int int = 4; 非法:int 是关键字 */ /* int a-b = 5; 非法:会被解析成 a 减 b 的表达式 */ printf("%d %d\n", a2_i, _3d); return 0; }注释掉的几行都属于编译期就失败的写法,考试时不需要真跑,只要在纸面上按四步链走一遍。真正需要记住的细节是:C 区分大小写,Main、MAIN都不是入口函数名,入口只能是main;标识符里不能出现中文标点,看起来像空格的字符往往是全角符号。
2.2 三种简单数据类型:C 里没有「逻辑型」
题库里反复出现的一道题是「C 语言的简单数据类型包括哪些」,正确答案只有整型、实型、字符型三类,逻辑型是干扰项。C 语言用整数 0 表示假、非 0 表示真,关系表达式和逻辑表达式的求值结果只可能是 0 或 1,这是判断题里「逻辑表达式的值一定是 0 或 1」被判为正确的依据。
| 类型 | 关键字 | 常见写法 | 需要记住的点 |
|---|---|---|---|
| 整型 | int | int a = 3; | 求余只对整型有效 |
| 单精度实型 | float | float f = 13.8f; | 字面量不加 f 会被当成 double |
| 双精度实型 | double | double d = 13.8; | 默认浮点字面量类型 |
| 字符型 | char | char c = 'A'; | 存的是 ASCII 码,本质是小整数 |
字符型能和整数一起运算,这是很多读程序题的考点:'A' + 32参与运算时取的是 65,结果是 97,用%d输出是 97,用%c输出是a。大小写字母之间正好差 32,小写a是 97,大写A是 65,这条 ASCII 常识在「C 语言不区分大小写」这类判断题里会反过来用一次。
2.3 运算符与隐式提升:为什么(int)f % 3等于 1
运算符这块的题眼不是优先级表,而是「什么时候发生类型提升、什么时候发生截断」。整数除整数,结果直接截断取整;表达式里只要出现一个浮点数,整型就会被提升成浮点参与计算;强制类型转换只改变这一次表达式的取值,不改变原变量的类型和值。
#include <stdio.h> int main(void) { int a = 3, b = 4; int m, n; float f = 13.8f; printf("%d\n", 11 / 3); /* 3:整数除法直接截断 */ printf("%f\n", 11.0 / 3); /* 3.666667:有浮点就按浮点算 */ printf("%d\n", (int)(11.0 / 3 + 0.5)); /* 4:加 0.5 再截断,模拟四舍五入 */ printf("%d\n", a < b ? a : b); /* 3:条件为真取问号后面那个 */ printf("%d\n", 2 % 5); /* 2:被除数小于除数,余数是被除数本身 */ printf("%d\n", 5 % 5); /* 0:整除,余数为零 */ n = (int)f % 3; /* 先 (int)f 得 13,再 13 % 3 得 1 */ printf("%d\n", n); m = (a = 4, 4 * 5); /* 逗号表达式取最后一个值,m 为 20 */ printf("%d %d\n", m, a); return 0; }这段代码基本覆盖了题库里运算符类题目的全部形态,几个参数值得单独说明。(int)(11.0 / 3 + 0.5)里的0.5是手动补偿量,不加就是 3;(int)f % 3和(int)(f % 3)完全不同,后者本身就非法,因为%的操作数必须是整型,编译器会直接拒绝;逗号表达式的值是最后一个子表达式的值,但前面a = 4的副作用照样发生,所以m是 20、a是 4。
提示:强制类型转换的优先级高于
%,所以(int)f % 3不需要额外加括号就已经是「先转换再取余」。真正需要括号的是把整个取余结果再转一次的场景。
三目运算符的规则也好记:条件 ? 表达式1 : 表达式2,条件为真取表达式 1,为假取表达式 2,嵌套时从右往左结合。题库里那几道a < b ? a : b的题,只要把 a、b 的值代进去就能立刻出结果,不需要分析优先级。
同级运算符的结合性也是填空题考点:算术、关系、逻辑这些同级运算都是自左向右,赋值和逗号是自右向左。题目问「如果一个运算对象两侧运算符优先级相同,按什么顺序执行」,答案就是自左向右,不要多写。
3. 数组与字符串:下标从 0 开始,字符串以 '\0' 收尾
数组类题目在题库里占比很高,原因在于它一次性考察了三个容易混淆的概念:长度必须是常量表达式、下标从 0 开始、字符串结尾多一个'\0'。三者中任何一个记反,都会连带错一片题。章节里那些「以下对一维数组 a 的正确说明是」的题,本质是在考第一点。
3.1 一维数组的三道门槛:定义、初始化、引用
定义的门槛是方括号里必须放常量表达式,初始化的门槛是必须用花括号,引用的门槛是下标不能等于长度。三个门槛各自对应一批错误写法,整理成对照表最省事。
| 场景 | 错误写法 | 错因 | 正确写法 |
|---|---|---|---|
| 定义 | char a(10); | 用了圆括号 | char a[10]; |
| 定义 | int a[]; | 没有给出长度 | int a[5]; |
| 定义 | int k = 5, a[k]; | 长度是变量不是常量 | #define N 5后int a[N]; |
| 初始化 | int a[5] = (0,1,2,3,4); | 用了圆括号 | int a[5] = {0,1,2,3,4}; |
| 初始化 | int a(5) = {}; | 定义形式就错了 | int a[5] = {0}; |
| 引用 | a[10](数组大小 10) | 下标越界 | a[9] |
| 引用 | a[3.5] | 下标必须是整型 | a[3] |
| 引用 | a(5) | 用了圆括号 | a[5] |
宏定义那一行值得多看一眼:#define N 10之后写int a[N];是合法的,因为预处理阶段N已经被替换成字面量 10,编译器看到的是常量。
#include <stdio.h> #define N 10 int main(void) { int a[N]; /* 合法:N 已被替换成常量 10 */ int b[3] = {0, 1, 2}; /* 合法:花括号初始化 */ /* int c[]; 非法:数组长度未知 */ /* int k = 5, d[k]; 非法:长度必须是常量表达式 */ a[0] = 100; printf("%d %d\n", a[0], b[2]); /* printf("%d\n", b[3]); 越界:编译多半不报错,运行结果不可预期 */ return 0; }越界这一条要特别标记:它属于运行期问题,编译器一般不会拦,程序可能打印出垃圾值、也可能直接崩,考试里凡是问「能否通过编译」的越界题,答案都是能通过。这一点在第 5 章还会再出现一次。
3.2 二维数组:第一维可省,第二维必须写
二维数组的规则只有一条需要死记:定义时可以省略第一维,第二维绝对不能省。原因是编译器按「总元素个数 ÷ 列数」反推行数,列数不知道就无从下手。
| 写法 | 是否合法 | 说明 |
|---|---|---|
int a[][3] = {1,2,3,4,5,6}; | 合法 | 反推出第一维为 2 |
int a[][3] = {{1,2,3},{4,5},{6,7}}; | 合法 | 三行,第一维为 3 |
int a[][] = {1,2,3,4,5,6}; | 非法 | 第二维缺失 |
int a[2][] = {1,2,3,4,5,6}; | 非法 | 第二维缺失 |
int a[2,3] = {1,2,3,4,5,6}; | 非法 | 二维数组要用两个方括号 |
int a[3][4];后访问a[2][4] | 非法 | 第二维最大下标是 3 |
引用方向的题喜欢考嵌套下标。int a[12] = {1,4,7,10,2,5,8,11,3,6,9,12};,当i = 10时求a[a[i]],从内向外算:a[10]是第 11 个数 9,再算a[9]是第 10 个数 6。这类题的通用解法是先写下标的对应关系,再逐层代入,不要在脑子里一次性算完。
字符型二维数组的题也是同一个套路。char x[][10] = {"Linux","windows","Mac"};中x[1][2]表示第二行第三个字符,第二行是windows,第三个字符是n。注意这里的「第三个」是从下标 0 数起的第三个,也就是下标 2。
3.3 字符数组与字符串:长度永远差一位
字符串是数组章节里最容易错的部分,核心只有一句:用字符串字面量初始化时,编译器会自动在末尾补一个'\0',而用字符逐个初始化时不会补。
#include <stdio.h> #include <string.h> int main(void) { char x[] = "hello"; /* 6 个字节:5 个字符 + '\0' */ char y[5] = {'h','e','l','l','o'}; /* 5 个字节,没有 '\0' */ char z[20]; printf("%zu %zu\n", sizeof(x), strlen(x)); /* 6 5 */ printf("%zu\n", sizeof(y)); /* 5 */ strcpy(z, x); /* 复制,连 '\0' 一起复制过去 */ strcat(z, "!"); /* 连接,目标数组必须有足够空间 */ printf("%s\n", z); /* hello! */ printf("%d\n", strcmp("abc", "abd")); /* 负数:第一个不同字符决定大小 */ return 0; }参数说明:sizeof是运算符,算的是数组占多少字节,包含结尾的'\0';strlen是函数,数到'\0'就停,不含'\0'。所以char a[] = "student";的数组长度是 8,而strlen(a)是 7。题库里「strlen 求出的长度包含'\0'」那道判断题是错的,原因就在这里。
strcat的参数顺序也要留意:第一个参数是目标,第二个
本文还有配套的精品资源,点击获取