exam-87 试卷整理与详解
这份笔记是根据 87.pdf 整理出来的,原卷文件在本地路径:
/Users/wff/Downloads/87.pdf这套卷子本身已经标出了一部分答案,我在整理时做了二次核对。个别位置有 OCR 识别误差,尤其是引号、分号、文件打开模式、逻辑运算符,我已经按 C 语言正确写法整理。
对新手来说,这套卷子非常适合复习下面这些内容:
- 函数定义、函数调用、递归
- 字符串比较、复制、连接
- 一维数组、二维数组初始化
- 数组下标和二维数组行优先存储
- 指针和数组名作为函数参数
- 文件读写基础
- 宏、结构体、表达式优先级
- 改错题和程序填空题的常见坑
1. 答案速查
Section titled “1. 答案速查”1.1 选择题答案
Section titled “1.1 选择题答案”| 题号 | 答案 |
|---|---|
| 1 | C |
| 2 | B |
| 3 | A |
| 4 | B |
| 5 | C |
| 6 | A |
| 7 | C |
| 8 | A |
| 9 | B |
| 10 | C |
| 11 | B |
| 12 | B |
| 13 | A |
| 14 | B |
| 15 | D |
| 16 | A |
| 17 | C |
| 18 | C |
| 19 | B |
| 20 | B |
| 21 | B |
| 22 | A |
| 23 | A |
| 24 | B |
| 25 | B |
1.2 填空题答案
Section titled “1.2 填空题答案”| 题号 | 答案 |
|---|---|
| 1 | 1 |
| 2 | "bi.dat", "w"、fclose(fp); |
| 3 | B 66 |
| 4 | 6 |
| 5 | 0 |
| 6 | 114, 124, -1 |
| 7 | 1 |
| 8 | 11 |
| 9 | 行 |
| 10 | 22 |
1.3 判断题答案
Section titled “1.3 判断题答案”| 题号 | 答案 |
|---|---|
| 1 | N |
| 2 | T |
| 3 | N |
| 4 | T |
| 5 | N |
| 6 | N |
| 7 | T |
| 8 | T |
| 9 | T |
| 10 | N |
2. 选择题详解
Section titled “2. 选择题详解”选择题第 1 题
Section titled “选择题第 1 题”题目问:以下正确的函数首部形式是哪一个?
答案:C
正确形式:
double fun(int x, int y)详细解析:
函数首部用于函数定义时,后面紧跟函数体,所以末尾不写分号。
double fun(int x, int y){ return x + y;}选项 A:
double fun(int x, int y);这是函数声明,也叫函数原型,不是函数定义里的函数首部。
容易踩坑点:
- 把“函数声明”和“函数定义首部”混为一谈。
- 形参
int x, y也是错的,C 语言里每个形参都要单独写类型。
给新手的建议:
- 函数声明通常有分号。
- 函数定义的函数首部后面跟
{},不写分号。
选择题第 2 题
Section titled “选择题第 2 题”题目问:当 s1 所指字符串大于 s2 所指字符串时,执行语句 S,应该怎么写?
答案:B
正确写法:
if (strcmp(s1, s2) > 0) S;详细解析:
字符串不能直接用 > 比较内容。
s1 > s2比较的是两个指针地址,不是字符串大小。
strcmp(s1, s2) 的结果规则是:
- 返回值大于
0:s1大于s2 - 返回值等于
0:两个字符串相等 - 返回值小于
0:s1小于s2
容易踩坑点:
- 用
s1 > s2比较字符串。 - 只写
strcmp(s1, s2),这样只能判断“不相等”,不能判断谁大。
给新手的建议:
- 字符串比较内容用
strcmp。 - 字符串复制用
strcpy。 - 字符串连接用
strcat。
选择题第 3 题
Section titled “选择题第 3 题”题目问:以下能对一维数组 a 正确初始化的是哪一个?
答案:A
正确写法:
int a[10] = {0};详细解析:
{0} 表示把第一个元素初始化为 0,剩余元素自动补 0。
所以这个数组实际效果是:
0 0 0 0 0 0 0 0 0 0其他选项的问题:
int a[n]在传统教材考试里,数组长度通常要求是常量表达式。- 初始化数组要用
{},不能用()。 {后面必须有完整的初始化列表,不能只写半截。
容易踩坑点:
- 看到
{0}以为只有第一个元素有值。
给新手的建议:
int a[10] = {0};是考试和实际写代码里都很常见的“全 0 初始化”写法。
选择题第 4 题
Section titled “选择题第 4 题”题目问:以下数组定义中不正确的是哪一个?
答案:B
错误写法:
int d[3][] = {{1, 2}, {1, 2, 3}, {1, 2, 3, 4}};详细解析:
二维数组定义时,第二维必须明确。
例如:
int d[][4] = {{1, 2}, {1, 2, 3}, {1, 2, 3, 4}};这样才可以,因为编译器知道每一行有 4 列。
容易踩坑点:
- 误以为二维数组只要写第一维就行。
给新手的建议:
- 二维数组初始化时,可以省略第一维,不能省略第二维。
选择题第 5 题
Section titled “选择题第 5 题”题目整理:
long fib(int n){ if (n > 2) return fib(n - 1) + fib(n - 2); else return 2;}
printf("%ld\n", fib(3));答案:C
详细解析:
先看递归出口:
fib(1) = 2fib(2) = 2所以:
fib(3) = fib(2) + fib(1) = 2 + 2 = 4输出结果是:
4容易踩坑点:
- 把这题当成普通斐波那契数列,直接套
1, 1, 2, 3。 - 忽略本题的递归出口返回的是
2,不是1。
给新手的建议:
- 递归题永远先看“什么时候停”。
- 不要背默认规律,要按题目代码一步一步代。
选择题第 6 题
Section titled “选择题第 6 题”题目问:与实际参数为实型数组名相对应的形式参数不可以定义为什么?
答案:A
错误写法:
float a;详细解析:
如果实参是数组名,比如:
float x[10];fun(x);那么传过去的是数组首元素地址,形参应该写成下面这种形式:
void fun(float a[])void fun(float *a)如果是二维实型数组,也可能写成:
void fun(float (*a)[3])但 float a 只是一个普通浮点变量,不能接收数组名。
容易踩坑点:
- 把数组参数当成普通变量。
给新手的建议:
- 一维数组作函数参数时,优先记住两种等价写法:
float a[]和float *a。
选择题第 7 题
Section titled “选择题第 7 题”题目问:以下不能正确进行字符串赋初值的是哪一个?
答案:C
错误写法:
char str[5] = "good!";详细解析:
字符串 "good!" 有 5 个可见字符:
g o o d !但字符串末尾还需要一个结束标志:
'\0'所以至少需要 6 个字符空间。
正确写法可以是:
char str[6] = "good!";char str[] = "good!";容易踩坑点:
- 只数可见字符,忘记
'\0'。
给新手的建议:
- 字符串初始化字符数组时,数组长度至少要等于“可见字符数 + 1”。
选择题第 8 题
Section titled “选择题第 8 题”题目问:以下对二维数组 a 的正确说明是哪一个?
答案:A
正确写法:
double a[1][4];详细解析:
二维数组的基本格式是:
类型名 数组名[行数][列数];其他选项的问题:
float a(3)(4)不是数组定义。int a[3][]第二维省略,错误。float a(3,4)也不是数组定义。
容易踩坑点:
- 把数学里的括号写法带到 C 语言数组里。
给新手的建议:
- C 语言数组下标用
[],不是()。
选择题第 9 题
Section titled “选择题第 9 题”题目整理:
char s1[] = "abc", s2[20], *t = s2;gets(t);问:当 s1 大于 s2 时输出 s2,应该怎么写?
答案:B
正确写法:
if (strcmp(s1, t) > 0) puts(s2);详细解析:
这里:
t = s2;所以 t 指向的就是 s2 的首地址。
因此:
strcmp(s1, t)就等价于比较:
strcmp(s1, s2)容易踩坑点:
- 忘记
t和s2指向同一段字符数组。 - 写成
strcmp(s2, t),这相当于自己和自己比较,结果是0。
给新手的建议:
- 指针题先画箭头:
t -> s2[0]。
选择题第 10 题
Section titled “选择题第 10 题”题目问:字符串的结束符是什么?
答案:C
正确答案:
'\0'详细解析:
'\0' 是空字符,ASCII 值为 0,用于标记字符串结束。
要注意下面几个东西不一样:
'0' // 字符 0,ASCII 值是 48'\0' // 空字符,ASCII 值是 0"0" // 字符串,包含 '0' 和 '\0'"\0" // 字符串,包含一个 '\0'容易踩坑点:
- 把
'0'和'\0'混淆。
给新手的建议:
- 字符串结束符永远记
'\0',中间有反斜杠。
选择题第 11 题
Section titled “选择题第 11 题”题目整理:
int a[][4] = {0, 0};问:下面不正确的叙述是哪一个?
答案:B
详细解析:
二维数组第二维是 4,一共给了 2 个初值,所以第一维可以推断为 1。
实际数组是:
0 0 0 0因为数组初始化时,没写到的元素会自动补 0。
选项 B 说“只有 a[0][0] 和 a[0][1] 得到初值 0,其余元素得不到初值 0”,这是错的。
容易踩坑点:
- 以为没显式写出来的元素就是随机值。
给新手的建议:
- 数组初始化时,只要写了初始化列表,没写到的元素通常自动补
0。
选择题第 12 题
Section titled “选择题第 12 题”题目整理:
char a[10];问:哪句不能从键盘给数组 a 输入值?
答案:B
错误写法:
a = getchar();详细解析:
a 是数组名,不能放在赋值号左边整体赋值。
而且 getchar() 只能读取一个字符,不可能直接填满整个数组。
下面几种写法在考试语境里都可以理解为输入字符数组:
for (i = 0; i < 10; i++) a[i] = getchar();
gets(a);scanf("%s", a);补充提醒:
gets在现代 C 语言中已经不推荐使用,因为容易越界。- 考试里出现
gets,通常只是考字符串输入概念。
容易踩坑点:
- 把字符数组
a当成一个普通字符变量。
给新手的建议:
- 数组名不是普通变量,不能写
a = ...。
选择题第 13 题
Section titled “选择题第 13 题”题目问:以下正确的说法是哪一个?
答案:A
正确说法:
如果函数返回值类型和 return 后表达式类型不一致,最终以函数定义的返回类型为准。
例如:
int fun(void){ return 3.14;}这里函数返回类型是 int,所以 3.14 会被转换成 3 返回。
容易踩坑点:
- 以为
return后面是什么类型,函数最终就返回什么类型。
给新手的建议:
- 看函数返回值类型,先看函数名前面的类型。
选择题第 14 题
Section titled “选择题第 14 题”题目整理:
int func(int a, int b){ return a + b;}
int x = 2, y = 5, z = 8, r;r = func(func(x, y), z);printf("%d\n", r);答案:B
详细解析:
先算里面:
func(x, y) = func(2, 5) = 7再算外面:
func(7, z) = func(7, 8) = 15所以输出:
15容易踩坑点:
- 函数嵌套调用时,不知道先算哪一层。
给新手的建议:
- 嵌套函数调用先从最里面开始算。
选择题第 15 题
Section titled “选择题第 15 题”题目整理:
int n[2] = {0}, i, j, k = 1;
for (i = 0; i <= k; i++) for (j = 0; j <= k; j++) n[j] = n[i] + 1;
printf("%d\n", n[k]);答案:D
详细解析:
初始状态:
n[0] = 0n[1] = 0k = 1循环过程:
| i | j | 执行语句 | 结果 |
|---|---|---|---|
| 0 | 0 | n[0] = n[0] + 1 | n[0] = 1 |
| 0 | 1 | n[1] = n[0] + 1 | n[1] = 2 |
| 1 | 0 | n[0] = n[1] + 1 | n[0] = 3 |
| 1 | 1 | n[1] = n[1] + 1 | n[1] = 3 |
最后输出:
n[k] = n[1] = 3容易踩坑点:
- 没注意数组元素在循环中已经被更新。
- 以为
n[i]一直是初始值。
给新手的建议:
- 数组循环赋值题,最好画一个表格记录每一步的变化。
选择题第 16 题
Section titled “选择题第 16 题”题目整理:
int x[3][3] = { {1, 2, 3}, {4, 5, 6}, {7, 8, 9}};
for (i = 0; i < 3; i++) printf("%d, ", x[i][2 - i]);答案:A
详细解析:
逐次代入:
| i | 2 - i | 访问元素 | 值 |
|---|---|---|---|
| 0 | 2 | x[0][2] | 3 |
| 1 | 1 | x[1][1] | 5 |
| 2 | 0 | x[2][0] | 7 |
所以输出:
3, 5, 7,容易踩坑点:
- 二维数组下标从
0开始。 - 把
x[i][2-i]看成固定列。
给新手的建议:
- 二维数组题先画成表格,再代下标。
选择题第 17 题
Section titled “选择题第 17 题”题目整理:
exce((v1, v2), (v3, v4, v5), v6);问:实参个数是多少?
答案:C
详细解析:
最外层参数有 3 个:
(v1, v2)(v3, v4, v5)v6
括号里面的逗号是逗号表达式的一部分,不是函数参数分隔符。
容易踩坑点:
- 看见逗号就直接数,结果把括号内的逗号也算进去了。
给新手的建议:
- 数函数实参个数,只看最外层逗号。
选择题第 18 题
Section titled “选择题第 18 题”题目整理:
char a1[] = "abc", a2[80] = "1234";问:把 a1 串连接到 a2 串后面,应该怎么写?
答案:C
正确写法:
strcat(a2, a1);详细解析:
strcat(目标串, 源串) 的意思是:
把源串接到目标串后面所以:
strcat(a2, a1);执行后 a2 变成:
1234abc容易踩坑点:
- 把
strcat(a1, a2)写反。
给新手的建议:
strcpy和strcat都是“第一个参数被改变”。
选择题第 19 题
Section titled “选择题第 19 题”题目问:以下不能正确定义二维数组的是哪一个?
答案:B
错误写法:
int a[2][] = {{1, 2}, {3, 4}};详细解析:
二维数组第二维不能省略。编译器必须知道每一行有几个元素,才知道如何计算 a[i][j] 的位置。
正确写法:
int a[][2] = {{1, 2}, {3, 4}};int a[2][2] = {{1, 2}, {3, 4}};容易踩坑点:
- 以为已经写了初值,第二维就可以不写。
给新手的建议:
- 二维数组的“列数”一定要明确。
选择题第 20 题
Section titled “选择题第 20 题”题目整理:
int a[3][4] = {0};答案:B
详细解析:
这个初始化会让数组中每个元素都是 0。
可以理解成:
0 0 0 00 0 0 00 0 0 0容易踩坑点:
- 以为只有
a[0][0]是 0。
给新手的建议:
= {0}对数组来说就是非常常见的“全部初始化为 0”。
选择题第 21 题
Section titled “选择题第 21 题”题目问:以下能对二维数组 a 进行正确初始化的是哪一个?
答案:B
正确写法:
int a[][3] = {1, 2, 3, 4, 5};详细解析:
第二维是 3,所以每行放 3 个元素:
1 2 34 5 0第一维可以根据初值个数自动推断出来。
其他选项的问题:
int a[][]两维都省略,错误。int a[2][]第二维省略,错误。int a[2][3]只能放 6 个元素,却给了 7 个,错误。
容易踩坑点:
- 不知道“第一维可省,第二维不可省”。
给新手的建议:
- 二维数组初始化时,先看列数有没有写出来。
选择题第 22 题
Section titled “选择题第 22 题”题目整理:
int a[3][4];问:对 a 数组元素的正确引用是哪一个?
答案:A
正确写法:
a[1 + 1][0]详细解析:
a[3][4] 的合法下标是:
第一维:0 1 2第二维:0 1 2 3a[1 + 1][0] 等价于:
a[2][0]这是合法的。
容易踩坑点:
a[2][4]第二维越界,因为最大只能到3。a(2)(1)不是 C 语言数组访问写法。a[1,3]不是二维数组元素访问,逗号表达式会让它变得很容易出错。
给新手的建议:
- 二维数组元素访问必须写成
a[i][j]。
选择题第 23 题
Section titled “选择题第 23 题”题目整理:
char array[] = "China";问:数组 array 占多少空间?
答案:A
详细解析:
"China" 有 5 个可见字符:
C h i n a字符串末尾还会自动加一个 '\0'。
所以数组实际有 6 个字符:
'C' 'h' 'i' 'n' 'a' '\0'占 6 个字节。
容易踩坑点:
- 忘记字符串结束符
'\0'。
给新手的建议:
- 字符串数组空间 = 可见字符数 + 1。
选择题第 24 题
Section titled “选择题第 24 题”题目整理:
static char str[10] = "China";问:数组元素个数是多少?
答案:B
详细解析:
数组定义中已经明确写了:
str[10]所以数组元素个数就是 10。
"China" 只决定前面几个元素的初值,不改变数组长度。
容易踩坑点:
- 把字符串长度当成数组长度。
给新手的建议:
- 题目问“数组元素个数”,优先看方括号里的长度。
选择题第 25 题
Section titled “选择题第 25 题”题目整理:
int a[3][4];问:非法引用是哪一个?
答案:B
非法写法:
a[0][4]详细解析:
第二维长度是 4,合法下标只能是:
0 1 2 3所以 a[0][4] 越界。
容易踩坑点:
- 看到长度是 4,就以为下标也能写 4。
给新手的建议:
- 数组最后一个下标永远是“长度 - 1”。
3. 填空题详解
Section titled “3. 填空题详解”填空题第 1 题
Section titled “填空题第 1 题”题目整理:
a = 3, b = 4, c = 4a + b > c && b == c && a || b + c && b == c答案:1
详细解析:
先按优先级拆开:
(a + b > c) && (b == c) && a || (b + c) && (b == c)逐个计算:
a + b > c -> 3 + 4 > 4 -> 真b == c -> 4 == 4 -> 真a -> 3 -> 真b + c -> 8 -> 真b == c -> 真所以整体为真,C 语言中真通常用 1 表示。
容易踩坑点:
- 不熟悉
&&和||的优先级。 - 忘记非 0 就是真。
给新手的建议:
- 逻辑表达式不会算时,先手动加括号。
填空题第 2 题
Section titled “填空题第 2 题”题目要求:把从终端读入的文本复制到新文件 bi.dat 中,用 @ 作为结束标志。
答案:
fp = fopen("bi.dat", "w");...fclose(fp);整理后的代码:
#include <stdio.h>#include <stdlib.h>
FILE *fp;
int main(void){ char ch;
if ((fp = fopen("bi.dat", "w")) == NULL) exit(0);
while ((ch = getchar()) != '@') fputc(ch, fp);
fclose(fp); return 0;}详细解析:
fopen("bi.dat", "w"):以写入方式打开文件,如果文件不存在则创建。getchar():从键盘读一个字符。fputc(ch, fp):把字符写入文件。fclose(fp):关闭文件。
补充说明:
原卷标注里文件模式可能显示成大写 W,但标准 C 语言中文件打开模式一般写小写 "w"。
容易踩坑点:
- 文件模式字符串忘记写双引号。
- 写完文件后忘记
fclose(fp);。
给新手的建议:
- 文件题先记住三步:打开文件、读写文件、关闭文件。
填空题第 3 题
Section titled “填空题第 3 题”题目整理:
char ch = 'B';printf("%c %d\n", ch, ch);答案:B 66
详细解析:
已知字符 'A' 的 ASCII 码是 65,所以:
'B' = 66%c 按字符输出,%d 按整数输出。
所以输出:
B 66容易踩坑点:
- 忘记格式串中
%c和%d中间有一个空格。
给新手的建议:
- 同一个字符变量既可以按字符看,也可以按 ASCII 码值看。
填空题第 4 题
Section titled “填空题第 4 题”题目整理:
int a[5] = {1, 3, 5, 7, 9}, *p;p = &a[2];问:++(*p) 的值是多少?
答案:6
详细解析:
p = &a[2],所以 p 指向 a[2]。
数组中:
a[2] = 5++(*p) 的意思是:
先把 *p 加 1,再取这个表达式的值所以 5 变成 6,表达式的值也是 6。
容易踩坑点:
- 看不懂
*p和++的结合。
给新手的建议:
- 看到
p = &a[2],就在旁边写一句:*p就是a[2]。
填空题第 5 题
Section titled “填空题第 5 题”题目整理:
a = 13;b = 6;!a答案:0
详细解析:
在 C 语言中:
0表示假- 非
0表示真
因为 a = 13 是非 0,所以 a 为真。
!a 就是假,结果为 0。
容易踩坑点:
- 以为
!a是把数字变成负数。
给新手的建议:
!是逻辑非,不是数学里的负号。
填空题第 6 题
Section titled “填空题第 6 题”题目整理:
int x = 6, y, z;
x *= 18 + 1;printf("%d, ", x--);
x += y = z = 11;printf("%d, ", x);
x = y == z;printf("%d\n", -x++);答案:114, 124, -1
详细解析:
第一步:
x *= 18 + 1;等价于:
x = x * 19;所以:
x = 6 * 19 = 114第二步:
printf("%d, ", x--);先输出 114,再让 x 变成 113。
第三步:
x += y = z = 11;赋值从右向左:
z = 11y = 11x = 113 + 11 = 124第四步:
x = y == z;y == z 为真,所以 x = 1。
第五步:
printf("%d\n", -x++);x++ 先取旧值 1,再自增,所以输出的是:
-1容易踩坑点:
x--和x++都是先用旧值,再改变变量。x += y = z = 11要从右往左看。
给新手的建议:
- 这类题一定拆成多行,不要在脑子里硬算。
填空题第 7 题
Section titled “填空题第 7 题”题目整理:
int x = 2, y = 3, z = 4;x + y && z答案:1
详细解析:
先算:
x + y = 55 是非 0,表示真。
z = 4 也是非 0,表示真。
所以:
真 && 真 = 真结果为 1。
容易踩坑点:
- 以为逻辑表达式会返回原来的数字
4或5。
给新手的建议:
&&和||的结果通常是0或1。
填空题第 8 题
Section titled “填空题第 8 题”题目整理:
int x;x = -3 + 4 * 5 - 6;答案:11
详细解析:
先乘除,后加减:
4 * 5 = 20所以:
x = -3 + 20 - 6 = 11容易踩坑点:
- 忘记乘法优先级高于加减法。
给新手的建议:
- 表达式题先把优先级高的部分圈出来。
填空题第 9 题
Section titled “填空题第 9 题”题目问:C 语言中,二维数组在内存中的存放方式是什么?
答案:行
详细解析:
C 语言二维数组按行优先存放。
例如:
int a[2][3] = { {1, 2, 3}, {4, 5, 6}};内存顺序是:
1 2 3 4 5 6先放第 0 行,再放第 1 行。
容易踩坑点:
- 把二维数组想成真正的二维表格,忘记内存本质上是一条连续空间。
给新手的建议:
- 二维数组画表格理解,下标计算时记住“按行一行一行存”。
填空题第 10 题
Section titled “填空题第 10 题”题目整理:
struct stud{ char num[6]; int s[4]; double ave;} a, *p;问:变量 a 在内存中占多少字节?
答案:22
详细解析:
按传统教材环境:
char num[6]占6字节int s[4]中int占2字节,所以共8字节double ave占8字节
所以:
6 + 8 + 8 = 22补充提醒:
现代编译器可能因为 int 字节数和结构体对齐规则,算出来不是 22。这类考试题通常按教材环境和题目默认字节数来答。
容易踩坑点:
- 忽略数组成员的元素个数。
- 忽略不同环境下
int字节数可能不同。
给新手的建议:
- 做考试题按题目环境算;自己写代码时可以用
sizeof(a)验证。
4. 判断题详解
Section titled “4. 判断题详解”判断题第 1 题
Section titled “判断题第 1 题”题目:
int i = 10, j = 2;i *= j + 8;判断:执行后 i 的值为 28。
答案:N
解析:
i *= j + 8;等价于:
i = i * (j + 8);所以:
i = 10 * (2 + 8) = 100不是 28。
易错点:复合赋值右边会整体参与运算,不是简单写成 i = i * j + 8。
判断题第 2 题
Section titled “判断题第 2 题”题目:
int c;while (c = getchar()) ;判断:这是正确的 C 语句。
答案:T
解析:
赋值表达式可以作为 while 的条件。每次读取一个字符,赋给 c,再根据 c 的值判断是否继续循环。
易错点:= 是赋值,== 是判断相等。这里用 = 语法上是可以的。
新手建议:虽然语法正确,但真实写代码时常常会写得更明确一些,避免误读。
判断题第 3 题
Section titled “判断题第 3 题”题目:关系运算符 <= 与 == 的优先级相同。
答案:N
解析:
<= 属于关系运算符,== 属于相等性运算符。
关系运算符优先级高于相等性运算符。
易错点:把所有比较符号都当成同一优先级。
判断题第 4 题
Section titled “判断题第 4 题”题目:
int a[3][4] = {{1}, {5}, {9}};判断:它的作用是将数组各行第一列的元素赋初值,其余元素为 0。
答案:T
解析:
数组实际为:
1 0 0 05 0 0 09 0 0 0易错点:不知道二维数组每一行可以用一组 {} 单独初始化。
判断题第 5 题
Section titled “判断题第 5 题”题目:表达式 (j = 3, j++) 的值是 4。
答案:N
解析:
逗号表达式的值看最后一个表达式。
最后一个表达式是:
j++j++ 的表达式值是旧值 3,执行后 j 才变成 4。
所以表达式的值是 3,不是 4。
易错点:把变量最终值和表达式值混在一起。
判断题第 6 题
Section titled “判断题第 6 题”题目:
#define S(a, b) t = a; a = b; b = t判断:由于变量 t 没定义,所以此宏定义是错误的。
答案:N
解析:
宏定义本身只是文本替换规则,不会在定义时检查 t 是否已经定义。
但如果实际使用宏时,展开后的代码里 t 没有定义,那编译就会报错。
易错点:宏定义阶段和宏展开后的编译阶段不是一回事。
判断题第 7 题
Section titled “判断题第 7 题”题目整理:
int a[3][3] = {{3, 5}, {8, 9}, {12, 35}}, i, sum = 0;
for (i = 0; i < 3; i++) sum += a[i][2 - i];判断:sum = 21。
答案:T
解析:
数组补 0 后是:
3 5 08 9 012 35 0求和元素:
a[0][2] = 0a[1][1] = 9a[2][0] = 12所以:
sum = 0 + 9 + 12 = 21易错点:忘记没写满的元素会自动补 0。
判断题第 8 题
Section titled “判断题第 8 题”题目:C 语言中只能逐个引用整型数组元素,而不能一次引用整个数组。
答案:T
解析:
例如:
int a[3] = {1, 2, 3};可以写:
printf("%d", a[0]);但不能直接用一条普通表达式把整个数组当一个值来引用或赋值。
易错点:数组名可以表示首地址,但它不是“整个数组的值”。
判断题第 9 题
Section titled “判断题第 9 题”题目:整数 -32100 可以赋值给 int 型和 long int 型变量。
答案:T
解析:
按传统 16 位有符号 int 环境:
int 范围:-32768 ~ 32767-32100 在这个范围内,所以可以赋给 int,也可以赋给范围更大的 long int。
易错点:不同编译环境下整数范围可能不同,考试题按教材环境判断。
判断题第 10 题
Section titled “判断题第 10 题”题目:在 C 程序中,函数既可以嵌套定义,也可以嵌套调用。
答案:N
解析:
C 语言可以嵌套调用函数:
r = func(func(x, y), z);但标准 C 语言不允许在一个函数内部再定义另一个函数。
易错点:把“嵌套调用”和“嵌套定义”混为一谈。
5. 改错题详解
Section titled “5. 改错题详解”功能:先把字符串 s 中的字符按正序存放到 t 中,然后把 s 中的字符按逆序连接到 t 后面。
例如:
s = "ABCDE"t = "ABCDEEDCBA"整理后的正确代码:
#include <stdio.h>#include <string.h>
void fun(char *s, char *t){ int i, sl;
sl = strlen(s);
for (i = 0; i <= sl; i++) t[i] = s[i];
for (i = 0; i < sl; i++) t[sl + i] = s[sl - i - 1];
t[sl + i] = '\0';}
int main(void){ char s[100], t[200];
printf("\nPlease enter string s: "); scanf("%99s", s);
fun(s, t);
printf("The result is: %s\n", t); return 0;}详细解析:
第一处错误:
t[sl + i] = s[sl - i];应该改成:
t[sl + i] = s[sl - i - 1];原因是字符串最后一个有效字符的下标是 sl - 1,s[sl] 是 '\0'。
第二处错误:
t[sl] = '\0';应该改成:
t[sl + i] = '\0';原因是逆序拼接完成后,字符串结尾位置已经移动到了 sl + i。
第三处错误:
fun(&s, &t);应该改成:
fun(s, t);原因是 s 和 t 本身作为数组名时,就可以表示首元素地址。
容易踩坑点:
- 字符串最后一个有效字符下标是
strlen(s) - 1。 '\0'必须放在最终字符串末尾。- 数组传参时通常直接写数组名,不写
&数组名。
给新手的建议:
- 字符串拼接题最重要的是算清楚下标。
- 可以拿
"ABCDE"手动代入:sl = 5,逆序第一个字符应该取s[4]。
功能:用数字 1、2、3、4 组成互不相同且无重复数字的三位数,并输出所有结果。
整理后的正确代码:
#include <stdio.h>
int main(void){ int i, j, k;
printf("\n");
for (i = 1; i <= 4; i++) for (j = 1; j <= 4; j++) for (k = 1; k <= 4; k++) if (i != j && i != k && j != k) printf("%d%d%d\n", i, j, k);
return 0;}详细解析:
第一处错误:
printf("\n")应该补分号:
printf("\n");第二处错误:
for (i = 1; i <= 5; i++)数字只有 1、2、3、4,所以应该写:
for (i = 1; i <= 4; i++)第三处错误:
if (i != k || i != j || j != k)应该改成:
if (i != j && i != k && j != k)原因是题目要求三个数字互不相同,所以必须同时满足三组不相等。
补充说明:
原卷标注里只强调把其中一个逻辑或改成逻辑与,但从题目功能看,三个数字都不能重复,完整正确条件应使用三个 &&。
容易踩坑点:
- 用
||会导致有重复数字时也可能通过判断。 - 循环边界写到
5,会把数字5也输出。
给新手的建议:
- “同时满足多个条件”通常用
&&。 - “满足任意一个条件”才用
||。
6. 程序设计题详解
Section titled “6. 程序设计题详解”程序设计 1
Section titled “程序设计 1”题目:任意输入 10 个国家的名字,按由小到大排序。
参考答案:
#include <stdio.h>#include <string.h>
#define N 10
int main(void){ char a[N][20], temp[20]; int i, j;
printf("请输入 10 个国家名称:\n"); for (i = 0; i < N; i++) scanf("%19s", a[i]);
for (i = 0; i < N - 1; i++) { for (j = i + 1; j < N; j++) { if (strcmp(a[i], a[j]) > 0) { strcpy(temp, a[i]); strcpy(a[i], a[j]); strcpy(a[j], temp); } } }
printf("排序后的结果:\n"); for (i = 0; i < N; i++) printf("%s\n", a[i]);
return 0;}详细解题过程:
第一步,定义二维字符数组:
char a[10][20];可以理解为:最多保存 10 个字符串,每个字符串最多占 20 个字符空间。
第二步,输入 10 个国家名字:
for (i = 0; i < N; i++) scanf("%19s", a[i]);第三步,用 strcmp 比较两个字符串大小:
if (strcmp(a[i], a[j]) > 0)如果 a[i] 比 a[j] 大,就交换它们,让小的排在前面。
第四步,字符串交换不能直接写:
a[i] = a[j]; // 错误应该用 strcpy:
strcpy(temp, a[i]);strcpy(a[i], a[j]);strcpy(a[j], temp);容易踩坑点:
- 字符串不能用
>比较内容。 - 字符数组不能整体赋值。
- 交换字符串要用临时字符数组和
strcpy。
给新手的建议:
- 看到“字符串排序”,先想到
strcmp和strcpy。 - 这题本质是数组排序,只是比较和交换的对象从整数变成了字符串。
程序设计 2
Section titled “程序设计 2”题目:编写函数 void fun(int tt[M][N], int pp[N]),求二维数组每一列中的最大元素,并依次放入一维数组 pp 中。
参考答案:
#include <stdio.h>
#define M 3#define N 4
void fun(int tt[M][N], int pp[N]){ int i, j;
for (j = 0; j < N; j++) { pp[j] = tt[0][j];
for (i = 1; i < M; i++) { if (tt[i][j] > pp[j]) pp[j] = tt[i][j]; } }}
int main(void){ int i; int tt[M][N] = { {1, 8, 3, 4}, {5, 2, 9, 6}, {7, 4, 0, 10} }; int pp[N];
fun(tt, pp);
for (i = 0; i < N; i++) printf("%d ", pp[i]); printf("\n");
return 0;}这组测试数据中,每列最大值是:
第 0 列:max(1, 5, 7) = 7第 1 列:max(8, 2, 4) = 8第 2 列:max(3, 9, 0) = 9第 3 列:max(4, 6, 10) = 10所以输出:
7 8 9 10详细解题过程:
外层循环控制列:
for (j = 0; j < N; j++)每一列先假设第 0 行最大:
pp[j] = tt[0][j];然后从第 1 行开始往下比较:
for (i = 1; i < M; i++)如果发现更大的值,就更新:
if (tt[i][j] > pp[j]) pp[j] = tt[i][j];容易踩坑点:
- 题目要求“每列最大值”,外层应该遍历列
j。 - 每列都要先初始化一次
pp[j]。 - 不要把
M和N搞反,M是行数,N是列数。
给新手的建议:
- 二维数组统计题先问自己:按行处理还是按列处理?
- 如果题目说“每列”,通常外层循环写列,内层循环写行。
7. 这套卷子最容易暴露的问题
Section titled “7. 这套卷子最容易暴露的问题”这套 exam-87 对新手来说,最容易暴露下面这些问题:
- 函数声明、函数定义、函数调用分不清。
- 字符串比较时想直接用
>。 - 字符数组长度忘记给
'\0'留位置。 - 二维数组第二维为什么不能省略还不够熟。
i++、++i、x--的表达式值和变量最终值分不清。- 逻辑运算中
&&和||的使用场景容易混。 - 结构体大小计算容易忽略数组成员。
- 程序设计题看到字符串排序、二维数组列最大值时,不知道先拆步骤。
8. 给新手的复习建议
Section titled “8. 给新手的复习建议”- 把第 15 题、第 16 题、第 6 道填空题手动列变量变化表。
- 把字符串相关题集中复习:第 2、7、9、10、18、23、24 题。
- 把二维数组相关题集中复习:第 4、8、11、16、19、20、21、22、25 题。
- 改错题 2 要重点记住:互不相同通常是三个条件同时成立,要用
&&。 - 程序设计 1 和程序设计 2 都建议自己重新手敲一遍,敲完以后改几个测试数据验证。
9. 最后总结
Section titled “9. 最后总结”这套卷子和 exam-86 一样,重点不是考特别偏的知识,而是反复检查 C 语言基础是否扎实:
- 数组和字符串是不是能稳定判断长度、下标、初始化。
- 函数题是不是能分清形参、实参、返回值。
- 表达式题是不是能按优先级一步一步算。
- 综合程序是不是能拆成输入、处理、输出三个部分。
如果你能把这套卷子的字符串题、二维数组题和两个程序设计题自己写出来,你对 C 语言前半部分的基础就会稳很多。