exam-83 试卷整理与详解
这份笔记是根据 83.pdf 整理出来的,原卷文件在本地路径:
/Users/wff/Downloads/83.pdf这套题继续围绕 C 语言基础展开:函数调用、函数返回类型、数组定义与初始化、二维数组行列位置、字符串结束符、局部变量作用域、位运算、宏定义、switch、改错题和程序设计题。
PDF 的 OCR 对代码符号有一些误差,比如 '\0'、||、&&、==、数组方括号和花括号容易识别错。我整理时按原卷红色标注和 C 语言语法一起校对。
特别提醒:
- 选择题第 14 题,原卷按老式 C 语言口径:函数名前没有写返回类型时,默认返回
int。现代 C 不推荐也不应这样写,实际代码请明确写返回类型。 - 选择题第 19 题,原卷红字标的是
[整型常量]。更严谨的教材表达常见为[常量表达式],但这套卷子按原卷答案整理为B,解析里会说明。 - 填空题第 7 题的
a | b是按位或,不是逻辑或||,这里很容易看错。
1. 答案速查
Section titled “1. 答案速查”1.1 选择题答案
Section titled “1.1 选择题答案”| 题号 | 答案 |
|---|---|
| 1 | C |
| 2 | A |
| 3 | D |
| 4 | B |
| 5 | A |
| 6 | B |
| 7 | A |
| 8 | D |
| 9 | D |
| 10 | D |
| 11 | B |
| 12 | B |
| 13 | C |
| 14 | C |
| 15 | A |
| 16 | C |
| 17 | A |
| 18 | B |
| 19 | B(原卷口径) |
| 20 | D |
| 21 | B |
| 22 | C |
| 23 | B |
| 24 | B |
| 25 | C |
1.2 填空题答案
Section titled “1.2 填空题答案”| 题号 | 答案 |
|---|---|
| 1 | 0 |
| 2 | 0 |
| 3 | 3 |
| 4 | 0 |
| 5 | 4 |
| 6 | 5.0,4,c=3 |
| 7 | 15 |
| 8 | 20 |
| 9 | x % 2 == 0 等合法写法 |
| 10 | 5 |
1.3 判断题答案
Section titled “1.3 判断题答案”| 题号 | 答案 |
|---|---|
| 1 | N |
| 2 | N |
| 3 | Y |
| 4 | Y |
| 5 | Y |
| 6 | N |
| 7 | Y |
| 8 | Y |
| 9 | N |
| 10 | N |
2. 选择题详解
Section titled “2. 选择题详解”选择题第 1 题
Section titled “选择题第 1 题”题目整理:
func((e1, e2), (e3, e4, e5))问:函数调用语句中实参的个数是多少?
答案:C
详细解析:
这个函数调用最外层只有两个实参:
(e1, e2)(e3, e4, e5)括号里的逗号属于逗号表达式,不是函数参数分隔符。
所以实参个数是:
2容易踩坑点:
- 一看到逗号就直接数成 5 个。
- 忘记只有最外层逗号才分隔函数实参。
给新手的建议:
- 数实参个数时,先找到函数调用最外层的小括号,再只数最外层逗号。
选择题第 2 题
Section titled “选择题第 2 题”题目问:下列叙述中正确的是哪一个?
答案:A
正确说法:
C 语言的函数不可以嵌套定义。详细解析:
C 语言可以嵌套调用函数:
printf("%d\n", max(a, b));但不能在一个函数内部再定义另一个函数:
int main(void){ int fun(void) // 错误 { return 1; }}其他选项的问题:
- C 语言不是所有函数都是外部函数,
static函数可以是内部函数。 - C 语言编译时当然会检查语法。
- C 语言中通常把子程序统一称为函数,没有“过程”和“函数”两类的语法区分。
容易踩坑点:
- 把“函数嵌套调用”和“函数嵌套定义”混为一谈。
给新手的建议:
- 调用可以嵌套,定义不可以嵌套。
选择题第 3 题
Section titled “选择题第 3 题”题目整理:
int a[10];问:给数组 a 的所有元素分别赋值为 1、2、3、... 的语句是哪一个?
答案:D
正确写法:
for (i = 1; i < 11; i++) a[i - 1] = i;详细解析:
当 i = 1 时:
a[i - 1] = a[0] = 1当 i = 2 时:
a[i - 1] = a[1] = 2一直到 i = 10:
a[i - 1] = a[9] = 10刚好给 a[0] ~ a[9] 赋值。
容易踩坑点:
- 写成
a[i] = i会漏掉a[0],还会访问a[10]越界。 - 数组长度是 10,合法下标是
0 ~ 9。
给新手的建议:
- 给长度为 10 的数组赋值时,最终一定要覆盖
a[0]到a[9]。
选择题第 4 题
Section titled “选择题第 4 题”题目问:以下数组定义中不正确的是哪一个?
答案:B
错误写法:
int d[3][] = {{1, 2}, {1, 2, 3}, {1, 2, 3, 4}};详细解析:
二维数组定义时,第二维不能省略。
错误点在:
d[3][]编译器必须知道每一行有几个元素,才能计算 d[i][j] 的地址。
可以这样写:
int d[][4] = {{1, 2}, {1, 2, 3}, {1, 2, 3, 4}};容易踩坑点:
- 以为有初始化列表就可以省略第二维。
给新手的建议:
- 二维数组口诀:第一维可以省,第二维必须写。
选择题第 5 题
Section titled “选择题第 5 题”题目问:在 C 语言的函数中,正确的说法是哪一个?
答案:A
正确说法:
函数可以有形参,也可以没有形参。详细解析:
有形参的函数:
int add(int a, int b){ return a + b;}没有形参的函数:
void print_line(void){ printf("hello\n");}数组名也可以作形参,例如:
void print_array(int a[], int n){ ...}容易踩坑点:
- 以为函数必须有参数。
- 以为数组不能作为函数参数。
给新手的建议:
- 不需要参数时,建议写
void,比如int main(void)。
选择题第 6 题
Section titled “选择题第 6 题”题目整理:
int a[10] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, *p = a;问:不能表示 a 数组元素的表达式是哪一个?
答案:B
错误表达式:
a[*p - a]详细解析:
初始化后:
p 指向 a[0]*p 的值是 1a 表示数组首地址表达式:
*p - a左边是整数 1,右边是地址 a,整数和地址不能这样相减,所以不能正确表示数组下标。
其他选项:
*p++等价于:
*(p++)它可以表示当前 p 指向的元素,只是取完后会让 p 后移。
*p表示 p 当前指向的元素。
a[9]表示第 10 个元素。
容易踩坑点:
*p是元素值,p或a才是地址。*p++会改变p的指向。
给新手的建议:
- 数组和指针混合题,先区分“值”和“地址”。
选择题第 7 题
Section titled “选择题第 7 题”题目问:下面叙述中正确的是哪一个?
答案:A
正确说法:
函数可以返回一个值,也可以什么值也不返回。详细解析:
有返回值的函数:
int add(int a, int b){ return a + b;}无返回值的函数:
void show(void){ printf("hello\n");}其他选项的问题:
- 空函数虽然不做操作,但可以作为占位函数、调试用函数或后续扩展接口。
- 用户自定义函数在使用前通常需要声明,但老式 C 语境中题目不会把“必须加以声明”作为最稳正确项。
- 老式 C 中函数声明不一定都写完整参数类型和返回类型;现代写法应明确写。
容易踩坑点:
- 把考试中的老式 C 口径和现代规范写法混在一起。
给新手的建议:
- 实际写代码时,函数返回类型和参数类型都明确写出来。
选择题第 8 题
Section titled “选择题第 8 题”题目问:若二维数组 a 有 m 列,则在 a[i][j] 前的元素个数是多少?
答案:D
答案:
i * m + j详细解析:
C 语言二维数组按行存储。
在 a[i][j] 前面有:
- 前面完整的
i行,每行m个元素,共i * m个。 - 当前第
i行中,a[i][j]前面有j个元素。
所以总数是:
i * m + j容易踩坑点:
- 把行列顺序写反。
- 忘记下标从
0开始。
给新手的建议:
- 看到二维数组位置题,就想“前面有几整行,再加本行前面几个”。
选择题第 9 题
Section titled “选择题第 9 题”题目整理:
char s[] = "ab\0cd";printf("%s", s);答案:D
输出:
ab详细解析:
字符串输出 %s 遇到 '\0' 就停止。
字符串实际存储为:
'a' 'b' '\0' 'c' 'd' '\0'printf("%s", s) 从开头输出,输出到第一个 '\0' 前停止,所以只输出:
ab容易踩坑点:
- 以为字符串中间的
'\0'会被当作普通字符输出。
给新手的建议:
- 对
%s来说,第一个'\0'就是字符串结束。
选择题第 10 题
Section titled “选择题第 10 题”题目问:以下能对二维数组 a 进行正确初始化的语句是哪一个?
答案:D
按原卷选项应理解为:
int a[][3] = {{1, 2, 3}, {4, 5, 6}};详细解析:
二维数组初始化时,第一维可以省略,第二维必须写出来。
这里第二维是 3,每一行 3 个元素:
1 2 34 5 6所以编译器可以推出第一维是 2。
其他选项的问题:
int a[2][4] = {{1,2,3},{4,5},{6}};给了 3 行初值,但数组只有 2 行。int a[][3]={{1,0,1}{},{1,1}};语法不正确,行之间缺少逗号。int a[2][] = ...第二维省略,错误。
容易踩坑点:
- 二维数组第二维不能省略。
- 初值少可以补
0,但行数不能超过定义。
给新手的建议:
- 二维数组初始化先看第二个
[]里有没有数字。
选择题第 11 题
Section titled “选择题第 11 题”题目整理:
int a[][4] = {0, 0};问:下面不正确的叙述是哪一个?
答案:B
错误说法:
有元素 a[0][0] 和 a[0][1] 可得到初值 0,其余元素均得不到初值 0。详细解析:
a[][4] 第二维是 4,初值只有两个 0,因此第一维被推断为 1。
等价于:
int a[1][4] = {0, 0};实际所有元素都是 0:
0 0 0 0前两个是显式给的 0,后两个是自动补的 0。
容易踩坑点:
- 以为只有写出来的元素才得到初值。
给新手的建议:
- 数组只要进行了部分初始化,没写到的元素会自动补
0。
选择题第 12 题
Section titled “选择题第 12 题”题目整理:
static char str[10] = "China";问:数组元素个数是多少?
答案:B
详细解析:
数组长度已经写明:
str[10]所以数组元素个数是:
10字符串 "China" 的有效字符长度是 5,加上结尾 '\0' 占 6 个位置,但数组整体仍然有 10 个元素。
容易踩坑点:
- 把字符串长度
5当成数组元素个数。 - 把字符串占用空间
6当成数组元素个数。
给新手的建议:
- 题目问“数组元素个数”,优先看方括号里的数字。
选择题第 13 题
Section titled “选择题第 13 题”题目问:以下不能正确进行字符串赋初值的语句是哪一个?
答案:C
错误写法:
char str[5] = "good!";详细解析:
字符串 "good!" 有 5 个有效字符:
g o o d !还需要一个字符串结束符:
'\0'所以一共需要 6 个位置。
但 str[5] 只有 5 个位置,放不下 '\0',因此错误。
其他选项:
char *str = "good!";指针指向字符串常量,合法。
char str[5] = {'g', 'o', 'o', 'd', 0};这里最后一个 0 相当于 '\0',合法,表示字符串 "good"。
char str[] = "good!";编译器自动分配 6 个位置,合法。
容易踩坑点:
- 只数有效字符,忘记
'\0'。
给新手的建议:
- 双引号字符串初始化字符数组时,空间至少要是“有效字符数 + 1”。
选择题第 14 题
Section titled “选择题第 14 题”题目整理:
fun(float x){ float y;
y = 3 * x - 4; return y;}问:fun 函数的返回值类型是什么?
答案:C
按原卷和老式 C 口径:
int详细解析:
函数名前没有显式写返回类型。
在老式 C 语言教材中,如果函数没有写返回类型,默认返回类型是 int。
因此这题选:
int补充提醒:
现代 C 语言不推荐也不应这样写。实际写代码时应明确写:
float fun(float x){ float y;
y = 3 * x - 4; return y;}容易踩坑点:
- 以为返回类型由
return y;中y的类型决定。
给新手的建议:
- 函数返回类型看函数名前面写了什么类型,不是看
return后面的表达式。
选择题第 15 题
Section titled “选择题第 15 题”题目问:在 C 语言中,调用函数除函数名外,还必须有什么?
答案:A
正确答案:
()详细解析:
函数调用基本格式:
函数名(实参列表)即使没有实参,也要写小括号:
fun();容易踩坑点:
- 无参函数调用时省略
()。
给新手的建议:
- 函数名后面带
(),才是调用函数。
选择题第 16 题
Section titled “选择题第 16 题”题目问:下列说法不正确的是哪一个?
答案:C
错误说法:
主函数 main 中定义的变量在整个文件或程序中有效。详细解析:
main 函数中定义的变量是 main 的局部变量,只在 main 函数内部有效。
例如:
int main(void){ int x = 10; return 0;}
void fun(void){ printf("%d", x); // 错误,x 在这里不可见}其他说法:
- 形参是局部变量。
- 复合语句中定义的变量只在该复合语句中有效。
- 不同函数中可以使用同名变量,它们互不影响。
容易踩坑点:
- 以为
main是主函数,所以里面的变量全程序可见。
给新手的建议:
- 变量在哪个
{}里定义,通常就只在那个范围内有效。
选择题第 17 题
Section titled “选择题第 17 题”题目问:下列对字符数组的初始化不正确的是哪一个?
答案:A
错误写法:
char s[5] = "abcde";详细解析:
字符串 "abcde" 实际需要 6 个位置:
'a' 'b' 'c' 'd' 'e' '\0'但 s[5] 只有 5 个位置,所以放不下字符串结束符 '\0'。
其他选项:
char s[] = "abcde";编译器自动分配 6 个位置,合法。
char s[5] = "abc";需要 4 个位置,剩余位置自动补 0,合法。
char s[5] = {'a', 'b', 'c', 'd', 'e'};作为字符数组初始化是合法的,只是它没有 '\0',不能当普通字符串使用。
容易踩坑点:
- 把字符数组初始化和字符串初始化混在一起。
给新手的建议:
- 双引号字符串会自动带
'\0'。 - 单引号字符列表不会自动多加
'\0'。
选择题第 18 题
Section titled “选择题第 18 题”题目问:C 语言中函数调用的方式有哪些?
答案:B
正确说法:
函数调用可以作为语句、函数表达式或函数参数三种。详细解析:
作为独立语句:
fun();作为表达式的一部分:
x = fun() + 3;作为函数实参:
printf("%d\n", fun());容易踩坑点:
- 忘记函数调用可以作为另一个函数的实参。
给新手的建议:
- 有返回值的函数调用,可以像一个值一样参与表达式。
选择题第 19 题
Section titled “选择题第 19 题”题目问:在 C 语言中,一维数组的定义方式为:类型说明符 数组名后面接什么?
答案:B(原卷口径)
原卷答案:
[整型常量]详细解析:
这套卷子按传统基础题口径,强调数组长度应写成固定整数,例如:
int a[10];所以原卷选 B。
补充理解:
更严谨的教材表达常见是:
[常量表达式]比如:
int a[2 + 3];这里 2 + 3 也是常量表达式。
容易踩坑点:
- 把普通变量也当成数组长度常量。
- 只背
[整型常量],不知道[2 + 3]这种常量表达式也常见。
给新手的建议:
- 做本卷按红字答案记
B;真正理解时,记“数组长度通常应是常量表达式”。
选择题第 20 题
Section titled “选择题第 20 题”题目整理:
int a[10] = {6, 7, 8, 9, 10};答案:D
详细解析:
数组初始化从下标 0 开始:
a[0] = 6a[1] = 7a[2] = 8a[3] = 9a[4] = 10后面的元素没有显式初值,会自动补 0:
a[5] ~ a[9] = 0容易踩坑点:
- 以为初值
6会赋给a[6]。 - 以为第一个初值从
a[1]开始。
给新手的建议:
- 初始化列表永远从第一个元素
a[0]开始依次放。
选择题第 21 题
Section titled “选择题第 21 题”题目整理:
int a[3][4] = {0};答案:B
详细解析:
= {0} 会让二维数组每个元素都初始化为 0。
可以理解为:
0 0 0 00 0 0 00 0 0 0所以正确叙述是:
数组 a 中每个元素均可得到初值 0。容易踩坑点:
- 以为只有
a[0][0]得到初值0。
给新手的建议:
{0}是常见的数组全 0 初始化写法。
选择题第 22 题
Section titled “选择题第 22 题”题目整理:
char a[] = "This is a program.";问:输出前 5 个字符的语句是哪一个?
答案:C
正确写法:
printf("%.5s", a);详细解析:
printf 输出字符串时,可以用精度控制最多输出几个字符:
%.5s表示最多输出字符串前 5 个字符。
所以会输出:
This注意第 5 个字符是空格。
容易踩坑点:
- 以为
%s只能输出整个字符串。 - 忘记空格也算一个字符。
给新手的建议:
printf("%.Ns", 字符串)可以输出前N个字符。
选择题第 23 题
Section titled “选择题第 23 题”题目问:以下不能正确定义二维数组的选项是哪一个?
答案:B
错误写法:
int a[2][] = {{1, 2}, {3, 4}};详细解析:
二维数组第二维不能省略。
可以写:
int a[][2] = {1, 2, 3, 4};但不能写:
int a[2][] = {{1, 2}, {3, 4}};容易踩坑点:
- 以为有初始化列表就能省略第二维。
给新手的建议:
- 二维数组定义时,必须让编译器知道每行几个元素。
选择题第 24 题
Section titled “选择题第 24 题”题目整理:
char a[10];问:以下语句中不能从键盘上给 a 数组的所有元素输入值的是哪一个?
答案:B
错误写法:
a = getchar();详细解析:
a 是数组名,不能作为赋值号左边整体赋值。
而且 getchar() 一次只读取一个字符,不可能直接给整个数组赋值。
可以逐个输入:
for (i = 0; i < 10; i++) a[i] = getchar();也可以按字符串输入:
scanf("%s", a);容易踩坑点:
- 把字符数组当成一个普通字符变量。
- 忘记数组名不能整体赋值。
给新手的建议:
- 给数组元素赋值,要么逐个
a[i] = ...,要么使用字符串输入函数。
选择题第 25 题
Section titled “选择题第 25 题”题目问:凡是函数中未指定存储类别的局部变量,其隐含的存储类别是什么?
答案:C
答案:
auto详细解析:
函数内部普通局部变量默认存储类别是自动变量:
void fun(void){ int x; // 默认等价于 auto int x;}auto 局部变量通常在进入函数或代码块时创建,离开函数或代码块后失效。
容易踩坑点:
- 把普通局部变量默认理解成
static。
给新手的建议:
- 普通局部变量默认是
auto,如果想让它保留上次调用后的值,才需要写static。
3. 填空题详解
Section titled “3. 填空题详解”填空题第 1 题
Section titled “填空题第 1 题”题目整理:
int x = 2, y = 3, z = 4;!x + y > z答案:0
详细解析:
先算逻辑非:
!x = !2 = 0因为非 0 为真,逻辑非后为 0。
再算:
0 + 3 > 43 > 4结果为假,所以表达式值为:
0容易踩坑点:
- 忘记
!的优先级高于+。 - 忘记 C 语言中假是
0。
给新手的建议:
- 逻辑表达式题先把每个真/假换成
1或0。
填空题第 2 题
Section titled “填空题第 2 题”题目整理:
3 && 0答案:0
详细解析:
逻辑与 && 要求两边都为真,结果才为真。
在 C 语言中:
3 是真0 是假所以:
真 && 假 -> 假 -> 0容易踩坑点:
- 把
&&当成普通乘法。
给新手的建议:
&&的结果只可能是1或0。
填空题第 3 题
Section titled “填空题第 3 题”题目整理:
int x = 2;z = x++ - 1;问:x 的值是多少?
答案:3
详细解析:
x++ 是后置自增:
先使用 x 的旧值 2再让 x 加 1 变成 3所以:
z = 2 - 1 = 1x = 3容易踩坑点:
- 把
x++当成先加再用。
给新手的建议:
x++先用后加,++x先加后用。
填空题第 4 题
Section titled “填空题第 4 题”题目整理:
int x = 15, n = 2;x %= (n + 3);答案:0
详细解析:
复合赋值:
x %= (n + 3);等价于:
x = x % (n + 3);先算:
n + 3 = 2 + 3 = 5再算:
15 % 5 = 0所以 x 的值为 0。
容易踩坑点:
- 忘记
%=是取余后再赋值。
给新手的建议:
- 复合赋值可以先展开成普通赋值再算。
填空题第 5 题
Section titled “填空题第 5 题”题目整理:
int x = 2;z = ++x + 1;答案:4
详细解析:
++x 是前置自增:
先让 x 变成 3再使用 x 的新值 3所以:
z = 3 + 1 = 4容易踩坑点:
- 把
++x和x++混淆。
给新手的建议:
- 前置先加再用,后置先用再加。
填空题第 6 题
Section titled “填空题第 6 题”题目整理:
int b, c;float a;
scanf("%f,%d,c=%d", &a, &b, &c);要求输入后:
a = 5.0b = 4c = 3答案:5.0,4,c=3
详细解析:
scanf 格式串里除了格式说明符,普通字符也必须按原样输入。
格式串:
"%f,%d,c=%d"表示输入数据必须长这样:
浮点数,整数,c=整数所以应输入:
5.0,4,c=3容易踩坑点:
- 忘记逗号和
c=也要原样输入。
给新手的建议:
scanf格式串里不是%...的普通字符,输入时通常要照着敲。
填空题第 7 题
Section titled “填空题第 7 题”题目整理:
int a = 13, b = 6;a | b答案:15
详细解析:
这里的 | 是按位或,不是逻辑或 ||。
把两个数写成二进制:
13 = 1101 6 = 0110逐位做“或”运算:
1101| 0110------ 1111二进制 1111 转成十进制就是:
15容易踩坑点:
- 把
|看成||。 - 不会把十进制数转成二进制看位运算。
给新手的建议:
- 单个
|是按位或,两个||才是逻辑或。
填空题第 8 题
Section titled “填空题第 8 题”题目整理:
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。
给新手的建议:
- 复合赋值右侧整体参与运算。
填空题第 9 题
Section titled “填空题第 9 题”题目:设 x 为 int 型变量,写出描述“x 是偶数”的表达式。
推荐答案:
x % 2 == 0详细解析:
偶数除以 2 的余数为 0,所以用取余判断:
x % 2 == 0原卷还给出了一些等价写法,例如:
!(x % 2)容易踩坑点:
- 写成
x / 2 == 0,这不是判断偶数。 - 忘记判断相等要写
==。
给新手的建议:
- 判断整除或奇偶,优先想到
%。
填空题第 10 题
Section titled “填空题第 10 题”题目整理:
(k = a = 5, b = 3, a * b)问:k 的值是多少?
答案:5
详细解析:
逗号表达式会从左到右依次执行。
第一项:
k = a = 5执行后:
a = 5k = 5第二项:
b = 3执行后:
b = 3第三项:
a * b只是计算:
5 * 3 = 15但没有把结果赋给 k,所以 k 仍然是:
5容易踩坑点:
- 以为逗号表达式最后一个值会自动赋给
k。
给新手的建议:
- 只有写了赋值号,变量值才会变。
4. 判断题详解
Section titled “4. 判断题详解”判断题第 1 题
Section titled “判断题第 1 题”题目:通过 return 语句,函数可以带回一个或一个以上的返回值。
答案:N
解析:
return 一次只能直接返回一个值。
如果想让函数带回多个结果,通常使用指针参数或结构体。
判断题第 2 题
Section titled “判断题第 2 题”题目:C 程序中有调用关系的所有函数必须放在同一个源程序文件中。
答案:N
解析:
C 程序可以由多个源文件组成。
一个文件中的函数可以通过函数声明调用另一个文件中的函数,最后链接到一起。
判断题第 3 题
Section titled “判断题第 3 题”题目:
a = (b = 4) + (c = 6)判断:这是一个合法的赋值表达式。
答案:Y
解析:
赋值表达式本身也有值。
(b = 4)的值是 4,(c = 6) 的值是 6,所以整个表达式合法。
判断题第 4 题
Section titled “判断题第 4 题”题目整理:
int a[3][4] = {{1}, {5}, {9}};判断:它的作用是将数组各行第一列的元素赋初值,其余元素值为 0。
答案:Y
解析:
数组内容是:
1 0 0 05 0 0 09 0 0 0没有显式初始化的元素会自动补 0。
判断题第 5 题
Section titled “判断题第 5 题”题目:整数 -32100 可以赋值给 int 型和 long int 型变量。
答案:Y
解析:
按传统 16 位有符号 int 环境,范围通常是:
-32768 ~ 32767-32100 在这个范围内,所以可以赋给 int,也可以赋给 long int。
判断题第 6 题
Section titled “判断题第 6 题”题目整理:
#define S(a, b) t = a; a = b; b = t判断:由于变量 t 没定义,所以此宏定义是错误的。
答案:N
解析:
宏定义本身只是文本替换规则,不会在定义阶段检查 t 有没有定义。
使用宏展开后,如果代码中没有提前定义 t,才会产生编译错误。
给新手的建议:
- 宏不是函数,它更像“复制粘贴替换”。
判断题第 7 题
Section titled “判断题第 7 题”题目整理:
int c;while (c = getchar()) ;判断:这是正确的 C 语句。
答案:Y
解析:
从语法上看,这是合法的 C 语句。
它的含义是:不断从键盘读取字符并赋给 c,只要赋值表达式的值不为 0,循环就继续。
补充提醒:
这并不是推荐写法。实际读取字符时,通常会判断 EOF:
while ((c = getchar()) != EOF){ ...}容易踩坑点:
- 看到
=就认为一定语法错误。这里是赋值表达式,语法上合法。
判断题第 8 题
Section titled “判断题第 8 题”题目:C 语言中只能逐个引用整型数组元素,而不能一次引用整个数组。
答案:Y
解析:
数组不能作为整体直接赋值或整体输出。
例如:
int a[3] = {1, 2, 3};int b[3];
b = a; // 错误通常要逐个处理:
for (i = 0; i < 3; i++) b[i] = a[i];判断题第 9 题
Section titled “判断题第 9 题”题目整理:
int i = 20;
switch (i / 10){case 2: printf("A");case 1: printf("B");}判断:输出结果为 A。
答案:N
解析:
先算:
i / 10 = 20 / 10 = 2进入 case 2,输出 A。
但 case 2 后面没有 break,所以会继续执行 case 1,输出 B。
实际输出:
AB容易踩坑点:
- 忘记
switch中没有break会继续向下执行。
判断题第 10 题
Section titled “判断题第 10 题”题目:如果有一个字符串,其中第 10 个字符为 '\n',则此字符串的有效字符为 9 个。
答案:N
解析:
'\n' 是换行字符,它仍然是一个普通有效字符。
真正表示字符串结束的是:
'\0'如果第 10 个字符是 '\0',那么有效字符才是前 9 个。
但题目说的是第 10 个字符为 '\n',所以不能说明字符串有效字符一定是 9 个。
容易踩坑点:
- 把
'\n'和'\0'混淆。
给新手的建议:
'\n'是换行,'\0'是字符串结束。
5. 改错题详解
Section titled “5. 改错题详解”功能:一个整数,它加上 100 后是一个完全平方数,再加上 168 后又是一个完全平方数,求这个整数。
整理后的正确代码:
#include <stdio.h>#include <math.h>
int main(void){ long int i; long int x, y;
for (i = 1; i < 100000; i++) { x = (long int)sqrt(i + 100); y = (long int)sqrt(i + 268);
if (x * x == i + 100 && y * y == i + 268) printf("\n%ld\n", i); }
return 0;}原卷要求修改的错误:
第一处:
for (i == 1; i < 100000; i++)应改为:
for (i = 1; i < 100000; i++)原因:= 是赋初值,== 是判断相等。
第二处:
x = sqrt(i + 100)应改为:
x = sqrt(i + 100);原因:语句末尾缺少分号。
第三处:
if (x * x == i + 100 || y * y == i + 268)应改为:
if (x * x == i + 100 && y * y == i + 268)原因:题目要求两个条件同时满足:
i + 100 是完全平方数i + 268 也是完全平方数所以要用逻辑与 &&,不能用逻辑或 ||。
详细解题过程:
对每个 i,先求:
sqrt(i + 100)sqrt(i + 268)如果平方根取整后再平方还能等于原数,说明它是完全平方数。
容易踩坑点:
=和==混用。&&和||混用。- 漏写分号。
给新手的建议:
- 题目里出现“并且”“同时”,通常用
&&。 - 题目里出现“或者”,通常用
||。
功能:用下面的和式求圆周率的近似值,直到最后一项的绝对值小于等于 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 输出。
容易踩坑点:
- 用整型变量保存小数项。
- 循环条件写反。
- 使用
fabs却没有包含<math.h>。 - 浮点数输出格式写成
%d。
给新手的建议:
- 级数题先看每一项怎么变,再看什么时候停止。
6. 程序设计题详解
Section titled “6. 程序设计题详解”程序设计 1
Section titled “程序设计 1”功能:若 x、y 为奇数,求 x 到 y 之间的奇数和;若 x、y 为偶数,则求 x 到 y 之间的偶数和。
参考答案:
#include <stdio.h>
int fun(int x, int y){ int i, s = 0;
for (i = x; i <= y; i += 2) s += i;
return s;}
int main(void){ int s;
s = fun(1, 1999) - fun(2, 1998); printf("s=%d\n", s);
return 0;}详细解题过程:
这道题默认传入的 x 和 y 同奇偶:
fun(1, 1999):从1开始每次加2,求所有奇数和。fun(2, 1998):从2开始每次加2,求所有偶数和。
核心循环是:
for (i = x; i <= y; i += 2) s += i;为什么每次加 2?
因为奇数到下一个奇数差 2:
1, 3, 5, 7, ...偶数到下一个偶数也差 2:
2, 4, 6, 8, ...本题主函数最终计算:
1 到 1999 的奇数和 - 2 到 1998 的偶数和结果是:
1000容易踩坑点:
- 循环写成
i++,这样会把奇偶都加进去。 - 忘记初始化
s = 0。 - 忘记
return s;。
给新手的建议:
- 如果要只遍历奇数或偶数,循环变量通常每次加
2。
程序设计 2
Section titled “程序设计 2”功能:编写函数 fun,将两个两位正整数 a、b 合并形成一个整数放在 c 中。
合并规则:
a的十位放到c的个位。a的个位放到c的十位。b的十位放到c的百位。b的个位放到c的千位。
例如:
a = 16b = 35c = 5361参考答案:
#include <stdio.h>
void fun(int a, int b, long *c){ *c = (b % 10) * 1000 + (b / 10) * 100 + (a % 10) * 10 + a / 10;}
int main(void){ int a = 16, b = 35; long c;
fun(a, b, &c); printf("c=%ld\n", c);
return 0;}详细解题过程:
先拆 a = 16:
a / 10 = 1 // 十位a % 10 = 6 // 个位再拆 b = 35:
b / 10 = 3 // 十位b % 10 = 5 // 个位按照题目要求组合:
| 来源 | 放到 c 的位置 | 对应权值 |
|---|---|---|
b % 10 | 千位 | *1000 |
b / 10 | 百位 | *100 |
a % 10 | 十位 | *10 |
a / 10 | 个位 | *1 |
所以:
*c = (b % 10) * 1000 + (b / 10) * 100 + (a % 10) * 10 + a / 10;代入 a = 16, b = 35:
*c = 5 * 1000 + 3 * 100 + 6 * 10 + 1 = 5000 + 300 + 60 + 1 = 5361为什么写 *c?
因为形参 c 是指针:
long *c要修改它指向的变量,必须写:
*c = ...容易踩坑点:
- 拆个位要用
% 10,拆十位要用/ 10。 - 忘记乘以
1000、100、10放到对应位。 - 形参是指针时,赋值要写
*c = ...。
给新手的建议:
- 数字拆位组合题,一定先画表:哪个数字的哪一位,放到结果的哪一位。
7. 这套卷子最容易暴露的问题
Section titled “7. 这套卷子最容易暴露的问题”这套 exam-83 很适合检查下面这些基础:
- 函数调用的实参个数只数最外层逗号。
- 函数可以嵌套调用,但不能嵌套定义。
- 老式 C 中函数不写返回类型默认
int,但现代写法要明确返回类型。 - 数组下标从
0开始,初始化列表从a[0]开始。 - 二维数组第二维不能省略。
- 字符串遇到第一个
'\0'就结束。 '\n'是换行字符,不是字符串结束符。|是按位或,||是逻辑或。&&表示两个条件同时满足,||表示满足其中一个。- 普通局部变量默认存储类别是
auto。
8. 给新手的复习建议
Section titled “8. 给新手的复习建议”- 把选择题第 1、2、5、7、14、15、18、25 题放在一起复习,它们都和函数有关。
- 把选择题第 3、4、8、10、11、19、20、21、23、24 题放在一起复习,它们都和数组有关。
- 把选择题第 9、12、13、17、22 题放在一起复习,它们都和字符串、字符数组有关。
- 填空题第 7 题建议手写二进制位运算过程,特别区分
|和||。 - 判断题第 9 题建议自己写一段
switch程序,分别试试有break和没有break的区别。 - 改错题第 1 题重点看
=、==、&&、||的区别。 - 程序设计第 2 题建议你自己换几个两位数,比如
a=24, b=68,手算再跑代码验证。
9. 最后总结
Section titled “9. 最后总结”第 83 套卷子虽然题目看起来分散,但核心还是基础细节:
- 函数:调用形式、返回类型、形参、实参、作用域。
- 数组:定义、初始化、下标范围、二维数组行列计算。
- 字符串:
'\0'、空间大小、前 N 个字符输出。 - 表达式:自增、自减、复合赋值、位运算、逗号表达式。
- 程序题:拆位、组合、奇偶求和、完全平方数判断。
复习时不要只背红字答案。你可以把每道题后面的“容易踩坑点”当作检查清单:如果能说清楚它想考你哪个坑,这套题就真正吃透了。