exam-82 试卷整理与详解
这份笔记是根据 82.pdf 整理出来的,原卷文件在本地路径:
/Users/wff/Downloads/82.pdf这套题主要复习 C 语言里的函数调用、数组初始化、字符串处理、二维数组、指针、文件读写、宏和结构体基础,以及两类常见程序设计题:判断素数、判断整除。
PDF 里的 OCR 对代码符号有一些误差,例如 '\0'、\x10、逗号、分号、花括号、==、% 等位置容易识别错。我整理时已经按原卷红色标注和 C 语言语法做了校对。
特别提醒:
- 选择题第 21 题问的是“字符数组初始化不正确”,不是“字符串赋值不正确”。所以
char s[5] = {'a','b','c','d','e'};作为字符数组是可以的,只是不能当普通字符串使用。 - 选择题第 23 题按传统教材和 Turbo C 考试口径判断,
int n = 5, a[n];是错误的。现代部分编译器可能支持变长数组,但做这类基础卷子要按教材标准答。 - 选择题第 25 题要分清“形参”和“实参”:函数调用可以作为实参,但不能作为函数定义中的形参。
1. 答案速查
Section titled “1. 答案速查”1.1 选择题答案
Section titled “1.1 选择题答案”| 题号 | 答案 |
|---|---|
| 1 | C |
| 2 | A |
| 3 | B |
| 4 | D |
| 5 | B |
| 6 | C |
| 7 | A |
| 8 | A |
| 9 | A |
| 10 | A |
| 11 | A |
| 12 | D |
| 13 | C |
| 14 | A |
| 15 | A |
| 16 | C |
| 17 | C |
| 18 | D |
| 19 | B |
| 20 | C |
| 21 | C |
| 22 | C |
| 23 | A |
| 24 | A |
| 25 | A |
1.2 填空题答案
Section titled “1.2 填空题答案”| 题号 | 答案 |
|---|---|
| 1 | 0 |
| 2 | "filea.dat", "r" |
| 3 | 12 34 |
| 4 | x >= 1 或 1 <= x |
| 5 | 2 |
| 6 | *pmax = *px 或 max = x 等等价写法 |
| 7 | p = fun 或 p = fun; |
| 8 | 58 |
| 9 | 6 |
| 10 | 15 |
1.3 判断题答案
Section titled “1.3 判断题答案”| 题号 | 答案 |
|---|---|
| 1 | Y |
| 2 | Y |
| 3 | N |
| 4 | Y |
| 5 | N |
| 6 | N |
| 7 | Y |
| 8 | N |
| 9 | Y |
| 10 | N |
2. 选择题详解
Section titled “2. 选择题详解”选择题第 1 题
Section titled “选择题第 1 题”题目问:在 C 语言中,调用函数除函数名外,还必须有什么?
答案:C
正确答案:
()详细解析:
函数调用的基本格式是:
函数名(实参列表)即使函数没有参数,也必须写一对小括号。
例如:
printf("hello\n");getchar();fun();fun 只是函数名,fun() 才表示调用函数。
容易踩坑点:
- 以为无参函数调用时可以省略
()。 - 把函数声明和函数调用混在一起。
给新手的建议:
- 看到函数名后面有
(),才表示“调用它”。
选择题第 2 题
Section titled “选择题第 2 题”题目整理:
int k[30] = {12, 324, 45, 6, 768, 98, 21, 34, 453, 456};int count = 0, i = 0;
while (k[i]){ if (k[i] % 2 == 0 || k[i] % 5 == 0) count++;
i++;}
printf("%d,%d\n", count, i);答案:A
详细解析:
数组只显式初始化了前 10 个数,后面的元素会自动补 0。
所以:
k[10] = 0循环条件是:
while (k[i])当 i = 10 时遇到 k[10] = 0,循环结束。因此一共检查前 10 个数,最后 i = 10。
再数满足条件的数:
| 元素 | 是否能被 2 或 5 整除 |
|---|---|
| 12 | 是 |
| 324 | 是 |
| 45 | 是 |
| 6 | 是 |
| 768 | 是 |
| 98 | 是 |
| 21 | 否 |
| 34 | 是 |
| 453 | 否 |
| 456 | 是 |
满足条件的共有 8 个。
输出:
8,10容易踩坑点:
- 忘记数组没写到的元素会自动补
0。 - 把
||误认为两个条件都要满足。
给新手的建议:
while(k[i])这种写法本质是在判断k[i] != 0。
选择题第 3 题
Section titled “选择题第 3 题”题目整理:
int a = 1, b = 2, c = 3, d = 4, e = 5;printf("%d\n", func((a + b, b + c, c + a), (d + e)));
int func(int x, int y){ return x + y;}答案:B
详细解析:
第一个实参是逗号表达式:
(a + b, b + c, c + a)逗号表达式的值看最后一个表达式:
c + a = 3 + 1 = 4第二个实参:
d + e = 4 + 5 = 9所以函数调用等价于:
func(4, 9)返回:
4 + 9 = 13容易踩坑点:
- 把逗号表达式里的三个表达式都加起来。
- 数实参时把括号里面的逗号也当作参数分隔符。
给新手的建议:
- 逗号表达式记一句:整体值看最后一个表达式。
选择题第 4 题
Section titled “选择题第 4 题”题目问:下列字符数组长度为 5 的是哪一个?
答案:D
正确写法:
char a[] = {'h', 'a', 'b', 'c', 'd'};详细解析:
初始化列表里一共有 5 个字符:
'h' 'a' 'b' 'c' 'd'所以数组长度为 5。
其他选项:
char d[6] = {'h', 'a', 'b', 'c', '\0'};数组长度已经写明是 6。
char b[] = {'h', 'a', 'b', 'c', 'd', '\0'};初始化列表有 6 个元素,所以长度是 6。
char c[10] = {'h', 'a', 'b', 'c', 'd'};数组长度已经写明是 10。
容易踩坑点:
- 把字符串长度和字符数组长度混在一起。
- 看到
'\0'就只算前面的有效字符。
给新手的建议:
- 题目问数组长度,看数组实际有多少个元素;题目问字符串长度,才看
'\0'前面有几个字符。
选择题第 5 题
Section titled “选择题第 5 题”题目问:以下不正确的定义语句是哪一个?
答案:B
错误写法:
int y[5] = {0, 1, 3, 5, 7, 9};详细解析:
y[5] 表示数组最多有 5 个元素:
y[0] ~ y[4]但初始化列表里给了 6 个数:
0, 1, 3, 5, 7, 9初值个数超过数组长度,所以错误。
补充说明:
原卷选项 A 的 OCR 容易把转义字符识别错。按原卷红字答案,本题重点考的是 B 中数组长度和初值个数不匹配。
容易踩坑点:
- 数组长度写了 5,却放了 6 个初值。
给新手的建议:
- 数组初始化时,先数方括号里的空间,再数花括号里的初值。
选择题第 6 题
Section titled “选择题第 6 题”题目整理:
int func(int a, int b){ int c;
c = a + b; return c;}
int x = 6, y = 7, z = 8, r;r = func((x--, y++, x + y), z--);printf("%d\n", r);答案:C
详细解析:
先看第一个实参:
(x--, y++, x + y)这是逗号表达式,依次执行:
x--:先使用 x 的旧值,然后 x 变成 5y++:先使用 y 的旧值,然后 y 变成 8x + y:此时 x = 5,y = 8,所以结果是 13第二个实参:
z--作为实参时使用旧值 8,然后 z 变成 7。
所以函数调用等价于:
func(13, 8)返回:
13 + 8 = 21容易踩坑点:
x--是先用后减,y++是先用后加。- 逗号表达式的值看最后一个表达式。
给新手的建议:
- 自增自减和逗号表达式混在一起时,一定要按顺序写变量变化过程。
选择题第 7 题
Section titled “选择题第 7 题”题目整理:
char a[10];问:以下语句中不能从键盘上给 a 数组的所有元素输入值的是哪一个?
答案:A
错误写法:
a = getchar();详细解析:
a 是数组名,不能作为赋值号左边整体赋值。
而且:
getchar()一次只读取一个字符,不可能直接给整个数组输入所有元素。
可以逐个输入:
for (i = 0; i < 10; i++) a[i] = getchar();也可以按字符串输入:
scanf("%s", a);容易踩坑点:
- 把字符数组当成一个普通字符变量。
- 忘记数组名不能整体赋值。
给新手的建议:
- 给数组元素赋值,要么逐个
a[i] = ...,要么使用字符串输入函数。
选择题第 8 题
Section titled “选择题第 8 题”题目问:以下对一维整型数组 a 的正确说明是哪一个?
答案:A
正确写法:
#define SIZE 10int a[SIZE];详细解析:
SIZE 是宏常量,预处理后相当于:
int a[10];按传统教材口径,数组长度应该是常量表达式。
其他选项的问题:
int n = 10, a[n];中n是变量,按传统教材口径不正确。scanf输入后再定义int a[n];,同样是变量长度数组,传统教材不认可。int a(10);不是 C 语言数组定义写法。
容易踩坑点:
- 把变量
n当作数组长度常量。 - 用圆括号定义数组。
给新手的建议:
- 数组定义用方括号:
int a[10];。
选择题第 9 题
Section titled “选择题第 9 题”题目问:以下能正确定义数组并正确赋初值的语句是哪一个?
答案:A
正确写法:
int d[3][2] = {{1, 2}, {3, 4}};详细解析:
d[3][2] 表示 3 行 2 列。给出的初值可以放成:
1 23 40 0没有显式给出的元素自动补 0。
其他选项的问题:
int a[1][2] = {{1}, {3}};只有 1 行,却给了 2 行初值。int c[2][] = ...第二维省略,错误。int N = 5, b[N][N];按传统教材口径,数组长度不能用普通变量。
容易踩坑点:
- 二维数组可以省略第一维,但不能省略第二维。
- 初值少可以补
0,行数超了不行。
给新手的建议:
- 二维数组题先检查“第二维有没有写”。
选择题第 10 题
Section titled “选择题第 10 题”题目问:以下不能正确定义二维数组的选项是哪一个?
答案:A
错误写法:
int a[2][] = {{1, 2}, {3, 4}};详细解析:
二维数组定义时,第二维不能省略。
正确示例:
int a[][2] = {1, 2, 3, 4};这里第一维可以由初值推断出来,但第二维必须明确,因为编译器需要知道每一行有几个元素。
容易踩坑点:
- 以为有初始化列表就可以省略任意一维。
给新手的建议:
- 二维数组口诀:第一维可省,第二维必须写。
选择题第 11 题
Section titled “选择题第 11 题”题目整理:
int a[3][4] = {0};答案:A
详细解析:
= {0} 会让数组中每个元素都初始化为 0。
可以理解为:
0 0 0 00 0 0 00 0 0 0容易踩坑点:
- 以为只有
a[0][0]得到初值0。
给新手的建议:
- 数组初始化中,
{0}是常见的全 0 初始化写法。
选择题第 12 题
Section titled “选择题第 12 题”题目整理:
char a1[] = "abc", a2[80] = "1234";问:将 a1 串连接到 a2 串后面的语句是哪一个?
答案:D
正确写法:
strcat(a2, a1);详细解析:
strcat 的格式是:
strcat(目标字符串, 要追加的字符串);所以 strcat(a2, a1) 表示把 a1 接到 a2 后面。
执行后:
a2 = "1234abc"容易踩坑点:
- 把
strcat两个参数顺序写反。 - 忘记目标数组必须有足够空间。
给新手的建议:
strcat(a2, a1)可以读成“把a1接到a2后面”。
选择题第 13 题
Section titled “选择题第 13 题”题目问:数组名作为实参数传递给函数时,数组名被处理为什么?
答案:C
正确理解:
数组名被处理为该数组的首地址。详细解析:
例如:
int a[10];fun(a);这里传给函数的不是整个数组的复制品,而是数组首元素的地址,也可以理解为:
&a[0]容易踩坑点:
- 以为数组传参会把所有元素复制一份。
给新手的建议:
- 数组名作实参,传的是地址。
选择题第 14 题
Section titled “选择题第 14 题”题目整理:
char s1[] = "abc", s2[20], *t = s2;gets(t);问:当字符串 s1 大于字符串 s2 时,输出 s2,正确语句是哪一个?
答案:A
正确写法:
if (strcmp(s1, t) > 0) puts(s2);详细解析:
这里:
t = s2;所以 t 指向的就是 s2。
比较字符串大小要用 strcmp:
strcmp(s1, t) > 0 表示 s1 大于 t 所指字符串因为 t 指向 s2,所以这就等价于判断 s1 > s2。
容易踩坑点:
- 用
s1 > s2比较字符串内容。 - 忘记
t和s2指向同一段数组。
给新手的建议:
- 字符串大小比较用
strcmp,不要直接用>。
选择题第 15 题
Section titled “选择题第 15 题”题目问:对于 void 类型函数,调用时不可作为哪一种?
答案:A
正确理解:
void 函数没有返回值,所以不能作为表达式使用。例如:
void show(void){ printf("hello\n");}可以这样调用:
show();不能这样写:
int x = show(); // 错误容易踩坑点:
- 以为所有函数调用都有结果值。
给新手的建议:
void函数是为了“做动作”,不是为了“拿结果”。
选择题第 16 题
Section titled “选择题第 16 题”题目问:以下不能对二维数组 a 进行正确初始化的语句是哪一个?
答案:C
错误写法:
int a[2][3] = {{1, 2}, {3, 4}, {5, 6}};详细解析:
a[2][3] 表示只有 2 行 3 列。
但初始化时给了 3 行:
{1, 2}{3, 4}{5, 6}行数超出,所以错误。
其他选项:
int a[][3] = {1, 2, 3, 4, 5, 6};第一维可以省略,第二维写了 3,合法。
int a[][3] = {{1, 2}, {0}};合法,缺少的元素补 0。
int a[2][3] = {0};合法,全部初始化为 0。
容易踩坑点:
- 少给初值可以补
0,多给行数不行。
给新手的建议:
- 二维数组初始化时,先看行数有没有超过定义。
选择题第 17 题
Section titled “选择题第 17 题”题目问:以下程序段中,不能正确赋字符串的是哪一个?
答案:C
错误写法:
char s[10];s = "abcdefg";详细解析:
数组名不能作为赋值号左边整体赋值。
定义时可以初始化:
char s[10] = "abcdefg";定义后再复制字符串,应写:
strcpy(s, "abcdefg");容易踩坑点:
- 把字符数组名当成普通变量。
给新手的建议:
- 字符数组定义时可以用
=初始化,定义之后复制字符串用strcpy。
选择题第 18 题
Section titled “选择题第 18 题”题目整理:
long fib(int n){ if (n > 2) return fib(n - 1) + fib(n - 2); else return 2;}
printf("%d\n", fib(3));答案:D
详细解析:
递归出口:
n <= 2 时,fib(n) = 2所以:
fib(3) = fib(2) + fib(1) = 2 + 2 = 4容易踩坑点:
- 看到
fib就套普通斐波那契数列,忘记这题的前两项都是2。
给新手的建议:
- 递归题先看出口值。
选择题第 19 题
Section titled “选择题第 19 题”题目整理:
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]);答案:B
详细解析:
初始:
n[0] = 0n[1] = 0k = 1外层 i 取 0 和 1,内层 j 也取 0 和 1。
逐步模拟:
| i | j | 语句 | 执行后 n[0] | 执行后 n[1] |
|---|---|---|---|---|
| 0 | 0 | n[0] = n[0] + 1 | 1 | 0 |
| 0 | 1 | n[1] = n[0] + 1 | 1 | 2 |
| 1 | 0 | n[0] = n[1] + 1 | 3 | 2 |
| 1 | 1 | n[1] = n[1] + 1 | 3 | 3 |
最后输出:
n[k] = n[1] = 3容易踩坑点:
- 没有注意
n[i]的值会在前面循环中变化。 - 内层循环没有花括号时,只控制下一条语句。
给新手的建议:
- 数组循环赋值题,用表格模拟最稳。
选择题第 20 题
Section titled “选择题第 20 题”题目问:用户定义的函数不可以调用的函数是哪一个?
答案:C
按本卷考试口径:
用户定义函数不可以调用 main 函数。详细解析:
main 函数是程序入口。通常程序启动时由系统调用 main,再由 main 去调用其他函数。
本类教材题一般要求理解为:
main 可以调用其他函数,其他用户自定义函数不应该调用 main。容易踩坑点:
- 把
main当成普通函数随便调用。
给新手的建议:
- 初学阶段把
main记成“程序总入口”,不要在其他函数里调用它。
选择题第 21 题
Section titled “选择题第 21 题”题目问:下列对字符数组的初始化不正确的是哪一个?
答案:C
错误写法:
char s[5] = "abcde";详细解析:
字符串 "abcde" 实际需要 6 个位置:
'a' 'b' 'c' 'd' 'e' '\0'但是 s[5] 只有 5 个位置,放不下结尾的 '\0',所以作为字符串初始化是不正确的。
重点区分:
char s[5] = {'a', 'b', 'c', 'd', 'e'};这个选项作为“字符数组初始化”是可以的,因为它只是放 5 个普通字符,不要求自动追加 '\0'。
但它不能当作正常字符串使用,因为它没有字符串结束符。
容易踩坑点:
- 把字符数组初始化和字符串初始化混在一起。
给新手的建议:
- 双引号
"abcde"是字符串,会自动带'\0'。 - 单个字符列表
{'a','b','c','d','e'}只是字符数组,不会自动多塞一个'\0'。
选择题第 22 题
Section titled “选择题第 22 题”题目整理:
char array[] = "China";问:数组 array 所占空间是多少?
答案:C
详细解析:
字符串 "China" 的有效字符有 5 个:
C h i n a字符串结尾还会自动加一个 '\0':
C h i n a \0所以数组占:
6 个字节容易踩坑点:
- 只数有效字符,忘记字符串结束符。
给新手的建议:
- 字符串数组占用空间通常是“有效字符个数 + 1”。
选择题第 23 题
Section titled “选择题第 23 题”题目问:以下定义语句中错误的是哪一个?
答案:A
错误写法:
int n = 5, a[n];详细解析:
按传统 C 语言教材和 Turbo C 考试口径,数组长度应是常量表达式。
n 是变量,不是常量表达式,所以这题判错。
其他选项:
char *a[3];char s[10] = "test";int a[] = {1, 2};这些都是合法写法。
补充提醒:
现代部分编译器支持变长数组,但这类基础考试通常不按这个标准判。
容易踩坑点:
- 把“编译器能跑”和“考试标准答案”混在一起。
给新手的建议:
- 做这类卷子时,数组长度优先按“常量表达式”判断。
选择题第 24 题
Section titled “选择题第 24 题”题目整理:
static char str[10] = "China";问:数组元素个数是多少?
答案:A
详细解析:
数组长度已经写明:
str[10]所以数组元素个数就是 10。
字符串 "China" 只决定前几个元素的初值,不改变数组整体长度。
容易踩坑点:
- 把字符串长度
5或字符串占用空间6当成数组元素个数。
给新手的建议:
- 题目问数组元素个数,优先看方括号里的数字。
选择题第 25 题
Section titled “选择题第 25 题”题目问:若已定义的函数有返回值,以下关于该函数调用的叙述中错误的是哪一个?
答案:A
错误说法:
函数调用可以作为一个函数的形参。详细解析:
函数调用有返回值时,可以出现在表达式中:
x = fun() + 3;也可以作为另一个函数的实参:
printf("%d\n", fun());也可以作为独立语句存在:
fun();但“形参”是函数定义时写在参数列表里的变量,例如:
int add(int a, int b){ return a + b;}这里 a 和 b 是形参。函数调用不能作为形参写在函数定义里。
容易踩坑点:
- 混淆形参和实参。
给新手的建议:
- 形参:函数定义时的参数。
- 实参:调用函数时传进去的具体值或表达式。
3. 填空题详解
Section titled “3. 填空题详解”填空题第 1 题
Section titled “填空题第 1 题”题目整理:
int a = 10, b = 15, c = 1, d = 2, e = 0;(c == b) > e答案:0
详细解析:
先算括号:
c == b1 == 15结果为假,也就是 0。
再算:
0 > e0 > 0结果仍然为假,所以表达式值为:
0容易踩坑点:
- 忘记关系表达式的结果是
1或0。
给新手的建议:
- 表达式题先按括号分块计算。
填空题第 2 题
Section titled “填空题第 2 题”题目功能:从名为 filea.dat 的文本文件中逐个读入字符并显示在屏幕上。
题目整理:
FILE *fp;char ch;
fp = fopen(____);ch = fgetc(fp);
while (!feof(fp)){ putchar(ch); ch = fgetc(fp);}
putchar('\n');fclose(fp);答案:"filea.dat", "r"
完整写法:
fp = fopen("filea.dat", "r");详细解析:
fopen 的两个参数是:
文件名打开方式本题要从文本文件中读取字符,所以打开方式是只读:
"r"容易踩坑点:
- 文件名和打开方式都要写成字符串。
- 读取文件用
"r",写入文件用"w",追加写入用"a"。
给新手的建议:
r可以记成 read,表示读。
填空题第 3 题
Section titled “填空题第 3 题”题目整理:
int a = 1, b;
scanf("%2d%2d", &a, &b);printf("%d %d\n", a, b);输入:
1234567答案:12 34
详细解析:
%2d 表示最多读取 2 位数字。
第一次 %2d 读取:
12赋给 a。
第二次 %2d 继续读取后面的 2 位:
34赋给 b。
所以输出:
12 34容易踩坑点:
- 以为
%2d会读取整个整数后保留两位。 - 忘记第二个
%2d会从剩余输入继续读。
给新手的建议:
scanf的宽度是“最多读几个字符”,不是输出保留位数。
填空题第 4 题
Section titled “填空题第 4 题”题目要求:把下面三目运算表达式改写成等价的 if 语句。
y = (x >= 10) ? 3 * x - 11 : (x < 1) ? x : 2 * x - 1;题目给出的结构:
if (x < 10) if (____) y = 2 * x - 1; else y = x;else y = 3 * x - 11;答案:x >= 1 或 1 <= x
详细解析:
原表达式可以分成三段:
x >= 10 -> y = 3 * x - 11x < 1 -> y = x1 <= x < 10 -> y = 2 * x - 1题目外层已经写了:
if (x < 10)在 x < 10 的前提下,要进入 y = 2 * x - 1,还需要:
x >= 1容易踩坑点:
- 三目运算符嵌套时看不清分支。
给新手的建议:
- 遇到嵌套三目,先翻译成分段条件。
填空题第 5 题
Section titled “填空题第 5 题”题目整理:
int a = 13, b = 6;a / b答案:2
详细解析:
a 和 b 都是整数,整数除法会舍去小数部分。
13 / 6 = 2不是 2.166...。
容易踩坑点:
- 忘记整数除法会截断小数。
给新手的建议:
- 只要
/两边都是整数,结果就是整数除法。
填空题第 6 题
Section titled “填空题第 6 题”题目功能:利用指针指向三个整型变量,并通过指针运算找出三个数中的最大值。
题目整理:
int x, y, z, max, *px, *py, *pz, *pmax;
scanf("%d%d%d", &x, &y, &z);
px = &x;py = &y;pz = &z;pmax = &max;
____;
if (*pmax < *py) *pmax = *py;
if (*pmax < *pz) *pmax = *pz;
printf("max=%d\n", max);答案示例:
*pmax = *px;也可以写:
max = x;详细解析:
程序后面要拿 max 先和 y、z 比较,所以空里应该先把 x 作为当前最大值。
由于:
pmax = &max;px = &x;所以:
*pmax = *px;等价于:
max = x;容易踩坑点:
pmax是地址,*pmax才是max这个变量本身。- 直接比较前必须先给
max一个初值。
给新手的建议:
- 指针题可以先把
*pmax翻译成“max 这个盒子里的值”。
填空题第 7 题
Section titled “填空题第 7 题”题目问:将函数 fun 的入口地址赋给指针变量 p 的语句是什么?
答案:p = fun;
详细解析:
函数名 fun 可以表示函数入口地址。
如果 p 是函数指针,那么:
p = fun;就是把函数 fun 的入口地址赋给 p。
不要写成:
p = fun();因为 fun() 表示调用函数,拿到的是函数返回值,不是函数地址。
容易踩坑点:
- 函数名加括号就是调用。
给新手的建议:
- 函数名不加
(),常常表示函数地址;加(),就是调用函数。
填空题第 8 题
Section titled “填空题第 8 题”题目整理:
int a[4][4] = { {1, 2, -3, -4}, {0, -12, -13, 14}, {-21, 23, 0, -24}, {-31, 32, -33, 0}};int i, j, s = 0;
for (i = 0; i < 4; i++){ for (j = 0; j < 4; j++) { if (a[i][j] < 0) continue;
if (a[i][j] == 0) break;
s += a[i][j]; }}
printf("%d\n", s);答案:58
详细解析:
遇到负数执行 continue,跳过当前数字;遇到 0 执行 break,结束当前行的内层循环;遇到正数才累加。
逐行看:
| 行 | 数据 | 累加情况 |
|---|---|---|
| 第0行 | 1, 2, -3, -4 | 加 1 + 2 |
| 第1行 | 0, -12, -13, 14 | 第一个是 0,本行结束 |
| 第2行 | -21, 23, 0, -24 | 跳过 -21,加 23,遇 0 结束 |
| 第3行 | -31, 32, -33, 0 | 跳过 -31,加 32,跳过 -33,遇 0 结束 |
所以:
1 + 2 + 23 + 32 = 58容易踩坑点:
continue和break作用不同。- 内层
break只结束内层循环。
给新手的建议:
- 这种题最好画二维表格,逐行模拟。
填空题第 9 题
Section titled “填空题第 9 题”题目整理:
int a[2][3];问:数组 a 中有多少个元素?
答案:6
详细解析:
二维数组元素个数等于:
行数 * 列数所以:
2 * 3 = 6容易踩坑点:
- 把
a[2][3]误解成最大下标是2和3,从而算成更多元素。
给新手的建议:
int a[2][3]是 2 行 3 列。
填空题第 10 题
Section titled “填空题第 10 题”题目整理:
int fun(int x){ static int t = 0; return t += x;}
int s, i;for (i = 1; i <= 5; i++) s = fun(i);
printf("%d\n", s);答案:15
详细解析:
static int t = 0; 表示 t 是静态局部变量。它不会在每次函数调用时重新变成 0,而是会保留上一次调用后的值。
逐次调用:
| 调用 | t 原值 | t += x 后 | 返回值 |
|---|---|---|---|
| fun(1) | 0 | 1 | 1 |
| fun(2) | 1 | 3 | 3 |
| fun(3) | 3 | 6 | 6 |
| fun(4) | 6 | 10 | 10 |
| fun(5) | 10 | 15 | 15 |
最后一次返回 15,所以 s = 15。
容易踩坑点:
- 以为局部变量每次调用都会重新初始化,忽略了
static。
给新手的建议:
static局部变量会“记住上一次的值”。
4. 判断题详解
Section titled “4. 判断题详解”判断题第 1 题
Section titled “判断题第 1 题”题目:
int a = 3, b = 2, c = 1;(a > b) == c判断:值为真,即为 1。
答案:Y
解析:
先算:
a > b -> 3 > 2 -> 真 -> 1再算:
1 == c -> 1 == 1 -> 真所以结果为 1。
判断题第 2 题
Section titled “判断题第 2 题”题目:共用体变量所占的内存长度等于最长成员的长度。
答案:Y
解析:
共用体所有成员共用同一段内存空间,所以它至少要能放下最长的成员。基础教材里通常表述为:共用体变量所占内存长度等于最长成员的长度。
补充提醒:
实际编译器可能因为内存对齐,让大小略有差异,但这类考试题按教材表述判断。
判断题第 3 题
Section titled “判断题第 3 题”题目整理:
printf("%f%%", 1.0 / 3);判断:输出为 0.333333。
答案:N
解析:
%f 默认输出 6 位小数:
0.333333但格式串里还有:
%%%% 会输出一个普通的百分号 %。
所以实际输出应包含百分号:
0.333333%判断题第 4 题
Section titled “判断题第 4 题”题目:整数 -32100 可以赋值给 int 型和 long int 型变量。
答案:Y
解析:
按传统 16 位有符号 int 环境,取值范围通常是:
-32768 ~ 32767-32100 在范围内,所以可以赋给 int,也可以赋给 long int。
判断题第 5 题
Section titled “判断题第 5 题”题目:通过 return 语句,函数可以带回一个或一个以上的返回值。
答案:N
解析:
return 一次只能直接返回一个值。
如果想让函数带回多个结果,通常使用指针参数或结构体。
判断题第 6 题
Section titled “判断题第 6 题”题目整理:
int i = 10, j = 0;
if (j = 0) i++;else i--;判断:执行后 i 的值为 11。
答案:N
解析:
这里:
j = 0是赋值,不是判断相等。
赋值表达式的值是被赋进去的值,也就是 0。条件为假,所以执行 else:
i--;因此:
i = 9不是 11。
容易踩坑点:
- 把
=看成==。
判断题第 7 题
Section titled “判断题第 7 题”题目整理:
int a[3][4] = {{1}, {5}, {9}};判断:它的作用是将数组各行第一列的元素赋初值,其余元素值为 0。
答案:Y
解析:
数组内容是:
1 0 0 05 0 0 09 0 0 0每一行只给了第一个元素,没给的元素自动补 0。
判断题第 8 题
Section titled “判断题第 8 题”题目整理:
#define S(a, b) t = a; a = b; b = t判断:由于变量 t 没定义,所以此宏定义是错误的。
答案:N
解析:
宏定义本身只是文本替换,不会在定义时检查 t 是否存在。
只有真正使用宏并展开成代码时,如果没有定义 t,才会编译出错。
给新手的建议:
- 宏不是函数,它更像“复制粘贴”。
判断题第 9 题
Section titled “判断题第 9 题”题目:在程序中定义了一个结构体类型后,可以多次用它来定义具有该类型的变量。
答案:Y
解析:
例如:
struct Student{ int id; int age;};
struct Student s1;struct Student s2;定义好结构体类型后,可以用它定义多个变量。
判断题第 10 题
Section titled “判断题第 10 题”题目:字符处理函数 strcpy(str1, str2) 的功能是把字符串 1 接到字符串 2 的后面。
答案:N
解析:
strcpy(str1, str2) 是复制:
把 str2 复制到 str1 中连接字符串用:
strcat(str1, str2);容易踩坑点:
- 混淆
strcpy和strcat。
5. 改错题详解
Section titled “5. 改错题详解”功能:根据下面公式求 π 值,并作为函数值返回。
题目公式:
π / 2 = 1 + 1/3 + 1/3 * 2/5 + 1/3 * 2/5 * 3/7 + ...整理后的正确代码:
#include <stdio.h>
double fun(double eps){ double s, t; int n = 1;
s = 0.0; t = 1.0;
while (t > eps) { s += t; t = t * n / (2.0 * n + 1.0); n++; }
return 2 * s;}
int main(void){ double x;
scanf("%lf", &x); printf("\neps=%lf,Pi=%lf\n\n", x, fun(x));
return 0;}三处错误说明:
第一处:
while (t <= eps)应改为:
while (t > eps)原因:当当前项 t 仍然大于精度 eps 时,才需要继续累加。
第二处:
t = n / (2 * n + 1) * t;应改为:
t = t * n / (2.0 * n + 1.0);原因:要避免整数除法。比如 1 / 3 如果按整数除法,结果是 0。
第三处:
return s;应改为:
return 2 * s;原因:公式左边是 π / 2,所以最终结果要乘以 2 才是 π。
容易踩坑点:
- 循环条件写反。
- 整数除法导致小数被截断。
- 忘记公式求的是
π / 2。
给新手的建议:
- 级数题先看“下一项如何由上一项得到”,再写循环。
功能:用下面的和式求圆周率的近似值,直到最后一项的绝对值小于等于 0.0001,输出结果显示 6 位小数。
题目公式:
π / 4 = 1 - 1/3 + 1/5 - 1/7 + ...整理后的正确代码:
#include <stdio.h>#include <math.h>
void fun(void){ int i = 1; double s = 0.0, t = 1.0, p = 1.0;
while (fabs(t) > 1e-4) { s += t; p = -p; i += 2; t = p / i; }
printf("pi=%f\n", s * 4);}
int main(void){ fun(); return 0;}四处错误说明:
第一处:
#include <stdlib.h>应改为:
#include <math.h>原因:fabs 是求浮点绝对值的函数,它在 <math.h> 中声明。
第二处:
int s = 0, t = 1, p = 1;应改为:
double s = 0.0, t = 1.0, p = 1.0;原因:级数求和涉及小数,不能使用 int 保存。
第三处:
while (fabs(t) <= 1e-4)应改为:
while (fabs(t) > 1e-4)原因:当当前项绝对值仍然大于 0.0001 时继续累加。
第四处:
printf("pi=%d\n", s * 4);应改为:
printf("pi=%f\n", s * 4);原因:s * 4 是浮点数,应使用 %f 输出。
容易踩坑点:
- 用
int保存小数项。 - 忘记
fabs要包含<math.h>。 - 输出浮点数却用了
%d。
给新手的建议:
- 这种交错级数可以用一个符号变量
p控制正负号。
6. 程序设计题详解
Section titled “6. 程序设计题详解”程序设计 1
Section titled “程序设计 1”功能:判断 m 是否为素数,并输出 100 ~ 199 之间的所有素数。
参考答案:
#include <stdio.h>
int fun(int m){ int i;
if (m <= 1) return 0;
for (i = 2; i * i <= m; i++) { if (m % i == 0) return 0; }
return 1;}
int main(void){ int m, k = 0;
for (m = 100; m < 200; m++) { if (fun(m)) { printf("%4d", m); k++;
if (k % 5 == 0) printf("\n"); } }
printf("\nk=%d\n", k); return 0;}详细解题过程:
素数的定义:
只能被 1 和它本身整除的大于 1 的整数判断步骤:
- 如果
m <= 1,一定不是素数。 - 从
2开始试除。 - 只要发现某个
i能整除m,就说明m不是素数。 - 如果一直没有找到因子,就返回
1,表示是素数。
为什么可以写:
i * i <= m因为如果 m 有一个大于平方根的因子,那么一定也有一个小于平方根的配对因子。所以只需要检查到平方根附近即可。
如果按原卷红字的更基础写法,也可以写:
int i, k = 1;
if (m <= 1) k = 0;
for (i = 2; i < m; i++){ if (m % i == 0) k = 0;}
return k;这也能得到正确结果,只是效率低一些。
本题输出的素数个数:
100 到 199 之间共有 21 个素数容易踩坑点:
- 忘记
1不是素数。 - 判断整除应写
m % i == 0。 - 循环范围写错,漏掉某些因子。
- 输出计数时忘记
k++。
给新手的建议:
- 素数题先写最朴素版本:从
2试到m - 1。理解后再优化到i * i <= m。
程序设计 2
Section titled “程序设计 2”功能:编写函数判断一个整数能否同时被 3 和 5 整除。若能返回 1,否则返回 0。调用该函数求出 15 ~ 300 之间能同时被 3 和 5 整除的数的个数。
参考答案:
#include <stdio.h>
int sum(int n){ if (n % 3 == 0 && n % 5 == 0) return 1;
return 0;}
int main(void){ int i, s = 0;
for (i = 15; i <= 300; i++) { if (sum(i) == 1) s = s + 1; }
printf("s=%d\n", s); return 0;}详细解题过程:
同时被 3 和 5 整除,要满足两个条件:
n % 3 == 0并且:
n % 5 == 0所以条件要用逻辑与:
n % 3 == 0 && n % 5 == 0从 15 到 300 之间,同时能被 3 和 5 整除的数,其实就是 15 的倍数:
15, 30, 45, ..., 300一共有:
300 / 15 = 20所以程序最终输出:
s=20容易踩坑点:
- 把
&&写成||。||表示能被 3 或 5 整除,不是同时整除。 - 循环边界要包含
300,所以写i <= 300。 - 判断整除要用
%,不是/。
给新手的建议:
- “同时满足”用
&&。 - “满足其中一个”用
||。
7. 这套卷子最容易暴露的问题
Section titled “7. 这套卷子最容易暴露的问题”这套 exam-82 很适合检查下面这些基础:
- 函数调用必须带
()。 - 函数调用可以作为实参,但不能作为形参。
- 逗号表达式的值看最后一个表达式。
- 数组初始化没写到的位置会自动补
0。 - 二维数组第一维可以省略,第二维不能省略。
- 字符数组长度和字符串占用空间不是一回事。
- 字符串用双引号时会自动包含
'\0'。 - 数组名作为函数实参时,传的是首地址。
strcpy是复制,strcat是连接,strcmp是比较。static局部变量会保留上一次函数调用后的值。
8. 给新手的复习建议
Section titled “8. 给新手的复习建议”- 把选择题第 4、21、22、24 题放在一起复习,它们都在考字符数组和字符串长度。
- 把选择题第 8、9、10、11、16、23 题放在一起复习,它们都在考数组定义和初始化。
- 把选择题第 1、3、6、13、15、20、25 题放在一起复习,它们都和函数调用有关。
- 填空题第 6 题建议手动画指针指向图,弄清楚
pmax和*pmax的区别。 - 填空题第 10 题建议反复记:
static局部变量不会每次调用都重新初始化。 - 两道改错题都和循环条件有关,复习时重点看“什么时候继续循环,什么时候停止”。
- 程序设计第 1 题建议自己手写一遍素数判断函数,这是 C 语言入门必练题。
- 程序设计第 2 题建议重点区分
&&和||。
9. 最后总结
Section titled “9. 最后总结”第 82 套卷子整体难度不算特别高,但它很爱考“细小但致命”的基础点:
- 少写函数调用的
(),意思就变了。 - 数组长度和初值个数不匹配,会直接出错。
- 字符数组能放 5 个字符,不代表它一定是合法字符串。
=和==不能混。int除法会舍去小数。return一次只能直接返回一个值。- 宏定义不是函数,字符串函数也各有分工。
复习这套时,不要只背答案。更稳的方式是每题都问一句:它到底想让我踩哪个坑?能把这个坑说清楚,后面遇到变形题就不容易被绕进去。