exam-90 试卷整理与详解
这份笔记是根据 90.pdf 整理出来的,原卷文件在本地路径:
/Users/wff/Downloads/90.pdf这套卷子继续围绕 C 语言基础展开:数组、字符串、函数、指针、文件、宏、表达式、递归和程序改错。PDF 的 OCR 对代码符号识别有一些误差,我已经按原卷红色标注和 C 语言语法做了整理。
特别提醒:
- 选择题第 21 题,原卷红字标的是
[整型常量]。更严谨的教材写法通常是[常量表达式],所以我在答案速查里写成A(原卷标 D),解析里会说明。 - 程序设计第 2 题,原卷红字里循环写成
i <= n,但主函数按i < n输入数据,所以正确处理数组时应写i < n,否则会越界。 - 填空题第 1 题 OCR 漏掉了循环中调用
move(s, z)的语句;根据答案cdeab可知程序功能是把字符串循环右移 3 次。
1. 答案速查
Section titled “1. 答案速查”1.1 选择题答案
Section titled “1.1 选择题答案”| 题号 | 答案 |
|---|---|
| 1 | C |
| 2 | C |
| 3 | C |
| 4 | A |
| 5 | D |
| 6 | C |
| 7 | C |
| 8 | A |
| 9 | A |
| 10 | D |
| 11 | D |
| 12 | D |
| 13 | D |
| 14 | D |
| 15 | C |
| 16 | B |
| 17 | B |
| 18 | B |
| 19 | B |
| 20 | A |
| 21 | A(原卷标 D) |
| 22 | B |
| 23 | D |
| 24 | D |
| 25 | D |
1.2 填空题答案
Section titled “1.2 填空题答案”| 题号 | 答案 |
|---|---|
| 1 | cdeab |
| 2 | 2.5 |
| 3 | 4 |
| 4 | a[1] 或 *(a + 1) |
| 5 | 20 |
| 6 | 1 |
| 7 | "a" |
| 8 | 8 |
| 9 | 2 或 两 |
| 10 | p = fun 或 p = fun; |
1.3 判断题答案
Section titled “1.3 判断题答案”| 题号 | 答案 |
|---|---|
| 1 | N |
| 2 | Y |
| 3 | Y |
| 4 | N |
| 5 | N |
| 6 | N |
| 7 | N |
| 8 | Y |
| 9 | N |
| 10 | Y |
2. 选择题详解
Section titled “2. 选择题详解”选择题第 1 题
Section titled “选择题第 1 题”题目问:以下正确的说法是哪一个?
答案:C
正确说法:
用户可以重新定义标准库函数,若如此,该函数将失去原有含义。详细解析:
标准库函数比如:
printfscanfstrlenstrcpy它们本来已经由系统库提供。如果用户自己又定义一个同名函数,名字会发生冲突,并且这个名字在当前程序里的含义会变成用户自己的定义。
补充提醒:
实际工程里不要这样做。重新定义标准库函数会让程序很混乱,甚至产生不可预期问题。
容易踩坑点:
- 以为标准库函数名永远不能被用户写出来。
- 以为使用标准库函数不需要包含头文件。
给新手的建议:
- 用标准库函数时,正常包含对应头文件,比如字符串函数包含
<string.h>。
选择题第 2 题
Section titled “选择题第 2 题”题目整理:
int a[10] = {6, 7, 8, 9, 10};答案:C
详细解析:
数组初始化从下标 0 开始,依次赋值:
a[0] = 6a[1] = 7a[2] = 8a[3] = 9a[4] = 10后面的元素没有显式初值,会自动补 0:
a[5] ~ a[9] = 0容易踩坑点:
- 以为第一个初值赋给
a[1]。
给新手的建议:
- 数组初始化和数组访问一样,都是从下标
0开始。
选择题第 3 题
Section titled “选择题第 3 题”题目问:以下能对二维数组 a 进行正确初始化的是哪一个?
答案:C
正确写法:
int a[][3] = {{1, 2, 3}, {4, 5, 6}};详细解析:
二维数组初始化时,第一维可以省略,第二维必须写出来。
这里第二维是 3,每一行 3 个元素:
1 2 34 5 6所以编译器可以推断第一维是 2。
容易踩坑点:
- 二维数组可以省略第一维,但不能省略第二维。
给新手的建议:
- 二维数组初始化题,先看“列数有没有写出来”。
选择题第 4 题
Section titled “选择题第 4 题”题目问:下列字符数组长度为 5 的是哪一个?
答案:A
正确写法:
char a[] = {'h', 'a', 'b', 'c', 'd'};详细解析:
初始化列表里正好有 5 个字符元素,所以数组长度就是 5。
注意:
如果写成:
char b[] = {'h', 'a', 'b', 'c', 'd', '\0'};那么数组长度就是 6,只是它表示的字符串有效长度是 5。
容易踩坑点:
- 把“字符数组长度”和“字符串长度”混在一起。
给新手的建议:
- 数组长度看元素个数。
- 字符串长度看
'\0'前面的有效字符个数。
选择题第 5 题
Section titled “选择题第 5 题”题目整理:
char c[] = "abc";int i = 0;
do ;while (c[i++] != '\0');
printf("%d", i - 1);答案:D
详细解析:
字符串 "abc" 实际存储为:
'a' 'b' 'c' '\0'循环过程:
| 次数 | 判断字符 | 判断后 i |
|---|---|---|
| 1 | c[0] | 1 |
| 2 | c[1] | 2 |
| 3 | c[2] | 3 |
| 4 | c[3] | 4 |
第 4 次遇到 '\0' 后退出,但 i++ 已经执行,所以 i = 4。
输出:
i - 1 = 3容易踩坑点:
- 忘记退出循环那一次
i++也执行了。
给新手的建议:
- 看到
i++在循环条件里,最好手动列每一步。
选择题第 6 题
Section titled “选择题第 6 题”题目问:在 C 语言程序中,函数定义和函数调用能否嵌套?
答案:C
正确说法:
函数的定义不可以嵌套,但函数的调用可以嵌套。详细解析:
函数定义不能写在另一个函数内部:
int main(void){ int fun(void) // 错误 { return 1; }}但函数调用可以嵌套:
printf("%d\n", max(a, b));容易踩坑点:
- 把“嵌套定义”和“嵌套调用”混为一谈。
给新手的建议:
- 函数可以在调用时一层套一层,但定义时不要放到另一个函数里面。
选择题第 7 题
Section titled “选择题第 7 题”题目整理:
int w = 3;
void main(void){ int w = 10; printf("%d\n", fun(5) * w);}
int fun(int k){ if (k == 0) return w;
return fun(k - 1) * k;}答案:C
详细解析:
先看 fun 函数里用到的 w。fun 函数外面能看到的是全局变量:
int w = 3;所以:
fun(0) = 3fun(1) = fun(0) * 1 = 3fun(2) = fun(1) * 2 = 6fun(3) = 6 * 3 = 18fun(4) = 18 * 4 = 72fun(5) = 72 * 5 = 360main 函数中有局部变量:
int w = 10;所以输出:
fun(5) * w = 360 * 10 = 3600容易踩坑点:
- 混淆全局变量
w = 3和main里的局部变量w = 10。 - 递归题没有先找出口
k == 0。
给新手的建议:
- 如果同名变量同时出现,先看“当前函数能访问哪个变量”。
选择题第 8 题
Section titled “选择题第 8 题”题目整理:
exce((v1, v2), (v3, v4, v5), v6);问:实参个数是多少?
答案:A
详细解析:
最外层参数有三个:
(v1, v2)(v3, v4, v5)v6括号里的逗号属于逗号表达式,不是函数参数分隔符。
容易踩坑点:
- 看到逗号就直接数,结果把括号内部的逗号也算进去了。
给新手的建议:
- 数实参个数,只看最外层逗号。
选择题第 9 题
Section titled “选择题第 9 题”题目整理:
int a[10];问:以下对数组元素的正确引用是哪一个?
答案:A
正确写法:
a[10 / 2 - 5]详细解析:
先算下标:
10 / 2 - 5 = 5 - 5 = 0所以:
a[10 / 2 - 5]等价于:
a[0]这是合法下标。
其他选项的问题:
a[4.5]下标不是整数。a[10]越界。a(1)不是数组元素引用写法。
容易踩坑点:
- 数组长度是 10,合法下标是
0 ~ 9。
给新手的建议:
- 下标表达式可以计算,但计算结果必须是合法整数下标。
选择题第 10 题
Section titled “选择题第 10 题”题目问:以下数组定义中不正确的是哪一个?
答案:D
错误写法:
int d[3][] = {{1, 2}, {1, 2, 3}, {1, 2, 3, 4}};详细解析:
二维数组定义时,第二维不能省略。
应写成类似:
int d[][4] = {{1, 2}, {1, 2, 3}, {1, 2, 3, 4}};这样编译器才知道每行有几个元素。
容易踩坑点:
- 以为写了初始化列表就能省略第二维。
给新手的建议:
- 二维数组可以省略第一维,不能省略第二维。
选择题第 11 题
Section titled “选择题第 11 题”题目问:以下定义语句中错误的是哪一个?
答案:D
错误写法:
int n = 5, a[n];详细解析:
按传统 C 语言教材和这类考试口径,数组长度应是常量表达式。
n 是变量,所以这里判错。
补充提醒:
有些现代编译器支持变长数组,但做这种教材卷子时,要按题目口径来答。
容易踩坑点:
- 把“编译器可能支持”和“考试标准答案”混在一起。
给新手的建议:
- 做卷子时,数组长度优先按常量表达式来判断。
选择题第 12 题
Section titled “选择题第 12 题”题目整理:
static char str[10] = "China";问:数组元素个数是多少?
答案:D
详细解析:
数组长度已经写明:
str[10]所以数组元素个数是 10。
字符串 "China" 只决定前几个元素的初值,不改变数组长度。
容易踩坑点:
- 把字符串长度
5或字符串占用空间6当成数组元素个数。
给新手的建议:
- 题目问“数组元素个数”,优先看方括号里的数字。
选择题第 13 题
Section titled “选择题第 13 题”题目问:以下函数原型中正确的是哪一个?
答案:D
正确写法:
void fun(int a, int b);详细解析:
C 语言函数形参之间用逗号分隔,每个形参都要写类型。
错误示例:
void fun(int a; int b) // 错,不能用分号分隔形参void fun(int a, b) // 错,b 没有写类型容易踩坑点:
- 把形参列表里的逗号写成分号。
- 以为
int a, b在函数形参里也表示两个参数都是int。
给新手的建议:
- 函数形参最稳写法:每个参数都写完整类型。
选择题第 14 题
Section titled “选择题第 14 题”题目整理:
char s1[] = "abc", s2[20], *t = s2;gets(t);问:当字符串 s1 大于 s2 时,输出 s2,应该写哪一句?
答案:D
正确写法:
if (strcmp(s1, t) > 0) puts(s2);详细解析:
这里:
t = s2;所以 t 指向的就是 s2。
strcmp(s1, t) > 0 就表示:
s1 > s2容易踩坑点:
- 用
s1 > s2比较字符串。 - 忘记
t和s2指向同一段数组。
给新手的建议:
- 字符串大小比较用
strcmp。
选择题第 15 题
Section titled “选择题第 15 题”题目问:下列不能正确进行字符串赋值的是哪一个?
答案:C
错误写法:
char s[5] = {'a', 'b', 'c', 'd', 'e'};详细解析:
如果题目说的是“字符串赋值”,字符数组末尾应有 '\0'。
上面这个数组只有 5 个普通字符,没有空间保存字符串结束符,所以不能作为正常字符串使用。
其他写法:
char s[5] = "abc";char s[6] = "abcde";char s[] = "abcde";都能形成合法字符串。
容易踩坑点:
- 把普通字符数组和字符串混为一谈。
给新手的建议:
- 字符串一定要有结尾标志
'\0'。
选择题第 16 题
Section titled “选择题第 16 题”题目问:在 C 语言函数中,关于形参的正确说法是哪一个?
答案:B
正确说法:
可以有形参,也可以没有形参。详细解析:
有形参的函数:
int add(int a, int b){ return a + b;}无形参的函数:
void print_line(void){ printf("hello\n");}容易踩坑点:
- 以为函数必须有参数。
给新手的建议:
- 不需要参数时,建议写
void,比如int main(void)。
选择题第 17 题
Section titled “选择题第 17 题”题目整理:
fff(float x){ return 5;}问:函数类型是什么?
答案:B
详细解析:
函数名前没有显式写返回类型。
按老式 C 语言教材口径,如果函数没有写返回类型,默认返回类型是 int。
所以函数类型是 int。
补充提醒:
现代 C 语言不推荐这种写法。实际写代码时应明确写:
int fff(float x)容易踩坑点:
- 以为函数类型和参数
x的类型相同。
给新手的建议:
- 函数返回类型看函数名前面的类型。
选择题第 18 题
Section titled “选择题第 18 题”题目问:以下对二维数组 a 的正确说明是哪一个?
答案:B
正确写法:
double a[1][4];详细解析:
二维数组定义格式:
类型名 数组名[行数][列数];其他选项的问题:
int a[3][]第二维省略,错误。float a(3,4)不是数组定义。float a(3)(4)也不是数组定义。
容易踩坑点:
- 用圆括号写数组。
给新手的建议:
- 数组下标一定用方括号
[]。
选择题第 19 题
Section titled “选择题第 19 题”题目问:与实际参数为实型数组名相对应的形式参数不可以定义为什么?
答案:B
错误写法:
float a;详细解析:
如果实参是实型数组名,传过去的是数组首地址。
一维数组形参可以写:
float a[]float *a二维数组或数组指针可能写:
float (*a)[3]但 float a 只是一个普通浮点变量,不能接收数组地址。
容易踩坑点:
- 把数组参数当成普通变量参数。
给新手的建议:
- 数组名作实参时,形参要能接收地址。
选择题第 20 题
Section titled “选择题第 20 题”题目问:能对一维数组正确初始化的语句是哪一个?
答案:A
正确写法:
int a[6] = {6 * 1};详细解析:
6 * 1 是一个表达式,结果为 6。
所以数组初始化为:
6 0 0 0 0 0其他选项的问题:
int a[6] = {};在传统教材语境里通常不作为正确写法。int a[6] = {1...3};不是标准初始化写法。int a[6] = (0,0,0);数组初始化不能用圆括号。
容易踩坑点:
- 以为
{6 * 1}会让 6 个元素都变成 1。
给新手的建议:
- 初始化列表里写几个值,就初始化前几个元素;剩余元素补
0。
选择题第 21 题
Section titled “选择题第 21 题”题目问:一维数组的定义方式是什么?
更严谨答案:A
原卷标注:D
推荐记法:
类型说明符 数组名[常量表达式];详细解析:
教材中一维数组定义通常写成:
int a[10];int b[2 + 3];方括号里应是常量表达式。
原卷把 [整型常量] 标为答案,这是一种更窄的说法,只覆盖了 10 这种写法,但不能很好覆盖 2 + 3 这种常量表达式。
容易踩坑点:
- 把任意整型变量也当成合法数组长度。
给新手的建议:
- 做题时如果老师按原卷答案讲,记住它想强调“数组长度不能是普通变量”。
- 真正理解时,优先记“常量表达式”。
选择题第 22 题
Section titled “选择题第 22 题”题目问:以下程序段中,不能正确赋字符串的是哪一个?
答案:B
错误写法:
char s[10];s = "abcdefg";详细解析:
数组名不能作为赋值号左边整体赋值。
如果定义后再给字符数组复制字符串,应写:
strcpy(s, "abcdefg");容易踩坑点:
- 把字符数组名当成普通变量。
给新手的建议:
- 定义时可以初始化:
char s[10] = "abcdefg"; - 定义后复制用
strcpy。
选择题第 23 题
Section titled “选择题第 23 题”题目整理:
int a[3][4] = {0};答案:D
详细解析:
= {0} 会让二维数组中每个元素都初始化为 0。
可以理解为:
0 0 0 00 0 0 00 0 0 0容易踩坑点:
- 以为只有
a[0][0]是 0。
给新手的建议:
- 数组初始化中,
{0}是很常见的全 0 初始化。
选择题第 24 题
Section titled “选择题第 24 题”题目整理:
char a[10];问:以下语句中不能从键盘给 a 数组所有元素输入值的是哪一个?
答案:D
错误写法:
a = getchar();详细解析:
a 是数组名,不能作为赋值号左边整体赋值。
而且 getchar() 只读取一个字符,不可能直接填充整个数组。
容易踩坑点:
- 把字符数组当成一个字符变量。
给新手的建议:
- 逐个输入字符用
a[i] = getchar()。 - 输入字符串可以用
scanf("%s", a)。
选择题第 25 题
Section titled “选择题第 25 题”题目整理:
strcat(strcpy(str1, str2), str3)答案:D
详细解析:
先执行内层:
strcpy(str1, str2)作用是把 str2 复制到 str1 中。
strcpy 的返回值是目标字符串 str1 的地址,所以外层等价于:
strcat(str1, str3)作用是把 str3 连接到 str1 后面。
所以整体功能是:
先把 str2 复制到 str1 中,再把 str3 连接到 str1 后面。容易踩坑点:
- 不知道
strcpy会返回目标字符串地址。 - 把
strcat的两个参数顺序理解反。
给新手的建议:
- 字符串函数嵌套时,先看内层,再看外层。
3. 填空题详解
Section titled “3. 填空题详解”填空题第 1 题
Section titled “填空题第 1 题”题目功能:输入 3,abcde,将字符串循环右移 3 次,输出结果。
答案:cdeab
整理后的关键代码:
#include <string.h>
void move(char *str, int n){ char temp; int i;
temp = str[n - 1]; for (i = n - 1; i > 0; i--) str[i] = str[i - 1]; str[0] = temp;}
int main(void){ char s[50]; int n, i, z;
scanf("%d,%s", &n, s); z = strlen(s);
for (i = 1; i <= n; i++) move(s, z);
printf("%s\n", s); return 0;}详细解析:
move(s, z) 的作用是把字符串整体右移一位:
abcde -> eabcd输入 n = 3,所以右移 3 次:
abcdeeabcddeabccdeab所以输出:
cdeab容易踩坑点:
- OCR 漏掉了
move(s, z)这句,直接看会觉得程序没有改变字符串。 - 循环右移一位时,要先保存最后一个字符。
给新手的建议:
- 字符串移动题先拿短字符串手动模拟。
填空题第 2 题
Section titled “填空题第 2 题”题目整理:
x = 2.5;a = 7;y = 4.7;
x + a % 3 * (int)(x + y) % 2 / 4答案:2.5
详细解析:
先算强制转换:
(int)(x + y) = (int)(2.5 + 4.7) = (int)7.2 = 7再按 *、%、/ 同级从左到右:
a % 3 = 7 % 3 = 11 * 7 = 77 % 2 = 11 / 4 = 0这里 1 / 4 是整数除法,结果为 0。
所以:
x + 0 = 2.5容易踩坑点:
- 忘记整数除法
1 / 4的结果是0。 - 忘记
%的操作数应为整型。
给新手的建议:
- 混合表达式题先标出哪些部分是整数运算,哪些部分是浮点运算。
填空题第 3 题
Section titled “填空题第 3 题”题目整理:
int a[5] = {2, 4, 6, 8, 10}, *p;p = a;p++;printf("%d", *p);答案:4
详细解析:
p = a 后,p 指向 a[0]。
执行:
p++;后,p 指向下一个元素 a[1]。
所以:
*p = a[1] = 4容易踩坑点:
p++不是让*p的值加 1,而是让指针指向下一个元素。
给新手的建议:
- 指针和数组结合时,
p++表示“往后移动一个元素位置”。
填空题第 4 题
Section titled “填空题第 4 题”题目:按内存排列顺序,数组 char a[2] 中的所有元素是 a[0] 和什么?
答案:a[1] 或 *(a + 1)
详细解析:
数组:
char a[2];有两个元素:
a[0]a[1]其中:
a[1]也可以写成:
*(a + 1)容易踩坑点:
- 忘记下标从 0 开始。
- 不理解
a[1]和*(a + 1)的关系。
给新手的建议:
a[i]可以理解成*(a + i)。
填空题第 5 题
Section titled “填空题第 5 题”题目整理:
int x = 2, y = 2;x *= y + 8;答案:20
详细解析:
复合赋值:
x *= y + 8;等价于:
x = x * (y + 8);所以:
x = 2 * (2 + 8) = 20容易踩坑点:
- 错算成
x = x * y + 8。
给新手的建议:
- 复合赋值右边整体参与运算。
填空题第 6 题
Section titled “填空题第 6 题”题目整理:
int x = 2;z = x++ - 1;答案:1
详细解析:
x++ 是后置自增,表达式先使用旧值 2,然后 x 才变成 3。
所以:
z = 2 - 1 = 1容易踩坑点:
- 把
x++当成先加再用。
给新手的建议:
x++是先用后加,++x是先加后用。
填空题第 7 题
Section titled “填空题第 7 题”题目整理:
FILE *fw;fw = fopen("readme.txt", ____);要求:向文本文件 readme.txt 的最后续写内容。
答案:"a"
完整写法:
fw = fopen("readme.txt", "a");详细解析:
文件打开模式:
"r":只读"w":写入,会清空原内容"a":追加写入,从文件末尾继续写
容易踩坑点:
- 想“续写”却用了
"w",导致原内容被清空。
给新手的建议:
- append 追加,对应
"a"。
填空题第 8 题
Section titled “填空题第 8 题”题目整理:
(a = 5, b = 2, a > b ? a++ : b++, a + b)答案:8
详细解析:
先执行逗号表达式前两项:
a = 5b = 2然后看三目运算:
a > b -> 5 > 2 -> 真所以执行:
a++a++ 执行后,a 变成 6。
最后整个逗号表达式的值看最后一项:
a + b = 6 + 2 = 8容易踩坑点:
- 忘记逗号表达式的值看最后一个表达式。
- 忘记
a++会让a最终加 1。
给新手的建议:
- 逗号表达式和三目运算混在一起时,先拆成多行。
填空题第 9 题
Section titled “填空题第 9 题”题目问:unsigned int 定义无符号基本整型变量,分配几个字节?
答案:2 或 两
详细解析:
按传统 Turbo C 教材环境,unsigned int 占 2 个字节。
补充提醒:
现代很多编译器中,unsigned int 通常占 4 个字节。考试题如果没有特别说明,通常按教材环境答。
容易踩坑点:
- 把现代电脑环境和教材环境混在一起。
给新手的建议:
- 考试按题目环境;实际写程序用
sizeof(unsigned int)查看。
填空题第 10 题
Section titled “填空题第 10 题”题目问:将函数 fun 的入口地址赋给指针变量 p 的语句是什么?
答案:p = fun
完整语句:
p = fun;详细解析:
函数名 fun 可以表示函数入口地址。
如果已经定义了函数指针 p,那么:
p = fun;就是把函数 fun 的入口地址赋给 p。
容易踩坑点:
- 写成
p = fun(),这表示调用函数,而不是取函数地址。
给新手的建议:
- 函数名不加括号表示函数地址;加括号表示调用函数。
4. 判断题详解
Section titled “4. 判断题详解”判断题第 1 题
Section titled “判断题第 1 题”题目:通过 return 语句,函数可以带回一个或一个以上的返回值。
答案:N
解析:
return 语句一次只能直接返回一个值。
如果想让函数“带回多个结果”,常见做法是传地址或使用结构体。
判断题第 2 题
Section titled “判断题第 2 题”题目:
#define S(a, b) a * barea = S(3, 2);判断:area 的值为 6。
答案:Y
解析:
宏展开后:
area = 3 * 2;结果是 6。
补充提醒:
这个宏在更复杂表达式中可能有优先级问题,最好写成:
#define S(a, b) ((a) * (b))判断题第 3 题
Section titled “判断题第 3 题”题目整理:
a = 3;b = 2;c = 1;(a > b) == c判断:结果为真,即 1。
答案:Y
解析:
a > b -> 3 > 2 -> 真 -> 1c = 11 == 1 -> 真所以结果为 1。
判断题第 4 题
Section titled “判断题第 4 题”题目:
float a;scanf("%7.2f", &a);判断:这是合法语句。
答案:N
解析:
scanf 的格式控制中可以写宽度,比如:
scanf("%7f", &a);但不能像 printf 一样写精度 .2。
容易踩坑点:
- 把
printf("%.2f")的格式照搬到scanf。
判断题第 5 题
Section titled “判断题第 5 题”题目:
7 && 3 + 12判断:值是 13。
答案:N
解析:
先算加法:
3 + 12 = 15再算逻辑与:
7 && 15 -> 真 && 真 -> 1所以结果是 1,不是 13。
判断题第 6 题
Section titled “判断题第 6 题”题目:进行宏定义时,宏名必须使用大写字母表示。
答案:N
解析:
宏名常用大写只是编程习惯,不是语法强制要求。
判断题第 7 题
Section titled “判断题第 7 题”题目:
file *fp;fp = fopen("a.txt", "r");判断:在 Turbo C 中是合法的。
答案:N
解析:
文件指针类型应写成大写:
FILE *fp;file 不是标准写法。
判断题第 8 题
Section titled “判断题第 8 题”题目:整数 -32100 可以赋值给 int 型和 long int 型变量。
答案:Y
解析:
按传统 16 位有符号 int 环境:
-32768 ~ 32767-32100 在这个范围内,所以可以赋给 int,也可以赋给 long int。
判断题第 9 题
Section titled “判断题第 9 题”题目:
#define S(a, b) t = a; a = b; b = t判断:由于变量 t 没定义,所以此宏定义是错误的。
答案:N
解析:
宏定义本身只是文本替换规则,不会在定义时检查 t 是否定义。
但是使用这个宏时,如果展开后的代码里没有提前定义 t,编译会报错。
判断题第 10 题
Section titled “判断题第 10 题”题目:C 语言中求余运算符 % 要求两个操作数都必须是整型或字符型数据,不可以为实型数据。
答案:Y
解析:
% 只能用于整数类型。
正确:
7 % 3错误:
7.5 % 2容易踩坑点:
- 以为
%可以直接对小数求余。
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)当当前项仍然大于精度 eps 时,才继续累加。
第二处:
t = n / (2 * n + 1) * t;应改为:
t = t * n / (2.0 * n + 1.0);原因是要避免整数除法。如果写 n / (2 * n + 1),当 n = 1 时就是 1 / 3,整数除法结果为 0。
第三处:
return s;应改为:
return 2 * s;因为公式求的是 π / 2,所以最终要乘以 2。
容易踩坑点:
- 级数题条件写反。
- 忘记整数除法会截断小数。
- 忘记公式左边是
π / 2,不是π。
给新手的建议:
- 级数题先看“每一项怎么从上一项变来”,再写循环。
功能:按递归公式求函数值。
题目给出的例子:
n = 5 时,函数值为 240n = 3 时,函数值为 60整理后的正确代码:
#include <stdio.h>
int fun(int n){ int c;
if (n == 1) c = 15; else c = fun(n - 1) * 2;
return c;}
int main(void){ int n;
printf("Enter n:"); scanf("%d", &n);
printf("The result :%d\n\n", fun(n)); return 0;}错误说明:
第一处:
fun(double n)应改为:
int fun(int n)题目中的 n 是递归层数,应使用整数。
第二处:
if (n = 1)应改为:
if (n == 1)= 是赋值,== 才是判断相等。
补充修正:
原题里 scanf("%d" &n); 也缺少逗号,应写:
scanf("%d", &n);容易踩坑点:
- 递归出口条件写成赋值。
- 忘记
scanf的格式串和变量地址之间有逗号。
给新手的建议:
- 递归题先找出口,这题出口就是
n == 1。
6. 程序设计题详解
Section titled “6. 程序设计题详解”程序设计 1
Section titled “程序设计 1”功能:将从键盘输入的每个单词的第一个字母转换为大写字母。输入时各单词用空格隔开,用 . 结束输入。
参考答案:
#include <stdio.h>
int fun(char *c, int status){ if (*c == ' ') return 1;
if (status && *c >= 'a' && *c <= 'z') *c += 'A' - 'a';
return 0;}
int main(void){ int flag = 1; char ch;
printf("请输入一字符串,用点号结束输入!\n");
do { ch = getchar(); flag = fun(&ch, flag); putchar(ch); } while (ch != '.');
printf("\n"); return 0;}详细解题过程:
flag 表示当前字符是否是一个单词的开头:
flag = 1:当前字符是单词开头flag = 0:当前字符不是单词开头
如果读到空格:
if (*c == ' ') return 1;说明下一个非空格字符可能是新单词开头。
如果当前是单词开头,并且是小写字母:
if (status && *c >= 'a' && *c <= 'z') *c += 'A' - 'a';就把它转成大写。
容易踩坑点:
- 空格字符应写成
' ',不是空字符串。 - 判断小写字母范围要写
*c >= 'a' && *c <= 'z'。 flag = fun(&ch, flag);语句末尾是分号,不是冒号。do...while结尾要有分号。
给新手的建议:
- 这种题要先弄清楚状态变量
flag的含义,它不是随便起的变量。
程序设计 2
Section titled “程序设计 2”功能:给定 n 个数据,求最大值第一次出现的位置。
参考答案:
#include <stdio.h>
int station(int s[], int n){ int i, k;
k = 0; for (i = 1; i < n; i++) { if (s[i] > s[k]) k = i; }
return k + 1;}
int main(void){ int a[100], n, i, t;
scanf("%d", &n);
for (i = 0; i < n; i++) scanf("%d", &a[i]);
t = station(a, n); printf("the max value position is:%d\n", t);
return 0;}详细解题过程:
先假设第一个元素最大:
k = 0;从第二个元素开始比较:
for (i = 1; i < n; i++)如果发现更大的值,就记录它的下标:
if (s[i] > s[k]) k = i;最后返回:
return k + 1;因为题目要的是“位置”,通常从 1 开始数;而数组下标从 0 开始,所以要加 1。
为什么不用 >=?
题目说如果最大值出现多次,求第一次出现的位置。只有遇到“严格更大”的值才更新 k,所以应该用:
s[i] > s[k]不能用:
s[i] >= s[k]容易踩坑点:
- 原卷红字写了
i <= n,但数组合法下标是0 ~ n - 1,所以这里应写i < n。 - 题目要求第一次出现的位置,所以比较条件要用
>,不要用>=。 printf的格式串和变量之间要有逗号。
给新手的建议:
- “找最大值位置”题的模板是:先假设第 0 个最大,再从第 1 个开始比较。
7. 这套卷子最容易暴露的问题
Section titled “7. 这套卷子最容易暴露的问题”这套 exam-90 很适合检查下面这些基础:
- 数组初始化从
a[0]开始,不是从a[1]开始。 - 字符数组长度和字符串长度要分清。
- 函数定义不能嵌套,但函数调用可以嵌套。
- 普通变量、数组名、函数名作为参数时含义不同。
strcpy、strcat、strcmp的参数顺序要熟。scanf和printf的格式控制不能混用。- 递归题先找出口,再看递推关系。
8. 给新手的复习建议
Section titled “8. 给新手的复习建议”- 把选择题第 2、4、9、10、11、12、18、20、21、23、24 题放在一起复习,它们都和数组有关。
- 把选择题第 14、15、22、25 题放在一起复习,它们都和字符串有关。
- 把选择题第 6、7、8、13、16、17、19 题放在一起复习,它们都和函数有关。
- 填空题第 1 题建议手动画字符串右移过程。
- 程序设计第 2 题建议手写一遍,因为“第一次出现的位置”这个细节很容易写错。
9. 最后总结
Section titled “9. 最后总结”第 90 套卷子的重点依旧是 C 语言基础细节:
- 下标从
0开始 - 字符串以
'\0'结束 - 数组名常常代表首地址
- 函数名可以代表函数入口地址
=和==不能混- 整数除法会截断小数
这些点都不花哨,但很容易在考试和写代码时反复出错。你复习这套时,重点不要只背答案,要能说清楚每一题为什么这么选。