exam-89 试卷整理与详解
这份笔记是根据 89.pdf 整理出来的,原卷文件在本地路径:
/Users/wff/Downloads/89.pdf这套卷子的 OCR 错字比较多,尤其是代码里的逗号、分号、括号、引号、return、strcmp、strcat 等符号容易被识别错。我整理时按原卷红色标注和 C 语言语法一起校对,下面的代码都改成了更容易阅读和上机验证的写法。
这套题主要复习:
- 函数参数传递、函数返回值、函数调用方式
- 字符串比较、连接、复制
- 一维数组、二维数组初始化和下标
- 字符数组和字符串长度
- 结构体、共用体、宏定义
switch、逻辑表达式、三目运算符- 程序改错和字符串处理程序设计
1. 答案速查
Section titled “1. 答案速查”1.1 选择题答案
Section titled “1.1 选择题答案”| 题号 | 答案 |
|---|---|
| 1 | D |
| 2 | A |
| 3 | A |
| 4 | C |
| 5 | C |
| 6 | A |
| 7 | A |
| 8 | C |
| 9 | D |
| 10 | B |
| 11 | B |
| 12 | B |
| 13 | A |
| 14 | C |
| 15 | C |
| 16 | B |
| 17 | A |
| 18 | A |
| 19 | C |
| 20 | C |
| 21 | D |
| 22 | B |
| 23 | B |
| 24 | B |
| 25 | D |
1.2 填空题答案
Section titled “1.2 填空题答案”| 题号 | 答案 |
|---|---|
| 1 | 15 |
| 2 | a=26,b=14,c=19 |
| 3 | 1 |
| 4 | 0 |
| 5 | 0 |
| 6 | 类型 |
| 7 | 8 |
| 8 | 9 |
| 9 | 3 |
| 10 | 5.169 |
1.3 判断题答案
Section titled “1.3 判断题答案”| 题号 | 答案 |
|---|---|
| 1 | Y |
| 2 | N |
| 3 | Y |
| 4 | Y |
| 5 | N |
| 6 | Y |
| 7 | N |
| 8 | Y |
| 9 | N |
| 10 | N |
2. 选择题详解
Section titled “2. 选择题详解”选择题第 1 题
Section titled “选择题第 1 题”题目问:调用函数时,如果实参是简单变量,它和对应形参之间的数据传递方式是什么?
答案:D
详细解析:
C 语言中,普通变量作为实参时,采用值传递。
例如:
void fun(int x){ x = 100;}
int a = 10;fun(a);函数里改的是形参 x,不会直接改外面的 a。
容易踩坑点:
- 以为函数里改了形参,外面的实参也会自动改变。
给新手的建议:
- 普通变量传参:传的是值。
- 想在函数里改外面的变量:通常要传地址。
选择题第 2 题
Section titled “选择题第 2 题”题目问:以下对 C 语言函数的描述中,正确的是哪一个?
答案:A
正确说法:
C 程序必须由一个或一个以上的函数组成。详细解析:
一个 C 程序至少要有一个 main 函数,因为程序从 main 开始执行。
其他选项的问题:
- 有调用关系的函数不一定必须放在同一个源文件中。
- 函数可以没有返回值,此时返回类型写
void。 - C 函数可以递归调用,但标准 C 语言不允许函数嵌套定义。
容易踩坑点:
- 把“嵌套调用”和“嵌套定义”混为一谈。
给新手的建议:
- C 函数可以互相调用,也可以自己调用自己,但不能在一个函数里面再定义另一个函数。
选择题第 3 题
Section titled “选择题第 3 题”题目整理:
int max(int x, int y){ int z;
if (x > y) z = x; else z = y;
return z;}
int a = 45, b = 27, c = 0;c = max(a, b);printf("%d\n", c);答案:A
详细解析:
调用:
max(45, 27)因为 45 > 27,所以返回 45。
最终输出:
45容易踩坑点:
- OCR 里
return、分号、逗号可能识别错,但题目核心是求两个数最大值。
给新手的建议:
- 函数题先看函数功能,再代入实参。
选择题第 4 题
Section titled “选择题第 4 题”题目问:判断两个字符串是否相等,正确的表达方式是哪一个?
答案:C
正确写法:
while (strcmp(s1, s2) == 0)详细解析:
strcmp(s1, s2) 的返回规则:
- 等于
0:两个字符串相等 - 大于
0:s1大于s2 - 小于
0:s1小于s2
不能写:
s1 == s2这比较的是地址,不是字符串内容。
容易踩坑点:
- 字符串比较内容不能直接用
==。
给新手的建议:
- 字符串比较用
strcmp,字符串复制用strcpy,字符串连接用strcat。
选择题第 5 题
Section titled “选择题第 5 题”题目整理:
char array[] = "China";问:数组 array 所占空间是多少?
答案:C
详细解析:
"China" 有 5 个可见字符:
C h i n a字符串末尾还有一个 '\0'。
所以一共占:
5 + 1 = 6容易踩坑点:
- 忘记字符串结束符
'\0'也占一个字节。
给新手的建议:
- 字符串初始化字符数组时,数组空间通常是“可见字符数 + 1”。
选择题第 6 题
Section titled “选择题第 6 题”题目问:以下正确的函数首部形式是哪一个?
答案:A
正确写法:
double fun(int x, int y)详细解析:
每个形参都要写类型:
int x, int y不能写:
int x, y另外,函数定义的函数首部后面直接跟函数体,不写分号。
容易踩坑点:
- 把
int x, y当成两个形参都有类型。 - 把函数声明和函数定义首部混淆。
给新手的建议:
- 函数形参表里,每个参数都单独写类型,最稳。
选择题第 7 题
Section titled “选择题第 7 题”题目整理:
char a1[] = "abc", a2[80] = "1234";问:将 a1 串连接到 a2 串后面,应写哪一句?
答案:A
正确写法:
strcat(a2, a1);详细解析:
strcat(目标串, 源串) 的意思是:把源串连接到目标串后面。
执行后 a2 变成:
1234abc容易踩坑点:
- 把
strcat(a1, a2)和strcat(a2, a1)写反。
给新手的建议:
strcpy和strcat都是第一个参数被修改。
选择题第 8 题
Section titled “选择题第 8 题”题目问:以下不能对二维数组 a 正确初始化的是哪一个?
答案:C
错误写法:
int a[2][3] = {{1, 2}, {3, 4}, {5, 6}};详细解析:
a[2][3] 表示 2 行 3 列。
但上面的初始化写了 3 行:
{1, 2}{3, 4}{5, 6}行数超过了定义的 2 行,所以错误。
容易踩坑点:
- 少写初值可以补
0,多写超出数组范围就不行。
给新手的建议:
- 二维数组初始化时,先数行数,再数列数。
选择题第 9 题
Section titled “选择题第 9 题”题目问:以下不正确的定义语句是哪一个?
答案:D
错误写法:
int y[5] = {0, 1, 3, 5, 7, 9};详细解析:
数组 y[5] 只能存 5 个元素,但初始化列表里给了 6 个值:
0 1 3 5 7 9所以错误。
容易踩坑点:
- 只看数组名和类型,没数初始化元素个数。
给新手的建议:
- 数组初始化题,一定先比较“数组长度”和“初值个数”。
选择题第 10 题
Section titled “选择题第 10 题”题目整理:
int a[][4] = {0, 0};问:下面不正确的叙述是哪一个?
答案:B
详细解析:
二维数组第二维是 4,给了两个初值,所以第一维可以推断为 1。
实际数组可以看作:
0 0 0 0没显式写到的元素也会自动补 0。
选项 B 说只有 a[0][0] 和 a[0][1] 得到初值 0,其余元素得不到初值 0,这是错误的。
容易踩坑点:
- 以为没写出来的元素就是随机值。
给新手的建议:
- 数组只要有初始化列表,没写到的部分一般自动补
0。
选择题第 11 题
Section titled “选择题第 11 题”题目问:以下不能正确定义二维数组的是哪一个?
答案:B
错误写法:
int a[2][] = {{1, 2}, {3, 4}};详细解析:
二维数组定义时,第二维不能省略。
正确写法应是:
int a[2][2] = {{1, 2}, {3, 4}};容易踩坑点:
- 以为已经写了初始化列表,所以第二维也可以省。
给新手的建议:
- 二维数组可以省第一维,不能省第二维。
选择题第 12 题
Section titled “选择题第 12 题”题目整理:
char a[10];问:哪句不能从键盘给数组 a 的所有元素输入值?
答案:B
错误写法:
a = getchar();详细解析:
数组名 a 不能作为赋值号左边整体赋值。
而且 getchar() 只能读一个字符,不可能直接给整个数组赋值。
容易踩坑点:
- 把字符数组当成单个字符变量。
给新手的建议:
- 字符数组整体输入可用
scanf("%s", a)。 - 逐个字符输入要写
a[i] = getchar()。
选择题第 13 题
Section titled “选择题第 13 题”题目整理:
fun(float x){ float y; y = 3 * x - 4; return y;}问:fun 函数返回值类型是什么?
答案:A
详细解析:
这个函数名前面没有显式写返回类型。
按老式 C 语言教材口径,如果函数没有显式说明返回类型,默认返回类型是 int。
所以答案是 int。
补充提醒:
现代 C 语言已经不推荐甚至不允许这种隐式 int 写法,实际写代码时应该明确写:
float fun(float x)容易踩坑点:
- 以为
return y中y是float,所以函数返回类型就是float。
给新手的建议:
- 函数返回类型看函数名前面的类型,不是只看
return后面的表达式。
选择题第 14 题
Section titled “选择题第 14 题”题目问:下列描述中不正确的是哪一个?
答案:C
错误说法:
可以对整型数组进行整体输入、输出。详细解析:
整型数组一般要逐个元素输入输出:
for (i = 0; i < n; i++) scanf("%d", &a[i]);字符数组如果存的是字符串,可以整体输入输出:
scanf("%s", s);printf("%s", s);容易踩坑点:
- 把整型数组和字符数组字符串混成一类。
给新手的建议:
- 整型数组逐个处理。
- 字符数组作为字符串时,可以用
%s整体处理。
选择题第 15 题
Section titled “选择题第 15 题”题目问:以下对二维数组 a 的正确说明是哪一个?
答案:C
正确写法:
double a[1][4];详细解析:
二维数组定义格式:
类型名 数组名[行数][列数];其他选项的问题:
int a[3][]第二维省略,错误。float a(3)(4)不是 C 语言数组定义。float a(3,4)也不是数组定义。
容易踩坑点:
- 把数学里的括号写法带到 C 语言里。
给新手的建议:
- 数组使用方括号
[],不是圆括号()。
选择题第 16 题
Section titled “选择题第 16 题”题目整理:
int a[10];问:对 a 数组元素的正确引用是哪一个?
答案:B
正确写法:
a[10 - 10]详细解析:
a[10 - 10] 等价于:
a[0]这是合法数组元素。
a[10] 越界,因为合法下标是:
0 ~ 9容易踩坑点:
- 数组长度是 10,最后下标却是 9。
给新手的建议:
- 数组下标从
0开始,这个点要反复提醒自己。
选择题第 17 题
Section titled “选择题第 17 题”题目整理:
func(rec1, rec2 + rec3, (rec4, rec5));问:这个函数调用语句中有几个实参?
答案:A
详细解析:
最外层实参有 3 个:
rec1rec2 + rec3(rec4, rec5)括号里的逗号属于逗号表达式,不增加实参个数。
容易踩坑点:
- 把
(rec4, rec5)看成两个参数。
给新手的建议:
- 数参数,只看最外层逗号。
选择题第 18 题
Section titled “选择题第 18 题”题目问:能对一维数组正确初始化的语句是哪一个?
答案:A
正确写法:
int a[6] = {6 * 1};详细解析:
这句是合法的,它会把第一个元素初始化为 6,其余元素补 0:
6 0 0 0 0 0其他选项的问题:
- 数组初始化应该用
{},不能用()。 - 空的
{}在传统教材语境里通常不作为正确写法。 int a[6] = {1,,,3};中间缺少表达式。
容易踩坑点:
- 以为
{6 * 1}会让 6 个元素都变成 1。
给新手的建议:
- 初始化列表里有几个值,就按顺序初始化几个元素;剩下的补
0。
选择题第 19 题
Section titled “选择题第 19 题”题目问:以下程序段中,不能正确赋字符串的是哪一个?
答案:C
错误写法:
char s[10];s = "abcdefg";详细解析:
数组名不能作为赋值号左边整体赋值。
如果定义后再给字符数组赋字符串,应该用:
strcpy(s, "abcdefg");容易踩坑点:
- 把字符数组名当成普通变量。
给新手的建议:
- 定义时可以初始化:
char s[10] = "abcdefg"; - 定义后再复制:
strcpy(s, "abcdefg");
选择题第 20 题
Section titled “选择题第 20 题”题目问:C 语言程序中,如果对函数类型不加显式说明,则函数的隐含说明类型是什么?
答案:C
详细解析:
按老式 C 语言教材口径,未显式说明返回类型时,默认是 int。
例如:
fun(void){ return 1;}会被看作返回 int。
补充提醒:
现代 C 语言不建议这样写,实际写代码要明确返回类型:
int fun(void)容易踩坑点:
- 以为没写类型就是
void。
给新手的建议:
- 考试按老教材记:不写返回类型,默认
int。 - 自己写代码时别省略返回类型。
选择题第 21 题
Section titled “选择题第 21 题”题目整理:
int a[10];问:给数组 a 的所有元素分别赋值为 1, 2, 3, ... 的语句是哪一个?
答案:D
正确写法:
for (i = 1; i < 11; i++) a[i - 1] = i;详细解析:
i 从 1 到 10,而数组下标需要从 0 到 9:
i = 1 -> a[0] = 1i = 2 -> a[1] = 2...i = 10 -> a[9] = 10容易踩坑点:
- 循环变量从 1 开始时,忘记数组下标要减 1。
给新手的建议:
- 值从
1开始,下标从0开始,常见搭配是a[i - 1] = i。
选择题第 22 题
Section titled “选择题第 22 题”题目问:C 语言中函数调用的方式有哪些?
答案:B
详细解析:
函数调用常见三种方式:
第一种,作为语句:
printf("hello\n");第二种,作为表达式的一部分:
x = max(a, b);第三种,作为另一个函数的参数:
printf("%d\n", max(a, b));容易踩坑点:
- 只记得函数可以单独调用,忘记它还可以放在表达式或实参里。
给新手的建议:
- 看到函数调用,先看它所在位置:单独一句、等号右边、还是另一个函数的括号里。
选择题第 23 题
Section titled “选择题第 23 题”题目整理:
int a[3][4] = {0};答案:B
详细解析:
= {0} 会让数组所有元素都初始化为 0。
可以理解为:
0 0 0 00 0 0 00 0 0 0容易踩坑点:
- 以为只有
a[0][0]是0。
给新手的建议:
- 数组的
{0}初始化,是非常常见的全 0 初始化。
选择题第 24 题
Section titled “选择题第 24 题”题目整理:
static char str[10] = "china";问:数组元素个数是多少?
答案:B
详细解析:
数组长度已经明确写在方括号里:
str[10]所以数组元素个数是 10。
字符串 "china" 只决定前几个元素的初值,不改变数组长度。
容易踩坑点:
- 把字符串长度
5或占用空间6当成数组元素个数。
给新手的建议:
- 题目问“数组元素个数”,优先看方括号里的数字。
选择题第 25 题
Section titled “选择题第 25 题”题目整理:
#include <stdio.h>
int z;
int p(int x){ static int y; return x + y;}
void main(void){ int a, b;
printf("%d\n", p(a));}问:如果不再定义新的变量,在 main 函数中可以使用的所有变量有哪些?
答案:D
详细解析:
在 main 中可以直接使用:
a:main的局部变量b:main的局部变量z:全局变量
不能直接使用:
x:函数p的形参,只在p内有效y:函数p的静态局部变量,只在p内有效
所以答案是:
a, b, z容易踩坑点:
- 以为
static局部变量可以在别的函数里直接访问。
给新手的建议:
- 变量能不能用,先看它定义在哪个作用域。
3. 填空题详解
Section titled “3. 填空题详解”填空题第 1 题
Section titled “填空题第 1 题”题目:字符串 \\name\\101ddress\b\xaf 的长度。
答案:15
详细解析:
这题主要考转义字符。按卷面给出的答案,字符串长度为 15。
转义字符题要记住:
\\表示一个反斜杠字符\b表示一个退格字符\x..表示十六进制转义字符- 八进制或十六进制转义序列整体通常按一个字符来数
补充提醒:
这道题的 OCR 识别不太清楚,反斜杠个数会直接影响长度。考试时要以原题字符串为准,做题方法是把每个转义序列圈起来,一个转义序列按一个字符数。
容易踩坑点:
- 把
\b当成两个普通字符。 - 把
\x..拆开数。
给新手的建议:
- 转义字符长度题,不要从左到右硬数,先把所有反斜杠开头的转义序列标出来。
填空题第 2 题
Section titled “填空题第 2 题”题目整理:
int a = 25, b = 14, c = 19;
a++ <= 2 && b-- <= 2 && c++ ? printf("***a=%d,b=%d,c=%d\n", a, b, c) : printf("a=%d,b=%d,c=%d\n", a, b, c);答案:a=26,b=14,c=19
详细解析:
先看第一个条件:
a++ <= 2a++ 先使用旧值 25,再让 a 变成 26。
25 <= 2结果是假。
由于 && 有短路特性,后面的:
b-- <= 2c++都不会执行。
所以:
a = 26b = 14c = 19条件为假,执行冒号后面的 printf。
容易踩坑点:
- 忘记
a++虽然比较用旧值,但变量本身已经加 1。 - 忘记
&&前面为假时,后面不再计算。
给新手的建议:
- 遇到
&&和++混在一起,一定按短路规则一步一步算。
填空题第 3 题
Section titled “填空题第 3 题”题目:
a = 13;b = 6;a && b答案:1
详细解析:
13 和 6 都是非 0,在 C 语言里都表示真。
真 && 真 = 真所以结果为 1。
容易踩坑点:
- 以为
&&会返回原来的数字。
给新手的建议:
- 逻辑运算结果通常是
0或1。
填空题第 4 题
Section titled “填空题第 4 题”题目整理:
a = 12;(0 < a) && (a < 2)答案:0
详细解析:
0 < 12 -> 真12 < 2 -> 假真 && 假 -> 假所以结果为 0。
容易踩坑点:
- 只看到
0 < a成立,就忘记后面还要同时成立。
填空题第 5 题
Section titled “填空题第 5 题”题目整理:
int x = 2, y = 3, z = 4;x + y && x == y答案:0
详细解析:
先按优先级理解:
(x + y) && (x == y)计算:
x + y = 5 -> 真x == y -> 2 == 3 -> 假真 && 假 -> 假所以结果是 0。
容易踩坑点:
- 对
+、==、&&的优先级不熟。
给新手的建议:
- 表达式题不确定时,先手动加括号。
填空题第 6 题
Section titled “填空题第 6 题”题目:结构体是不同数据类型的数据集合,作为数据类型,必须先定义结构体什么,再定义结构体变量?
答案:类型
详细解析:
结构体使用时通常先定义结构体类型:
struct Student{ int id; char name[20];};再定义结构体变量:
struct Student s1;容易踩坑点:
- 把结构体类型和结构体变量混在一起。
给新手的建议:
struct Student是类型,s1才是变量。
填空题第 7 题
Section titled “填空题第 7 题”题目给出数组:
下标:0 1 2 3 4 5 6 7 8 9元素:9 4 12 8 2 10 7 5 1 3问:数值最小的元素下标是多少?
答案:8
详细解析:
最小值是 1,它位于:
a[8]所以答案是 8。
容易踩坑点:
- 把第 9 个位置错写成下标
9。
给新手的建议:
- 数组题要把“第几个”和“下标是多少”分开,下标从
0开始。
填空题第 8 题
Section titled “填空题第 8 题”题目整理:
int f(int x, int y){ return (y - x) * x;}
int a = 3, b = 4, c = 5, d;d = f(f(3, 4), f(3, 5));printf("%d\n", d);答案:9
详细解析:
先算内层:
f(3, 4) = (4 - 3) * 3 = 3f(3, 5) = (5 - 3) * 3 = 6再算外层:
f(3, 6) = (6 - 3) * 3 = 9所以输出 9。
容易踩坑点:
- 函数嵌套调用时,没有先算内层。
给新手的建议:
- 嵌套函数调用按“从内到外”代值。
填空题第 9 题
Section titled “填空题第 9 题”题目整理:
int a = 1, b = 2, c = 3;
if (a > c) b = a;a = c;c = b;问:执行后 a 的值是多少?
答案:3
详细解析:
先判断:
a > c -> 1 > 3 -> 假所以:
b = a;不会执行。
后面两句不属于 if,一定会执行:
a = c; // a = 3c = b; // c = 2所以 a = 3。
容易踩坑点:
- 没有大括号时,
if只控制紧跟着的一条语句。
给新手的建议:
- 新手写
if时建议总是加{},减少误解。
填空题第 10 题
Section titled “填空题第 10 题”题目整理:
float x;x = 5.16894;(int)(x * 1000 + 0.5) / (float)1000答案:5.169
详细解析:
先算:
x * 1000 = 5168.94x * 1000 + 0.5 = 5169.44强制转换为 int 后,小数部分被截断:
(int)5169.44 = 5169再除以 1000.0:
5169 / 1000.0 = 5.169这个写法相当于保留三位小数的四舍五入。
容易踩坑点:
- 以为
(int)是四舍五入,其实它是直接截断。 +0.5才是实现四舍五入的关键。
给新手的建议:
- 保留小数题要分清“截断”和“四舍五入”。
4. 判断题详解
Section titled “4. 判断题详解”判断题第 1 题
Section titled “判断题第 1 题”题目:C 语言本身不提供输入输出语句,输入和输出操作由函数实现。
答案:Y
解析:
C 语言的输入输出通常通过标准库函数实现,例如:
printf();scanf();getchar();putchar();判断题第 2 题
Section titled “判断题第 2 题”题目:
char array[] = "hello";判断:数组 array 所占空间为 5 个字节。
答案:N
解析:
"hello" 有 5 个可见字符,但还要加结尾的 '\0'。
所以占 6 个字节。
判断题第 3 题
Section titled “判断题第 3 题”题目:共用体变量所占的内存长度等于最长成员的长度。
答案:Y
解析:
按教材口径,共用体成员共用同一块内存,所以所占空间按最长成员计算。
补充提醒:
实际编译器还可能考虑内存对齐,但入门考试一般按最长成员长度判断。
判断题第 4 题
Section titled “判断题第 4 题”题目整理:
a = 3;b = 2;c = 1;(a > b) == c判断:值为真,即为 1。
答案:Y
解析:
a > b -> 3 > 2 -> 真 -> 1c = 11 == 1 -> 真所以结果为 1。
判断题第 5 题
Section titled “判断题第 5 题”题目:C 语言的 switch 语句中,case 后可以是常量、常量表达式,也可以是有确定值的变量。
答案:N
解析:
case 后面必须是整型常量表达式,不能是普通变量。
正确:
case 1:case 2 + 3:不正确:
case x:判断题第 6 题
Section titled “判断题第 6 题”题目整理:
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。
答案:Y
解析:
数组补全后:
3 5 08 9 012 35 0取的元素是:
a[0][2] = 0a[1][1] = 9a[2][0] = 12所以:
sum = 0 + 9 + 12 = 21判断题第 7 题
Section titled “判断题第 7 题”题目整理:
int i = 20;
switch (i / 10){case 2: printf("A");case 1: printf("B");}判断:输出结果为 A。
答案:N
解析:
i / 10 = 2,所以先进入 case 2,输出 A。
但 case 2 后面没有 break,程序会继续执行 case 1,再输出 B。
实际输出:
AB判断题第 8 题
Section titled “判断题第 8 题”题目:整数 -32100 可以赋值给 int 型和 long int 型变量。
答案:Y
解析:
按传统 16 位有符号 int 环境:
-32768 ~ 32767-32100 在范围内,可以赋给 int,也可以赋给 long int。
判断题第 9 题
Section titled “判断题第 9 题”题目:
int a[10] = {1 * 10};判断:可以使数组中全部元素的值为 1。
答案:N
解析:
1 * 10 的结果是 10。
所以数组实际初始化为:
10 0 0 0 0 0 0 0 0 0不是全部元素都是 1。
判断题第 10 题
Section titled “判断题第 10 题”题目:宏定义中使用了变量 t,由于变量 t 没定义,所以此宏定义是错误的。
答案:N
解析:
宏定义本身只是文本替换规则,不会在定义时检查变量 t 是否存在。
但如果使用宏展开后,代码里没有提前定义 t,编译时会报错。
易错点:
- 宏定义阶段和宏展开后编译阶段不是一回事。
5. 改错题详解
Section titled “5. 改错题详解”功能:根据企业当月利润计算奖金。
规则整理:
- 利润
<= 10 万:奖金为利润的10% 10 万 ~ 20 万:超过 10 万部分按7.5%20 万 ~ 40 万:超过 20 万部分按5%40 万 ~ 60 万:超过 40 万部分按3%60 万 ~ 100 万:超过 60 万部分按1.5%> 100 万:超过 100 万部分按1%
整理后的正确代码:
#include <stdio.h>
int main(void){ long int i; double bonus1, bonus2, bonus4, bonus6, bonus10, bonus;
scanf("%ld", &i);
bonus1 = 100000 * 0.1; bonus2 = bonus1 + 100000 * 0.075; bonus4 = bonus2 + 200000 * 0.05; bonus6 = bonus4 + 200000 * 0.03; bonus10 = bonus6 + 400000 * 0.015;
if (i <= 100000) bonus = i * 0.1; else if (i <= 200000) bonus = bonus1 + (i - 100000) * 0.075; else if (i <= 400000) bonus = bonus2 + (i - 200000) * 0.05; else if (i <= 600000) bonus = bonus4 + (i - 400000) * 0.03; else if (i <= 1000000) bonus = bonus6 + (i - 600000) * 0.015; else bonus = bonus10 + (i - 1000000) * 0.01;
printf("bonus=%f\n", bonus); return 0;}原题中主要错误:
第一处:
scanf("%ld" &i);应改为:
scanf("%ld", &i);第二处:
if (i > 100000)应改为:
if (i <= 100000)第三处:
printf("bonus=%d", bonus)应补分号,并且因为 bonus 是 double,更稳的输出格式是:
printf("bonus=%f\n", bonus);容易踩坑点:
scanf的格式串和变量地址之间要有逗号。- 分段计算奖金时,区间边界很容易写反。
double类型输出应用%f。
给新手的建议:
- 分段计算题先画区间,再写
if...else if...else。
功能:输入一个字符串,将其中的字符 'a' 替换成字符串 "shu" 后输出。
例如:
输入:123abcaHello输出:123shubcshuHello整理后的正确代码:
#include <stdio.h>
int main(void){ int i; char line[81];
scanf("%80s", line);
for (i = 0; line[i] != '\0'; i++) { if (line[i] == 'a') printf("shu"); else printf("%c", line[i]); }
printf("\n"); return 0;}原题中主要错误:
第一处:
scanf("%s", &line);应改为:
scanf("%s", line);字符数组名本身就是首地址,不需要再写 &。
第二处:
for (i = 0; line[i] != '\n'; i++)应改为:
for (i = 0; line[i] != '\0'; i++)字符串结束标志是 '\0',不是换行符。
第三处:
if (line[i] = 'a')应改为:
if (line[i] == 'a')= 是赋值,== 才是判断相等。
第四处:
printf("%s", line[i]);应改为:
printf("%c", line[i]);line[i] 是单个字符,应该用 %c。
容易踩坑点:
- 字符数组输入时不要写
&line。 - 字符串结束符是
'\0'。 - 判断相等用
==。 - 单个字符输出用
%c,字符串输出用%s。
给新手的建议:
- 这道题很适合练习“逐个字符扫描字符串”的模板。
6. 程序设计题详解
Section titled “6. 程序设计题详解”程序设计 1
Section titled “程序设计 1”功能:对长度为 8 个字符的字符串,将 8 个字符按降序排列。
例如:
原字符串:CEAedcab排序后:edcbaECA参考答案:
#include <stdio.h>
void fun(char *s, int num){ int i, j; char t;
for (i = 0; i < num; i++) { for (j = i + 1; j < num; j++) { if (s[i] < s[j]) { t = s[i]; s[i] = s[j]; s[j] = t; } } }}
int main(void){ char s[10];
printf("输入 8 个字符的字符串:"); scanf("%9s", s);
fun(s, 8); printf("\n%s\n", s);
return 0;}详细解题过程:
这题本质是字符排序,和整数排序思路一样。
外层循环固定当前位置:
for (i = 0; i < num; i++)内层循环找后面更大的字符:
for (j = i + 1; j < num; j++)如果后面的字符更大,就交换:
if (s[i] < s[j])因为题目要求降序,所以大的字符要放前面。
容易踩坑点:
- 降序条件应是
s[i] < s[j],不是s[i] > s[j]。 - 字符比较用的是字符编码顺序,通常小写字母编码大于大写字母。
给新手的建议:
- 排序题先明确“升序还是降序”,再决定交换条件。
程序设计 2(原卷编号 3)
Section titled “程序设计 2(原卷编号 3)”功能:统计一个长度为 2 的字符串在另一个字符串中出现的次数。
例如:
主字符串:asdasasafgasdaszx67asdmklo子字符串:as输出:6参考答案:
#include <stdio.h>#include <string.h>
int fun(char *str, char *substr){ int i; int n = 0; int len = strlen(str);
for (i = 0; i <= len - 2; i++) { if (str[i] == substr[0] && str[i + 1] == substr[1]) n++; }
return n;}
int main(void){ char str[81], substr[3]; int n;
printf("输入主字符串:"); scanf("%80s", str);
printf("输入子字符串:"); scanf("%2s", substr);
n = fun(str, substr); printf("n=%d\n", n);
return 0;}详细解题过程:
因为子字符串长度为 2,所以每次只需要比较两个字符:
str[i] == substr[0]str[i + 1] == substr[1]如果两个都相等,就说明从 str[i] 位置开始出现了一次子字符串:
n++;循环条件写成:
i <= strlen(str) - 2原因是最后一次比较要访问 str[i + 1],所以 i 不能超过倒数第二个字符的位置。
容易踩坑点:
- 循环写成
i < strlen(str),导致访问str[i + 1]越界。 printf("n=%d\n" n);少了逗号,应写printf("n=%d\n", n);。substr[3]是为了存两个字符加一个'\0'。
给新手的建议:
- 子串匹配题先确定“每次比较几个字符”,再决定循环到哪里结束。
7. 这套卷子最容易暴露的问题
Section titled “7. 这套卷子最容易暴露的问题”这套 exam-89 比较集中地考了这些基础:
- 普通变量传参是值传递。
- 字符串不能直接用
==比较内容。 - 字符数组长度和字符串长度要分清。
- 二维数组第二维不能省略。
- 函数不写返回类型时,老教材按
int处理。 switch没有break会继续往下执行。- 字符数组输入不需要写
&。
8. 给新手的复习建议
Section titled “8. 给新手的复习建议”- 把选择题第 1、13、20、22、25 题放在一起看,它们都和函数有关。
- 把选择题第 4、5、7、12、14、19、24 题放在一起看,它们都和字符串有关。
- 把选择题第 8、10、11、15、16、18、21、23 题放在一起看,它们都和数组有关。
- 改错题 2 很值得手敲一遍,因为它把
scanf、'\0'、==、%c这几个新手高频错误集中在一起了。 - 程序设计 1 练排序,程序设计 2 练字符串扫描,这两类题后面还会反复出现。
9. 最后总结
Section titled “9. 最后总结”第 89 套试卷的重点不是难算法,而是 C 语言基础细节是否稳定:
- 函数调用时传的是值还是地址
- 数组下标是否越界
- 字符串是否带
'\0' scanf参数要不要加&=和==是否分清switch是否需要break
这些点看起来小,但考试和写程序时都特别容易扣分。把这套题吃透,对数组、字符串和函数这三块会很有帮助。