C 语言前五个任务 · 零基础复习讲义
面向零基础:每个知识点都配能直接跑通的完整代码和真实输出,不讲空理论。 内容按教材前五个任务组织,并与你手上的四份课内实验(实验 1—4)逐条对应。 每个任务的例题都标了「这道题对应哪次实验」,复习时可以直接对着实验报告核。
PART 00零基础起步:先弄懂这四件事
① 一个 C 程序的最小骨架
#include <stdio.h>
int main()
{
printf("Hello\n");
return 0;
}② 四个步骤,一步不能少
- 编辑:写代码,存成
.c文件 - 编译:把
.c变成.exe(快捷键 F11) - 运行:看结果
- 调试:结果不对就回来改
③ 每一行的作用
#include:告诉编译器「我要用别人写好的工具箱」stdio.h:输入输出工具箱(printf / scanf 在里面)int main():程序唯一的入口,从这开始执行return 0;:告诉系统「我正常结束了」
④ 三条铁律
- 每条语句结尾必须有分号
; - 标点必须是英文半角,中文逗号、中文分号、中文引号全会报错
- C 语言严格区分大小写:
Main≠main
第一个真实可跑的程序:算出 1 + 2
#include <stdio.h>
int main()
{
int a = 1, b = 2; /* 定义两个整数变量并赋值 */
printf("%d + %d = %d\n", a, b, a + b);
return 0;
}看懂这一行就入门了:printf("格式串", 变量1, 变量2),格式串里的每个 %d 都会被后面的变量按顺序顶替。
TASK 01任务一 · ATM 主界面设计
对应实验 1「程序设计环境与程序结构」。这个任务只干一件事:把字打到屏幕上。看着简单,但它是后面所有代码的地基。
1.1 知识储备
| 考点 | 要求 | 重要度 |
|---|---|---|
| C 程序的结构 | 头文件、主函数、语句、返回值,缺一个都跑不起来 | ★★★★ |
| printf 的基本用法 | 能输出文字、变量、多个变量 | ★★★★★ |
转义字符 \n \t | 换行、制表对齐,区别要分清 | ★★★★ |
| 格式控制符 | %d %f %c %s 各管什么类型 | ★★★★★ |
| 编译运行与调试 | 会新建、编译、运行;会看报错定位行号 | ★★★★ |
| 常见错误 | 漏分号、大小写、全角符号、窗口闪退 | ★★★ |
① printf 到底怎么用
printf("格式串", 变量1, 变量2, ...);格式串里有两类东西:普通字符(原样输出)和格式符(以 % 开头,被后面的变量替换)。
| 格式符 | 对应类型 | 例子 |
|---|---|---|
%d | int 整数 | printf("%d", 123); → 123 |
%f | float / double 小数 | printf("%f", 1.5); → 1.500000 |
%c | char 单个字符 | printf("%c", 'A'); → A |
%s | 字符串 | printf("%s", "abc"); → abc |
%% | 输出一个百分号 | printf("90%%"); → 90% |
② 转义字符:看不见的字符怎么写
| 写法 | 含义 | 效果 |
|---|---|---|
\n | 换行 | 光标跳到下一行开头 |
\t | 制表符(Tab) | 跳到下一个制表位,用来对齐列 |
\\ | 一个反斜杠 | 输出 \ |
\" | 一个双引号 | 在字符串里打出 " |
\n 管「换不换行」,\t 管「对齐到第几列」。做 ATM 菜单、成绩表格时,\t 比手动敲空格靠谱得多。1.2 例题实操
要求姓名、年龄、籍贯、爱好各占一行,且冒号对齐。
#include <stdio.h>
int main()
{
printf("姓名:陈泽阳\n");
printf("年龄:18\n");
printf("籍贯:福建平潭\n");
printf("爱好:编程、篮球\n");
return 0;
}每一行一个 printf,句末的 \n 负责换行。如果不写 \n,四个 printf 的输出会连成一整行:姓名:陈泽阳年龄:18籍贯…——这就是实验报告里那道思考题「不加 \n 会有什么后果」的答案。
想让冒号对齐,把 : 换成 \t:printf("姓名\t陈泽阳\n");。
关键是「一次 printf 里放多个 \n」,而不是写三次 printf。
#include <stdio.h>
int main()
{
printf("*********************\nVery good\n*********************\n");
return 0;
}一个字符串里可以出现任意多个 \n,每遇到一个就换一次行。所以「三行内容」不需要三条语句。
星号数量要数准:21 个。考试时如果要求「星号数量由变量控制」,那就得用循环了(任务六)。
#include <stdio.h>
int main()
{
/* 写法一:先定义,后赋值 */
int a, b, sum1;
a = 123;
b = 456;
sum1 = a + b;
printf("写法一:%d + %d = %d\n", a, b, sum1);
/* 写法二:定义时直接初始化 */
int c = 123, d = 456;
printf("写法二:%d + %d = %d\n", c, d, c + d);
return 0;
}两种写法的区别只在「什么时候给值」:写法一先占一块内存,值不确定(是垃圾值),后面才填;写法二在占内存的同时就填好,更安全、更短。
实验报告要求「比较二者区别」,可以这样答:初始化赋值能避免「变量未初始化就参与运算」导致的随机结果,实际工程中都推荐写法二。
⚠ 如果写成 int a, b; printf("%d", a+b); 而不赋值,输出可能是任意数,这属于「用了未初始化的变量」。
这两题引入了 scanf——从键盘读数据。注意 scanf 里变量名前必须加 &。
#include <stdio.h>
int main()
{
int a, b, max, w, h;
printf("请输入两个整数(用逗号隔开):");
scanf("%d,%d", &a, &b);
if (a > b) max = a; else max = b;
printf("较大者:%d\n", max);
printf("请输入矩形的长和宽:");
scanf("%d,%d", &w, &h);
printf("面积:%d\n", w * h);
return 0;
}三个重点:
scanf("%d,%d", &a, &b)里的逗号是普通字符,你输入时就必须真的敲逗号。这个坑在任务四会专门讲。&是取地址符,意思是「把读到的数放到 a 那块内存里」,漏写会得到随机值甚至崩溃。if ... else ...属于任务五的内容,这里先用最小形式。
TASK 02任务二 · 计算学生的综合积分
对应实验 2「数据类型及算术表达式」。这是丢分最集中的一章——不是不会写,而是被「整数除法」「类型转换」这些细节坑掉。
2.1 知识储备
① 四种基本数据类型
| 类型 | 占字节 | 能存什么 | 例子 |
|---|---|---|---|
int | 4 字节 | 整数,约 ±21 亿 | int age = 18; |
float | 4 字节 | 小数,约 7 位有效数字 | float h = 1.75f; |
double | 8 字节 | 小数,约 15 位有效数字 | double pi = 3.14159; |
char | 1 字节 | 单个字符(本质是 ASCII 码) | char c = 'A'; |
'A' 的值是 65,'a' 是 97,'0' 是 48。所以 printf("%d", 'A') 会输出 65,而 printf("%c", 65) 会输出 A。大小写转换就是 ±32。② 类型转换:自动 vs 强制
int a = 5, b = 3;
printf("%f\n", a / b); /* 错:输出 1.000000 */
printf("%f\n", (float)a / b); /* 对:输出 1.666667 */
printf("%f\n", a * 1.0 / b); /* 对:输出 1.666667 */int 相除,结果先截断成整数,再赋给 float。所以 5/3 得到 1,不是 1.666。这是实验 2 任务 1 的核心,也是期末必考。三种修法:
(float)a / b、a / (float)b、a * 1.0 / b。③ 运算符一览(按优先级从高到低)
| 类别 | 运算符 | 要点 |
|---|---|---|
| 括号 / 强制转换 | () (类型) | 优先级最高 |
| 算术 | * / % 高于 + - | % 只能用于整数,求余数 |
| 自增自减 | ++ -- | a++ 先用后加,++a 先加后用 |
| 关系 | > < >= <= == != | 结果是 1(真)或 0(假) |
| 逻辑 | && || ! | 有短路特性,任务五详解 |
| 条件 | ? : | 三目运算符,唯一的「三操作数」 |
| 赋值 | = += -= *= /= | 优先级最低,从右往左结合 |
2.2 例题实操
#include <stdio.h>
int main()
{
int a, b;
float c;
a = 5;
b = 3;
c = a / b;
printf("%f\n", c);
return 0;
}错误在第 6 行 c = a / b;。因为 a、b 都是 int,a / b 会先做整数除法,5/3 截断成 1,然后才把整数 1 转成 float 存进 c,所以是 1.000000。
三种修改方案(都能得到 1.666667):
c = (float)a / b;—— 把 a 先转成浮点,再做浮点除法c = a / (float)b;—— 把 b 先转成浮点c = a * 1.0 / b;—— 用一个浮点常量把整个式子「拉成」浮点运算
如果把 float c; 改成 double c;,%f 仍然可用(printf 中 double 也用 %f);但 scanf 读 double 必须用 %lf。
#include <stdio.h>
int main()
{
char small, big, c1, c2;
printf("输入一个小写字母:");
scanf("%c", &small);
big = small - 32; /* 小写比大写大 32 */
printf("%c 对应的大写是 %c\n", small, big);
printf("输入两个字符:");
getchar(); /* 吃掉上一次输入留下的回车 */
scanf("%c%c", &c1, &c2);
printf("较小字符的 ASCII:%d\n", c1 < c2 ? c1 : c2);
return 0;
}两个关键点:
- ±32 的规律:ASCII 表里
'a'=97、'A'=65,正好差 32。所以大写转小写+32,小写转大写-32。 - getchar() 吃掉回车:第一次
scanf后,输入缓冲区里还剩一个回车符,会被下一次%c当成字符读走,导致后面的输入错位。所以在两次之间加一个getchar();。 - 三目运算符
c1 < c2 ? c1 : c2的意思是:条件成立取前者,否则取后者。等价于一个 if-else,但更短。
需要 math.h 里的 sqrt()。
#include <stdio.h>
#include <math.h>
int main()
{
double a, b, c, d, x1, x2;
printf("输入 a,b,c:");
scanf("%lf,%lf,%lf", &a, &b, &c);
d = b * b - 4 * a * c;
if (d >= 0) {
x1 = (-b + sqrt(d)) / (2 * a);
x2 = (-b - sqrt(d)) / (2 * a);
printf("x1=%.2f x2=%.2f\n", x1, x2);
} else {
printf("无实根\n");
}
return 0;
}三个必须注意的点:
#include <math.h>不能少,否则报undefined reference to 'sqrt'。- 分母
2*a必须加括号。写成-b + sqrt(d) / 2 * a就完全错了——除法和乘法同级,从左往右算。 - 用
double就用%lf读、%.2f写,别混。
实验报告里提醒的两组核对数据:a=1,b=-5,c=6 得 3 和 2;a=2,b=4,c=2 得两个相等的根 −1。
核心是「取余拿个位、整除丢个位」这对组合。注意 100 的逆序是 1 还是 001,这是个坑。
#include <stdio.h>
int main()
{
int n, g, s, b, r;
printf("输入三位数:");
scanf("%d", &n);
g = n % 10; /* 个位 */
s = n / 10 % 10; /* 十位 */
b = n / 100; /* 百位 */
r = g * 100 + s * 10 + b;
printf("逆序数:%d\n", r);
return 0;
}分离各位的标准套路(背下来,后面数组、循环都会用到):
- 个位:
n % 10 - 十位:
n / 10 % 10 - 百位:
n / 100
输入 100 会输出什么?g=0、s=0、b=1,r = 0×100+0×10+1 = 1,输出 1。如果你想让它是 001,得用 %03d 输出——这是「数值」和「字符串」的区别,也是实验报告里让你思考的那道题。
TASK 03任务三 · 坐标点的象限判断流程图绘制
这个任务不写代码,只画流程图。但它是「先想清楚再写」的训练,考试里通常以选择题、填空题、画图题出现,很多人在这里白丢分。
3.1 知识储备
① 算法的五个特征
| 特征 | 含义 |
|---|---|
| 有穷性 | 必须在有限步内结束,不能死循环 |
| 确定性 | 每一步的含义必须唯一,不能有歧义 |
| 可行性 | 每一步都能真正执行 |
| 有零个或多个输入 | 可以没有输入(如直接输出菜单) |
| 有一个或多个输出 | 没有输出的算法没有意义 |
② 流程图符号(必背)
| 形状 | 含义 | 例子 |
|---|---|---|
| 椭圆 / 圆角矩形 | 起止框 | 开始、结束 |
| 矩形 | 处理框(赋值、计算) | y = x + 1 |
| 菱形 | 判断框(条件) | x > 0 ? |
| 平行四边形 | 输入 / 输出框 | 输入 x、输出 y |
| 箭头 | 流程线 | 表示执行方向 |
| 小圆圈 | 连接点 | 连接被分开的流程线 |
③ 三种基本结构
顺序结构
从上往下依次执行,没有分支、没有回退。最基本的结构。
选择结构
有菱形判断框,两条出口。对应 if / if-else / switch。
循环结构
有一条往回指的箭头,满足条件就重复。对应 while / for。
3.2 例题实操
点在坐标平面上有四种情况,先判断是不是在轴上,再判断象限。
- 椭圆:开始
- 平行四边形:输入 x, y
- 菱形:
x == 0 || y == 0 ?→「是」分支输出「在坐标轴上」,结束 - 菱形:
x > 0 ?→「是」再判断y > 0 ?:是则第一象限,否则第四象限 - 「否」分支再判断
y > 0 ?:是则第二象限,否则第三象限 - 椭圆:结束
对应的代码(和流程图一一对应):
#include <stdio.h>
int main()
{
double x, y;
printf("输入 x,y:");
scanf("%lf,%lf", &x, &y);
if (x == 0 || y == 0)
printf("在坐标轴上\n");
else if (x > 0 && y > 0)
printf("第一象限\n");
else if (x < 0 && y > 0)
printf("第二象限\n");
else if (x < 0 && y < 0)
printf("第三象限\n");
else
printf("第四象限\n");
return 0;
}画图题评分点:起止框必须是椭圆、判断框必须是菱形、每个判断要有「是 / 否」两条出口标注。少一个出口标注就扣分。
- 输入 n;若
n <= 1,直接判定「不是素数」并结束(这是最容易漏的边界)。 - 令
i = 2(从 2 开始试除)。 - 菱形:
i <= n-1 ?→「否」表示已经试完,判定「是素数」。 - 菱形:
n % i == 0 ?→「是」判定「不是素数」并结束;「否」则i = i + 1,箭头回到第 3 步(这条回指的箭头就是循环结构的标志)。
图里必须有那条往回指的箭头,这是「循环」和「顺序」的唯一区别。没有回指箭头,判卷老师会认为你画成了顺序结构。
- 矩形 → 赋值语句:图里写
sum = sum + i,代码就是sum = sum + i; - 菱形 → if 或 while:如果两条出口之后还能汇合,用
if;如果有一条出口回到前面,用while。 - 平行四边形 → scanf / printf:输入框写
scanf,输出框写printf。
按这个规则,任何流程图都能直译成代码,反过来也成立。
TASK 04任务四 · 各类数据输出格式控制
对应实验 3「基本输入输出」。这章全是细节:宽度、精度、对齐、scanf 的格式串、缓冲区。考试几乎必出一道填空。
4.1 知识储备
① printf 的宽度与精度(重点)
printf("%9.3f", 123.4567); /* 总宽 9 列,小数 3 位 → " 123.457" */
printf("%-5.2s", "abcdef"); /* 宽度 5,左对齐,取前 2 个字符 → "ab " */
printf("%5d", 42); /* 宽度 5,右对齐 → " 42" */
printf("%-5d", 42); /* 宽度 5,左对齐 → "42 " */
printf("%03d", 7); /* 补零到 3 位 → "007" */| 写法 | 含义 | 记忆口诀 |
|---|---|---|
%9.3f | 总宽 9,小数 3 位 | 小数点前是「总宽」,后面是「小数位」 |
%-5d | 宽 5,左对齐 | 负号就是「往左靠」 |
%03d | 宽 3,空位补 0 | 0 就是「补零」 |
%.2s | 只取前 2 个字符 | 对字符串,精度=取几个字符 |
② scanf 的格式串:普通字符必须原样输入
| 程序里的写法 | 运行时应该怎么输入 | 说明 |
|---|---|---|
scanf("%d%d", &a, &b) | 5 8 或 5<回车>8 | 空格、回车都能分隔 |
scanf("%d,%d", &a, &b) | 5,8 | 必须敲逗号,敲空格会失败 |
scanf("a=%d,b=%d", &a, &b) | a=5,b=8 | 格式串里的 a= 和 ,b= 都要照抄 |
scanf("%c%c%c", &c1, &c2, &c3) | ABC(不能有空格) | %c 不跳过空格和回车 |
%c 会把空格、回车当成有效字符读进去,所以连续读字符前要先用 getchar(); 把回车吃掉。② scanf 的变量前必须加 &(数组名和字符串除外),漏了会得到随机值或直接崩溃。③ getchar / putchar
char c;
c = getchar(); /* 从键盘读一个字符,等价于 scanf("%c", &c) */
putchar(c); /* 输出一个字符,等价于 printf("%c", c) */
putchar('\n'); /* 输出一个换行 */它们只能处理单个字符,好处是简单、不会被格式串坑;坏处是读数字不方便。
4.2 例题实操
#include <stdio.h>
int main()
{
int a, b;
scanf("%d%d", &a, &b); /* 试着把这行换成下面两种 */
printf("%d,%d\n", a, b);
return 0;
}| 写法 | 正确输入 | 错误输入会怎样 |
|---|---|---|
"%d%d" | 5 8 或 5回车8 | — |
"%d,%d" | 5,8 | 输入 5 8 时 b 读不到,输出 5,随机值 |
"a=%d,b=%d" | a=5,b=8 | 只输 5,8 会直接失败 |
规律:格式串里的普通字符(逗号、字母、等号)是「必须匹配的字面量」,你输入时得原样敲出来。格式符 %d 才对应真正的数据。
123.4567 输出为总宽 9 列、小数 3 位;"abcdef" 输出占 5 列、左对齐、只取前 2 个字符 实验3·任务3#include <stdio.h>
int main()
{
float a = 123.4567;
printf("%9.3f", a); /* 填空 1 */
printf("\n");
printf("%-5.2s", "abcdef");/* 填空 2 */
printf("\n");
return 0;
}填空 1 = %9.3f:总宽 9 列,123.457 本身占 7 列,所以前面补 2 个空格。小数第 4 位 7 会四舍五入,所以是 123.457。
填空 2 = %-5.2s:%-5 表示宽度 5 且左对齐,.2 表示只取前 2 个字符,得到 ab 后面补 3 个空格。
⚠ 如果实际值整数部分超过总宽(比如 1234.567 用 %9.3f),宽度会被突破,不会截断数字——这也是实验报告让你思考的点。
#include <stdio.h>
int main()
{
float cn, ma, en, pc, sum, avg;
printf("输入语文 数学 英语 计算机:");
scanf("%f%f%f%f", &cn, &ma, &en, &pc);
sum = cn + ma + en + pc;
avg = sum / 4;
printf("总分:%.1f 平均分:%.1f\n", sum, avg);
return 0;
}这题看着简单,但有一个隐藏陷阱:如果写成 int sum; 而用 avg = sum / 4;,因为 sum 是 int、4 也是 int,又是整数除法,86.25 会变成 86。
正确做法:sum 用 float,或者写 avg = sum / 4.0;。
#include <stdio.h>
int main()
{
int t, h, m, s;
printf("输入总秒数:");
scanf("%d", &t);
h = t / 3600; /* 1 小时 = 3600 秒 */
m = t % 3600 / 60; /* 去掉小时后剩下的秒数,再整除 60 */
s = t % 60; /* 最后余下的就是秒 */
printf("%d 小时 %d 分 %d 秒\n", h, m, s);
return 0;
}这是「单位换算三连」的标准写法,顺序不能乱:
- 先用
/3600取出小时; - 再用
%3600把小时「扣掉」,剩下的秒数/60得分钟; - 最后
%60得秒。
写成 m = t / 60; 就错了——那会把小时部分也重复算进分钟里。
#include <stdio.h>
#define PI 3.1415926
int main()
{
double r, s, v;
printf("输入半径:");
scanf("%lf", &r);
s = 4 * PI * r * r;
v = 4.0 / 3 * PI * r * r * r; /* 注意:不能写 4/3 */
printf("表面积:%.2f 体积:%.2f\n", s, v);
return 0;
}核心陷阱4/3 是两个整数相除,结果是 1,体积会算成原来的 3/4 倍(正确答案的 75%),而且不报错,属于「静默错误」——最坑的一种。
三种正确写法:4.0/3、4.0/3.0、(double)4/3。
PI 用什么?直接写 3.14159 简单但精度有限;用宏 #define PI 3.1415926 便于统一修改。不建议依赖 M_PI,因为某些编译器(尤其老版本 VC)默认不定义它。
TASK 05任务五 · 健康状况检查系统设计
对应实验 4「选择结构(if 分支)」。这一章是逻辑最容易写错的地方:短路求值、边界条件、= 与 ==。
5.1 知识储备
① 条件表达式:关系运算 + 逻辑运算
| 运算符 | 含义 | 例子(假设 a=3, b=5) |
|---|---|---|
> < | 大于、小于 | a < b → 1(真) |
>= <= | 大于等于、小于等于 | a >= 3 → 1 |
== | 等于(两个等号) | a == 3 → 1 |
!= | 不等于 | a != b → 1 |
&& | 逻辑与:两边都真才真 | a > 0 && b > 0 → 1 |
|| | 逻辑或:一边真就真 | a > 4 || b > 4 → 1 |
! | 逻辑非:取反 | !(a > 0) → 0 |
if (5) 也是成立的。② 短路求值(实验 4 任务 1 的考点)
int a = 0, b = 6, d;
a && ++b; /* a 已经是 0(假),&& 右边根本不会执行 → b 仍是 6 */
d = b || a++; /* b 是 6(真),|| 右边根本不会执行 → a 仍是 0 */
printf("%d,%d\n", a, b); /* 输出 0,6 */A && B:A 为假时,B 不执行。A || B:A 为真时,B 不执行。所以上面的
++b 和 a++ 都被跳过了。这是考试最爱考的一道「陷阱题」。③ 三种 if 形式
/* 单分支 */
if (条件) { 语句; }
/* 双分支 */
if (条件) { 语句1; } else { 语句2; }
/* 多分支 */
if (条件1) { 语句1; }
else if (条件2) { 语句2; }
else if (条件3) { 语句3; }
else { 语句4; }>=90,再写 >=80,否则 95 分会被 >=80 先接住,判成 B。5.2 例题实操
#include <stdio.h>
int main()
{
int a = 0, b = 6, c, d;
a && ++b;
d = b || a++;
printf("%d,%d\n", a, b);
return 0;
}逐步推演(这正是实验报告要求你写的过程):
a && ++b:先看a,a=0 是假,&&直接短路,++b不执行 → b 还是 6。b || a++:先看b,b=6 非 0,是真,||直接短路,a++不执行 → a 还是 0。- 所以输出
0,6。
如果把 a && ++b; 改成 a || ++b;,因为 a 是假,|| 要看右边,++b 就会执行,b 变成 7。这个对比实验报告里也让你做。
条件:能被 4 整除且不能被 100 整除,或能被 400 整除。
#include <stdio.h>
int main()
{
int y;
printf("输入年份:");
scanf("%d", &y);
if ((y % 4 == 0 && y % 100 != 0) || y % 400 == 0)
printf("%d 是闰年\n", y);
else
printf("%d 不是闰年\n", y);
return 0;
}括号不能省。&& 的优先级高于 ||,虽然这里刚好不影响结果,但养成加括号的习惯,能避免一半的逻辑错误。
判断顺序也要想清楚:为什么要先 y%4==0 && y%100!=0?因为 1900 能被 4 整除也能被 100 整除,必须是「不是闰年」;而 2000 能被 400 整除,必须是「是闰年」。所以要把 400 那一支单独用 || 挂在后面。
#include <stdio.h>
int main()
{
float a, b, c, max, min;
printf("输入三个数:");
scanf("%f%f%f", &a, &b, &c);
max = a; min = a; /* 先假定 a 最大也最小 */
if (b > max) max = b;
if (c > max) max = c;
if (b < min) min = b;
if (c < min) min = c;
printf("最大值:%g 最小值:%g\n", max, min);
return 0;
}打擂台法:先把第一个数当成「当前擂主」,后面的数依次来挑战,大的就换上去。这样写比嵌套 if 清晰得多,而且扩展到 10 个数也一样写。
测试要覆盖三种情况:三数全等(3,3,3)、两数相等(3,3,1)、含负数(−5,−2,−9)。用 %g 输出可以自动去掉多余的小数 0。
90 以上 A,80—89 B,70—79 C,60—69 D,60 以下 E;小于 0 或大于 100 要给出提示。
#include <stdio.h>
int main()
{
float s;
printf("输入成绩:");
scanf("%f", &s);
if (s < 0 || s > 100) {
printf("成绩输入错误,请输入 0~100 的分数\n");
} else if (s >= 90) {
printf("等级:A\n");
} else if (s >= 80) {
printf("等级:B\n");
} else if (s >= 70) {
printf("等级:C\n");
} else if (s >= 60) {
printf("等级:D\n");
} else {
printf("等级:E\n");
}
return 0;
}三个要点:
- 非法输入必须放在最前面判断,否则 101 会被
>=90接住,判成 A。 - 条件只写一边:
s >= 90就够,不用写s >= 90 && s <= 100,因为 101 已经被前面拦掉了。这叫「利用多分支的已知条件」。 - 边界值要测:90、89、60、59——这是实验报告里点名的八组数据里的四个。
如果改用 switch,先要 s/10 取整再分情况,但负数会让结果变成 0 或负数,不如 if 链健壮——这是实验报告第 4 步的反思题。
BMI = 体重(kg) ÷ 身高(m)²。判定:<18.5 偏瘦,18.5—23.9 正常,24—27.9 超重,≥28 肥胖。
#include <stdio.h>
int main()
{
double h, w, bmi;
printf("输入身高(m) 体重(kg):");
scanf("%lf%lf", &h, &w);
if (h <= 0) {
printf("身高输入有误\n");
} else {
bmi = w / (h * h);
printf("BMI = %.1f ", bmi);
if (bmi < 18.5)
printf("偏瘦\n");
else if (bmi < 24)
printf("正常\n");
else if (bmi < 28)
printf("超重\n");
else
printf("肥胖\n");
}
return 0;
}这题把前面所有知识点串起来了:输入(任务四)+ 算术运算(任务二)+ 多分支(任务五)。
h * h必须加括号,写成w / h * h就变成了(w/h)*h = w,结果永远是体重——一个非常隐蔽的错误。- 先判断
h <= 0,避免除零(C 语言里 double 除 0 会得到 inf,不报错但结果没意义)。 - 分支条件同样只写一边,靠顺序兜住区间。
PART 06五个任务一句话总结 + 20 条必背
先看这张总表:每个任务到底在考什么
| 任务 | 一句话本质 | 必考的 2 个点 | 最容易丢分 |
|---|---|---|---|
| 任务一 ATM 主界面 |
把字打到屏幕上,学会程序骨架 | ① printf 的格式符 ② \n 换行 |
漏分号、中文标点、窗口闪退 |
| 任务二 综合积分 |
算数,但类型决定了结果 | ① 整数除法截断 ② 强制类型转换 |
5/3 得 1、4/3 得 1 |
| 任务三 象限流程图 |
先想清楚,再动手写 | ① 四种框的形状 ② 三种基本结构 |
循环结构少画回指箭头 |
| 任务四 输出格式 |
输入输出全是细节,细节全是分 | ① 宽度/精度/对齐 ② scanf 格式串与 & |
%c 吃回车、scanf 漏 & |
| 任务五 健康检查 |
让程序会「选」,逻辑顺序决定对错 | ① 短路求值 ② 多分支的条件顺序 |
= 与 ==、if 后多分号 |
26 道例题速查:每道题到底在练什么
| 题号 | 练的是什么 | 一句话要点 |
|---|---|---|
| 任务一·例1 | printf 输出多行文字 | 每句末尾 \n 换行,不写就全挤一行 |
| 任务一·例2 | 一次 printf 输出三行 | 一个字符串里可以有多个 \n |
| 任务一·例3 | 先定义后赋值 vs 初始化 | 初始化更安全,避免用到垃圾值 |
| 任务一·例4 | scanf 输入 + 简单比较 | 变量前必须加 & |
| 任务二·例1 | 改错:整数除法 | 5/3 先截断成 1,三种改写都要会 |
| 任务二·例2 | ASCII 转换 + 三目运算符 | 大小写差 32;连续读字符要先吃回车 |
| 任务二·例3 | sqrt + 运算优先级 | 分母 2*a 必须加括号 |
| 任务二·例4 | 分离各位数字 | %10 取末位、/10 砍末位 |
| 任务三·例1 | 象限判断(流程图 + 代码) | 先判轴,再判象限;四种情况不重不漏 |
| 任务三·例2 | 素数判断流程图 | 循环的标志是「往回指的箭头」 |
| 任务三·例3 | 流程图翻译成代码 | 矩形→赋值、菱形→if/while、平行四边形→scanf/printf |
| 任务四·例1 | 三种 scanf 格式串 | 格式串里的普通字符要原样输入 |
| 任务四·例2 | 宽度 / 精度 / 对齐 | %9.3f = 总宽 9、小数 3 位 |
| 任务四·例3 | 总分平均(隐藏整数除法) | sum 用 float 或除 4.0 |
| 任务四·例4 | 秒转时分秒 | / 与 % 交替用,顺序不能乱 |
| 任务四·例5 | 4/3 陷阱 | 必须写 4.0/3 |
| 任务五·例1 | 短路求值 | && 左边假就短路,|| 左边真就短路 |
| 任务五·例2 | 闰年判断 | 三条件一个不能少,括号要加 |
| 任务五·例3 | 三数最值(打擂台) | 先假定第一个是擂主,再依次挑战 |
| 任务五·例4 | 成绩等级 + 非法输入 | 非法值先拦,条件从严格到宽松 |
| 任务五·例5 | BMI 综合应用 | h*h 加括号,先判除零 |
| 手写 1 | 圆周长面积 | 纯顺序结构,r*r 别写成 r*2 |
| 手写 2 | 四位数拆位 | 固定「个→十→百→千」顺序 |
| 手写 3 | 三角形判断 | 两层 if:先判能否构成,再判类型 |
| 手写 4 | 年月求天数 | 12 个月分三类,2 月单独判闰年 |
| 手写 5 | 字符分类 | 用 ASCII 区间,两头都要写 |
20 条必背:考前一天只看这一页
程序结构
- 必须有
#include <stdio.h>才能用 printf/scanf - 入口是
int main(),结尾return 0; - 每条语句以
;结束 - 严格区分大小写,标点用英文半角
数据类型
int4 字节、float4、double8、char1- char 存的是 ASCII:
'A'=65、'a'=97、'0'=48 - 大小写差 32,大写转小写
+32 %d整数、%f小数、%c字符、%s字符串、%lf读 double
运算陷阱
- 两个 int 相除先截断:
5/3=1,要小数就写(float)a/b 4/3得 1,4.0/3才得 1.333%只能用于整数,a%b是余数a++先用后加,++a先加后用
输入输出
- scanf 的变量前必须加
& - scanf 格式串里的普通字符要原样输入
%c不跳过回车,连续读字符前加getchar();%-5d左对齐、%03d补零、%9.3f总宽 9 小数 3 位
选择结构
=是赋值,==才是判断相等&&左边假就短路,||左边真就短路- 多分支从上往下命中即停,条件要从「最严格」往「最宽松」写
if (x>0);多了个分号 = 语句体为空 = 判断失效
流程图
- 起止框椭圆、处理框矩形、判断框菱形、输入输出平行四边形
- 循环的标志是「有一条往回指的箭头」
PART 07报错急救表:编译不过时先查这张表
这些全部来自你四份实验报告的「常见错误与调试提示」,考试时也可能出成简答题。
| 报错 / 现象 | 真正的原因 | 怎么改 |
|---|---|---|
expected ';' before ... | 上一行语句末尾漏了分号 | 看报错行的前一行末尾 |
undefined reference to 'main' | 函数名拼错或写成 Main | C 区分大小写,改成 main |
stray '\' in program | 中文全角标点混入代码 | 检查引号、逗号、分号是不是英文半角 |
| 窗口一闪而过 | 程序正常结束,控制台自动关闭 | return 0; 前加 getchar(); |
| 中文显示乱码 | 源文件编码与控制台编码不一致 | 另存为 UTF-8,或改用英文输出 |
输出 1.000000 | 两个整数相除,先截断再赋值 | 强转其一为 float,或写 1.0 |
undefined reference to 'sqrt' | 没包含 math.h | 加 #include <math.h> |
%d 输出浮点数变乱码 | 格式符与实参类型不匹配 | 浮点用 %f,整型用 %d |
| 结果总是随机数 | scanf 漏写 & | 检查 &a、&b |
| 输入数字后紧跟字符读不到 | 回车符被下一次读入吸收 | 两次读取之间加 getchar(); |
| 条件永远成立 | 把 == 写成 = | 赋值表达式的值恒非零,改成 == |
| 判断语句没反应 | if (x>0); 后面多了分号 | 删掉分号,或加花括号 |
| 浮点数比较失败 | 用 == 直接比浮点 | 改用 fabs(a-b) < 1e-6 |
| 闰年判断出错 | 只判断了「能被 4 整除」 | 补全 (%4==0 && %100!=0) || %400==0 |
PART 08自测 35 题(先做完再展开答案)
- 以下程序输出什么?
printf("%d", 'A'); int a=7, b=2; printf("%f", a/b);输出什么?为什么?- 写出三种让
7/2得到 3.5 的写法。 printf("%9.3f", 3.14159);输出占几个字符、前面有几个空格?printf("%-5d", 42);的结果是什么(用·表示空格)?scanf("%d,%d", &a, &b);运行时输入5 8会怎样?- 为什么连续读两个
%c时容易出问题?怎么解决? char c='b'; c=c-32;之后 c 是什么?- 写一条语句输出
90%。 int a=5; printf("%d %d", a++, ++a);从「先加后用」角度解释为什么会这样。a=0, b=3; if (a && b++);执行后 b 是多少?a=5; if (a=0) printf("真"); else printf("假");输出什么?为什么?- 写一段判断
n是偶数的代码。 - 成绩等级判断,为什么
>=90必须写在>=80前面? - 输入 100,用
%d输出三位数逆序的结果是 1,怎么让它显示成 001? - 判断闰年的完整条件是什么(用 % 和逻辑运算符写出来)?
4/3*3.14159*1*1*1的结果约为多少?错在哪?- 流程图里判断框用什么形状?输入输出框用什么形状?
- 怎么从流程图看出这是循环结构而不是顺序结构?
int sum=0; sum=sum+5;之后 sum 是多少?这一行的作用是什么?- 写代码:输入秒数 3661,输出
1 小时 1 分 1 秒。 if (x > 0); printf("正数");有什么问题?- 三个数求最大值,不打擂台的话最容易漏掉哪种情况?
float和double哪个精度高?读 double 用什么格式符?printf("%c", 65);输出什么?- 找错:
int a; scanf("%d", a);错在哪? printf("%5.1f", 3.14159);输出什么(用·表示空格)?- 写一条语句,把
double x四舍五入取整存到int n里。 int i = 2; printf("%d", i++); printf("%d", i);两次分别输出什么?- 找错:
if (a > b); { printf("a 大"); } char c = 'A'; printf("%c%d", c + 1, c);输出什么?- 写一段判断字符 ch 是否为小写字母的代码。
printf("%d", 7 % 3 * 2);输出什么?- 找错:
if (x = 5) printf("yes"); - 写出「总宽 9、左对齐、保留 2 位小数」的格式符。
展开答案
65(char 的本质是 ASCII 码,%d按整数输出)1.000000,因为7/2是整数除法,先得 3,再转成浮点(float)7/2、7/(float)2、7*1.0/2(或7.0/2)- 共 9 个字符,前面 3 个空格(
3.142只占 5 列,加上 4 个空格;注意 3.14159 四舍五入为 3.142) 42···(左对齐,右边补 3 个空格)- a 得到 5,但 b 读不到(因为格式串要求逗号),b 是随机值
- 因为第一次输入后的回车符还留在缓冲区,会被第二个
%c读走;在两次之间加getchar(); 'B'(98 − 32 = 66,ASCII 66 就是 B)printf("90%%");(两个百分号才输出一个)a++先取 5 再自增;++a先把 a 加到 7 再取值,所以输出5 7(具体顺序依编译器而定,考试一般不考未定义行为,记住「先用后加 / 先加后用」即可)- b 还是 3。a 是 0(假),
&&短路,右边的b++不执行 - 输出「假」。
a=0是赋值,整个表达式的值是 0,被判为假(这是=与==的经典陷阱) if (n % 2 == 0) printf("偶数");- 多分支从上往下命中即停。如果
>=80在前,95 分会先满足它,被判成 B,A 就永远取不到 - 用
printf("%03d", r);(宽度 3,空位补 0) (y%4==0 && y%100!=0) || y%400==0- 约 3.14。
4/3先算成 1,所以结果只有正确答案的 75% - 判断框是菱形,输入输出框是平行四边形
- 看有没有一条往回指的箭头(流程线回到前面的步骤)
- sum 是 5;这行是「累加」,等价于把 sum 自身加上 5 再存回去,循环求和时天天用
h=t/3600; m=t%3600/60; s=t%60; printf("%d 小时 %d 分 %d 秒", h,m,s);if后面多了分号,语句体变成空语句,printf无论条件真假都会执行- 三数全相等、或两数相等的情况(打擂台法天然不会漏)
double精度高;读 double 用%lf,输出用%fA(65 对应字符 A)- 漏了取地址符,应写
scanf("%d", &a); ··3.1(3.1占 3 列,在 5 列里右对齐,前面补 2 个空格)n = (int)(x + 0.5);(正数适用;负数要写成(int)(x - 0.5))- 先输出
2,再输出3(i++先取值后自增) if后面多了分号,条件等于空语句,花括号里的 printf 会无条件执行B65(c+1得 66 按字符输出是 B,c按整数输出是 65)if (ch >= 'a' && ch <= 'z') printf("小写");2(7%3得 1,再乘 2;%和*同级从左往右)=是赋值,表达式值为 5(恒真),永远打印 yes;应改成==%-9.2f
PART 09两天冲刺:按小时排给你
| 时间 | 做什么 | 具体到动作 |
|---|---|---|
| D1 上午 3 小时 | 任务一 + 任务二 | 把 PART 00 的 hello.c 亲手敲一遍跑通(能跑通就说明环境没问题)。然后读任务一、任务二的知识储备,重点抄「整数除法」那一块到一张 A4。 |
| D1 下午 3 小时 | 任务二例题 | 敲例 1(改错)、例 3(求根)、例 4(逆序数)。每题先自己写,卡住再看解析。逆序数的「取余 + 整除」组合要能默写。 |
| D1 晚上 2 小时 | 任务三 + 任务四前半 | 背流程图四种框;把「象限判断」流程图手画一遍。然后读任务四的 printf 宽度精度,把 %9.3f、%-5.2s 的含义念出声。 |
| D2 上午 3 小时 | 任务四例题 | 敲例 1(三种 scanf)、例 4(秒转换)、例 5(球体积,重点看 4/3)。这三种是填空和改错的高频点。 |
| D2 下午 3 小时 | 任务五 | 先手推例 1 的短路求值(写出 a、b 的变化过程),再敲闰年、成绩等级两道。成绩等级的顺序问题必须想明白。 |
| D2 晚上 2 小时 | 自测 + 收口 | 做 PART 08 的 25 题,限时 40 分钟。错题回到对应任务的例题重看一遍。睡前只读 PART 06 的 20 条必背。 |
| 考前 30 分钟 | 只做三件事 | 读 20 条必背 → 扫一遍报错急救表 → 想一遍「整数除法 / scanf 的 & / == 与 = 」这三个最常丢分的点。 |
PART 10六个必背代码模板 + 五道手写题
这些模板覆盖了前五个任务里 90% 的写法。考试时不用从零想,先认出这是哪一类,再套对应模板改两个变量名就是答案。
10.1 六个模板(照着默写)
模板 1 · 输入两个数,输出较大者(打擂台)
int a, b, max;
scanf("%d%d", &a, &b);
max = a;
if (b > max) max = b;
printf("较大者:%d\n", max);模板 2 · 三个数求最值(打擂台法,可扩到 n 个)
max = a; min = a; if (b > max) max = b; if (c > max) max = c; if (b < min) min = b; if (c < min) min = c;
模板 3 · 分离各位数字(三位、四位通用)
/* 三位数 n */ g = n % 10; /* 个位 */ s = n / 10 % 10; /* 十位 */ b = n / 100; /* 百位 */ /* 四位数 n */ g = n % 10; s = n / 10 % 10; b = n / 100 % 10; q = n / 1000;
%10,砍掉末位用 /10」。两个动作交替用,就能从右往左剥出每一位。模板 4 · 单位换算(秒 → 时分秒)
h = t / 3600;
m = t % 3600 / 60;
s = t % 60;
printf("%d 小时 %d 分 %d 秒\n", h, m, s);模板 5 · 整数算出小数(三种写法任选)
avg = (float)sum / n; /* 写法一:强转 */ avg = sum / (float)n; /* 写法二:强转分母 */ avg = sum * 1.0 / n; /* 写法三:乘浮点常量 */ avg = sum / 4.0; /* 写法四:分母直接写浮点 */
模板 6 · 多分支判等级(注意顺序)
if (s < 0 || s > 100) {
printf("输入错误\n"); /* 非法值放最前 */
} else if (s >= 90) {
printf("A\n");
} else if (s >= 80) {
printf("B\n");
} else if (s >= 70) {
printf("C\n");
} else if (s >= 60) {
printf("D\n");
} else {
printf("E\n");
}10.2 五道手写题(先自己在纸上写,再对答案)
这五道全部只用前五个任务的知识,不涉及循环和数组。建议每题限时 8 分钟。
易错① 面积是
r * r 不是 r * 2;② 用 double 就必须用 %lf 读、%f 或 %.2f 写;③ 半径 2 时周长和面积数值相同,不是算错了。#include <stdio.h>
#define PI 3.1415926
int main()
{
double r, c, s;
printf("输入半径:");
scanf("%lf", &r);
c = 2 * PI * r;
s = PI * r * r;
printf("周长:%.2f 面积:%.2f\n", c, s);
return 0;
}半径 2 时周长和面积数值相同,别以为算错了——2πr = πr² 在 r=2 时恰好相等。
%10 取末位、/10 砍末位」组合出来:个位 n%10、十位 n/10%10、百位 n/100%10、千位 n/1000。从右往左剥,逻辑最顺。易错先算千位再算个位,容易把中间步骤写乱;建议固定「个→十→百→千」的顺序。
#include <stdio.h>
int main()
{
int n, q, b, s, g;
scanf("%d", &n);
g = n % 10;
s = n / 10 % 10;
b = n / 100 % 10;
q = n / 1000;
printf("千位:%d\n百位:%d\n十位:%d\n个位:%d\n", q, b, s, g);
return 0;
}if 嵌套,外层的条件成立才轮到内层。易错① 三个条件都要写(
a+b>c、a+c>b、b+c>a),只写一个会漏;② 等边要 a==b && b==c 两个都成立,写成 || 就错了。#include <stdio.h>
int main()
{
double a, b, c;
scanf("%lf%lf%lf", &a, &b, &c);
if (a + b > c && a + c > b && b + c > a) {
if (a == b && b == c)
printf("等边三角形\n");
else if (a == b || b == c || a == c)
printf("等腰三角形\n");
else
printf("普通三角形\n");
} else {
printf("不能构成三角形\n");
}
return 0;
}&& 串起来;只要有一个不满足就不构成三角形。易错① 闰年条件要写全
(y%4==0 && y%100!=0) || y%400==0;② 千万别写成 m==4 || 6 || 9 || 11——在 C 里 || 6 就是「非零即真」,整个条件恒为真,4/6/9/11 月全变 31 天。#include <stdio.h>
int main()
{
int y, m, days;
scanf("%d%d", &y, &m);
if (m == 2) {
if ((y % 4 == 0 && y % 100 != 0) || y % 400 == 0)
days = 29;
else
days = 28;
} else if (m == 4 || m == 6 || m == 9 || m == 11) {
days = 30;
} else {
days = 31;
}
printf("%d 年 %d 月有 %d 天\n", y, m, days);
return 0;
}这题是「闰年 + 多分支」的组合,也是实验 4 任务 2 的升级版。2 月单独拿出来判,是因为只有它受闰年影响。
'A'<=ch && ch<='Z' 这种写法就够,不用列举 26 个字母。易错区间必须两头都写。只写
ch >= 'a' 会把所有大于 a 的字符(包括数字、符号)都算进来。#include <stdio.h>
int main()
{
char ch;
printf("输入一个字符:");
scanf("%c", &ch);
if (ch >= 'A' && ch <= 'Z')
printf("大写字母\n");
else if (ch >= 'a' && ch <= 'z')
printf("小写字母\n");
else if (ch >= '0' && ch <= '9')
printf("数字字符\n");
else
printf("其他字符\n");
return 0;
}'A' <= ch && ch <= 'Z' 利用了 ASCII 码的连续性(大写 65—90、小写 97—122、数字 48—57),比列举 26 个字母省事得多。