C PROGRAMMING · TASK 1-5

C 语言前五个任务 · 零基础复习讲义

📘 《C语言程序设计》第 4 版(微课版·任务式·AI 助学) 李刚 · 徐义晗 主编 人民邮电出版社

面向零基础:每个知识点都配能直接跑通的完整代码和真实输出,不讲空理论。 内容按教材前五个任务组织,并与你手上的四份课内实验(实验 1—4)逐条对应。 每个任务的例题都标了「这道题对应哪次实验」,复习时可以直接对着实验报告核。

PART 00零基础起步:先弄懂这四件事

① 一个 C 程序的最小骨架
#include <stdio.h>
int main()
{
    printf("Hello\n");
    return 0;
}
② 四个步骤,一步不能少
  1. 编辑:写代码,存成 .c 文件
  2. 编译:把 .c 变成 .exe(快捷键 F11)
  3. 运行:看结果
  4. 调试:结果不对就回来改
③ 每一行的作用
  • #include:告诉编译器「我要用别人写好的工具箱」
  • stdio.h:输入输出工具箱(printf / scanf 在里面)
  • int main():程序唯一的入口,从这开始执行
  • return 0;:告诉系统「我正常结束了」
④ 三条铁律
  • 每条语句结尾必须有分号 ;
  • 标点必须是英文半角,中文逗号、中文分号、中文引号全会报错
  • C 语言严格区分大小写:Main ≠ main
⚠ 零基础阶段 90% 的报错都来自这三条铁律漏分号、中文标点、大小写写错。看到一屏红字别慌,先按这三条自查一遍,通常就解决一半。

第一个真实可跑的程序:算出 1 + 2

#include <stdio.h>
int main()
{
    int a = 1, b = 2;          /* 定义两个整数变量并赋值 */
    printf("%d + %d = %d\n", a, b, a + b);
    return 0;
}
运行结果1 + 2 = 3

看懂这一行就入门了:printf("格式串", 变量1, 变量2),格式串里的每个 %d 都会被后面的变量按顺序顶替。

TASK 01任务一 · ATM 主界面设计

对应实验 1「程序设计环境与程序结构」。这个任务只干一件事:把字打到屏幕上。看着简单,但它是后面所有代码的地基。

1.1 知识储备

考点要求重要度
C 程序的结构头文件、主函数、语句、返回值,缺一个都跑不起来★★★★
printf 的基本用法能输出文字、变量、多个变量★★★★★
转义字符 \n \t换行、制表对齐,区别要分清★★★★
格式控制符%d %f %c %s 各管什么类型★★★★★
编译运行与调试会新建、编译、运行;会看报错定位行号★★★★
常见错误漏分号、大小写、全角符号、窗口闪退★★★

① printf 到底怎么用

printf("格式串", 变量1, 变量2, ...);

格式串里有两类东西:普通字符(原样输出)和格式符(以 % 开头,被后面的变量替换)。

格式符对应类型例子
%dint 整数printf("%d", 123); → 123
%ffloat / double 小数printf("%f", 1.5); → 1.500000
%cchar 单个字符printf("%c", 'A'); → A
%s字符串printf("%s", "abc"); → abc
%%输出一个百分号printf("90%%"); → 90%

② 转义字符:看不见的字符怎么写

写法含义效果
\n换行光标跳到下一行开头
\t制表符(Tab)跳到下一个制表位,用来对齐列
\\一个反斜杠输出 \
\"一个双引号在字符串里打出 "
一句话区分\n 管「换不换行」,\t 管「对齐到第几列」。做 ATM 菜单、成绩表格时,\t 比手动敲空格靠谱得多。

1.2 例题实操

例 1输出个人自我介绍,每项占一行 实验1·任务1

要求姓名、年龄、籍贯、爱好各占一行,且冒号对齐。

#include <stdio.h>
int main()
{
    printf("姓名:陈泽阳\n");
    printf("年龄:18\n");
    printf("籍贯:福建平潭\n");
    printf("爱好:编程、篮球\n");
    return 0;
}
运行结果姓名:陈泽阳 年龄:18 籍贯:福建平潭 爱好:编程、篮球
解析

每一行一个 printf,句末的 \n 负责换行。如果不写 \n,四个 printf 的输出会连成一整行:姓名:陈泽阳年龄:18籍贯…——这就是实验报告里那道思考题「不加 \n 会有什么后果」的答案。

想让冒号对齐,把 : 换成 \t:printf("姓名\t陈泽阳\n");。

例 2输出三行:21 个星号 / Very good / 21 个星号,只用一次 printf 实验1·任务2

关键是「一次 printf 里放多个 \n」,而不是写三次 printf。

#include <stdio.h>
int main()
{
    printf("*********************\nVery good\n*********************\n");
    return 0;
}
运行结果********************* Very good *********************
解析

一个字符串里可以出现任意多个 \n,每遇到一个就换一次行。所以「三行内容」不需要三条语句。

星号数量要数准:21 个。考试时如果要求「星号数量由变量控制」,那就得用循环了(任务六)。

例 3求两数之和:a=123、b=456,分别用「先定义后赋值」和「定义时初始化」两种写法 实验1·任务3
#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;
}
运行结果写法一:123 + 456 = 579 写法二:123 + 456 = 579
解析

两种写法的区别只在「什么时候给值」:写法一先占一块内存,值不确定(是垃圾值),后面才填;写法二在占内存的同时就填好,更安全、更短。

实验报告要求「比较二者区别」,可以这样答:初始化赋值能避免「变量未初始化就参与运算」导致的随机结果,实际工程中都推荐写法二。

⚠ 如果写成 int a, b; printf("%d", a+b); 而不赋值,输出可能是任意数,这属于「用了未初始化的变量」。

例 4输入两个整数,输出较大者;再输入矩形两边,输出面积 实验1·任务4、5

这两题引入了 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;
}
运行结果(输入 3,5 与 3,5)请输入两个整数(用逗号隔开):3,5 较大者:5 请输入矩形的长和宽:3,5 面积:15
解析

三个重点:

  • scanf("%d,%d", &a, &b) 里的逗号是普通字符,你输入时就必须真的敲逗号。这个坑在任务四会专门讲。
  • & 是取地址符,意思是「把读到的数放到 a 那块内存里」,漏写会得到随机值甚至崩溃。
  • if ... else ... 属于任务五的内容,这里先用最小形式。

TASK 02任务二 · 计算学生的综合积分

对应实验 2「数据类型及算术表达式」。这是丢分最集中的一章——不是不会写,而是被「整数除法」「类型转换」这些细节坑掉。

2.1 知识储备

① 四种基本数据类型

类型占字节能存什么例子
int4 字节整数,约 ±21 亿int age = 18;
float4 字节小数,约 7 位有效数字float h = 1.75f;
double8 字节小数,约 15 位有效数字double pi = 3.14159;
char1 字节单个字符(本质是 ASCII 码)char c = 'A';
char 其实就是小整数'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 例题实操

例 1程序改错:期望输出 1.666667,实际输出 1.000000 实验2·任务1
#include <stdio.h>
int main()
{
    int a, b;
    float c;
    a = 5;
    b = 3;
    c = a / b;
    printf("%f\n", c);
    return 0;
}
运行结果1.000000
解析

错误在第 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。

例 2小写字母转大写;输入两个字符,输出较小字符的 ASCII 码 实验2·任务2、3
#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;
}
运行结果输入一个小写字母:a a 对应的大写是 A 输入两个字符:AB 较小字符的 ASCII:65
解析

两个关键点:

  • ±32 的规律:ASCII 表里 'a'=97、'A'=65,正好差 32。所以大写转小写 +32,小写转大写 -32。
  • getchar() 吃掉回车:第一次 scanf 后,输入缓冲区里还剩一个回车符,会被下一次 %c 当成字符读走,导致后面的输入错位。所以在两次之间加一个 getchar();。
  • 三目运算符 c1 < c2 ? c1 : c2 的意思是:条件成立取前者,否则取后者。等价于一个 if-else,但更短。
例 3求一元二次方程的两个实根,保留两位小数 实验2·任务4

需要 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;
}
运行结果(a=1,b=-5,c=6)x1=3.00 x2=2.00
解析

三个必须注意的点:

  • #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。

例 4输入一个三位正整数,输出它的逆序数(不许用字符串) 实验2·任务5

核心是「取余拿个位、整除丢个位」这对组合。注意 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;
}
运行结果输入三位数:123 逆序数:321
解析

分离各位的标准套路(背下来,后面数组、循环都会用到):

  • 个位: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 例题实操

例 1画出「判断坐标点在第几象限」的流程图,并写出对应代码 教材·任务三

点在坐标平面上有四种情况,先判断是不是在轴上,再判断象限。

流程图思路(按顺序画)
  1. 椭圆:开始
  2. 平行四边形:输入 x, y
  3. 菱形:x == 0 || y == 0 ? →「是」分支输出「在坐标轴上」,结束
  4. 菱形:x > 0 ? →「是」再判断 y > 0 ?:是则第一象限,否则第四象限
  5. 「否」分支再判断 y > 0 ?:是则第二象限,否则第三象限
  6. 椭圆:结束

对应的代码(和流程图一一对应):

#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;
}
运行结果输入 x,y:3,-2 第四象限

画图题评分点:起止框必须是椭圆、判断框必须是菱形、每个判断要有「是 / 否」两条出口标注。少一个出口标注就扣分。

例 2「判断素数」的流程图要点 教材·AI助学案例
要点拆解
  1. 输入 n;若 n <= 1,直接判定「不是素数」并结束(这是最容易漏的边界)。
  2. 令 i = 2(从 2 开始试除)。
  3. 菱形:i <= n-1 ? →「否」表示已经试完,判定「是素数」。
  4. 菱形:n % i == 0 ? →「是」判定「不是素数」并结束;「否」则 i = i + 1,箭头回到第 3 步(这条回指的箭头就是循环结构的标志)。

图里必须有那条往回指的箭头,这是「循环」和「顺序」的唯一区别。没有回指箭头,判卷老师会认为你画成了顺序结构。

例 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,空位补 00 就是「补零」
%.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 例题实操

例 1同一段程序,三种 scanf 写法分别该怎么输入 实验3·任务1
#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 才对应真正的数据。

例 2程序填空: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;
}
运行结果(空格用 · 标出)···123.457 ab···
解析

填空 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),宽度会被突破,不会截断数字——这也是实验报告让你思考的点。

例 3输入四门课成绩,求总分和平均分(保留一位小数) 实验3·任务4
#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;
}
运行结果输入语文 数学 英语 计算机:90 85 78 92 总分:345.0 平均分:86.3
解析

这题看着简单,但有一个隐藏陷阱:如果写成 int sum; 而用 avg = sum / 4;,因为 sum 是 int、4 也是 int,又是整数除法,86.25 会变成 86。

正确做法:sum 用 float,或者写 avg = sum / 4.0;。

例 4输入总秒数,输出「x 小时 x 分 x 秒」 实验3·任务5
#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;
}
运行结果输入总秒数:3661 1 小时 1 分 1 秒
解析

这是「单位换算三连」的标准写法,顺序不能乱:

  • 先用 /3600 取出小时;
  • 再用 %3600 把小时「扣掉」,剩下的秒数 /60 得分钟;
  • 最后 %60 得秒。

写成 m = t / 60; 就错了——那会把小时部分也重复算进分钟里。

例 5输入球半径,输出表面积和体积(保留两位小数),注意 4/3 的陷阱 实验3·任务6
#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;
}
运行结果输入半径:1 表面积:12.57 体积:4.19
解析

核心陷阱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
记住C 语言里「真」是 1,「假」是 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 例题实操

例 1阅读程序,说出 a、b 的最终值 实验4·任务1
#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;
}
运行结果0,6
解析

逐步推演(这正是实验报告要求你写的过程):

  1. a && ++b:先看 a,a=0 是假,&& 直接短路,++b 不执行 → b 还是 6。
  2. b || a++:先看 b,b=6 非 0,是真,|| 直接短路,a++ 不执行 → a 还是 0。
  3. 所以输出 0,6。

如果把 a && ++b; 改成 a || ++b;,因为 a 是假,|| 要看右边,++b 就会执行,b 变成 7。这个对比实验报告里也让你做。

例 2判断闰年 实验4·任务2

条件:能被 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;
}
测试数据2000 → 是闰年;1900 → 不是;2024 → 是;2023 → 不是
解析

括号不能省。&& 的优先级高于 ||,虽然这里刚好不影响结果,但养成加括号的习惯,能避免一半的逻辑错误。

判断顺序也要想清楚:为什么要先 y%4==0 && y%100!=0?因为 1900 能被 4 整除也能被 100 整除,必须是「不是闰年」;而 2000 能被 400 整除,必须是「是闰年」。所以要把 400 那一支单独用 || 挂在后面。

例 3输入三个数,输出最大值和最小值(不许用数组) 实验4·任务3
#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;
}
运行结果输入三个数:3 3 1 最大值:3 最小值:1
解析

打擂台法:先把第一个数当成「当前擂主」,后面的数依次来挑战,大的就换上去。这样写比嵌套 if 清晰得多,而且扩展到 10 个数也一样写。

测试要覆盖三种情况:三数全等(3,3,3)、两数相等(3,3,1)、含负数(−5,−2,−9)。用 %g 输出可以自动去掉多余的小数 0。

例 4成绩等级 A—E,并处理非法输入 实验4·任务5

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;
}
测试数据90 → A;89 → B;60 → D;59 → E;-1 → 提示错误;101 → 提示错误
解析

三个要点:

  • 非法输入必须放在最前面判断,否则 101 会被 >=90 接住,判成 A。
  • 条件只写一边:s >= 90 就够,不用写 s >= 90 && s <= 100,因为 101 已经被前面拦掉了。这叫「利用多分支的已知条件」。
  • 边界值要测:90、89、60、59——这是实验报告里点名的八组数据里的四个。

如果改用 switch,先要 s/10 取整再分情况,但负数会让结果变成 0 或负数,不如 if 链健壮——这是实验报告第 4 步的反思题。

例 5健康状况检查系统:输入身高体重,输出 BMI 结论 教材·任务五

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;
}
运行结果(1.75 / 68)BMI = 22.2 正常
解析

这题把前面所有知识点串起来了:输入(任务四)+ 算术运算(任务二)+ 多分支(任务五)。

  • 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 后多分号
怎么用这张表考前 10 分钟只看它:先看「一句话本质」确认自己知道这章在干什么,再看「必考的两个点」默念一遍,最后看「最容易丢分」提醒自己别踩。

26 道例题速查:每道题到底在练什么

题号练的是什么一句话要点
任务一·例1printf 输出多行文字每句末尾 \n 换行,不写就全挤一行
任务一·例2一次 printf 输出三行一个字符串里可以有多个 \n
任务一·例3先定义后赋值 vs 初始化初始化更安全,避免用到垃圾值
任务一·例4scanf 输入 + 简单比较变量前必须加 &
任务二·例1改错:整数除法5/3 先截断成 1,三种改写都要会
任务二·例2ASCII 转换 + 三目运算符大小写差 32;连续读字符要先吃回车
任务二·例3sqrt + 运算优先级分母 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秒转时分秒/ 与 % 交替用,顺序不能乱
任务四·例54/3 陷阱必须写 4.0/3
任务五·例1短路求值&& 左边假就短路,|| 左边真就短路
任务五·例2闰年判断三条件一个不能少,括号要加
任务五·例3三数最值(打擂台)先假定第一个是擂主,再依次挑战
任务五·例4成绩等级 + 非法输入非法值先拦,条件从严格到宽松
任务五·例5BMI 综合应用h*h 加括号,先判除零
手写 1圆周长面积纯顺序结构,r*r 别写成 r*2
手写 2四位数拆位固定「个→十→百→千」顺序
手写 3三角形判断两层 if:先判能否构成,再判类型
手写 4年月求天数12 个月分三类,2 月单独判闰年
手写 5字符分类用 ASCII 区间,两头都要写

20 条必背:考前一天只看这一页

程序结构
  1. 必须有 #include <stdio.h> 才能用 printf/scanf
  2. 入口是 int main(),结尾 return 0;
  3. 每条语句以 ; 结束
  4. 严格区分大小写,标点用英文半角
数据类型
  1. int 4 字节、float 4、double 8、char 1
  2. char 存的是 ASCII:'A'=65、'a'=97、'0'=48
  3. 大小写差 32,大写转小写 +32
  4. %d 整数、%f 小数、%c 字符、%s 字符串、%lf 读 double
运算陷阱
  1. 两个 int 相除先截断:5/3=1,要小数就写 (float)a/b
  2. 4/3 得 1,4.0/3 才得 1.333
  3. % 只能用于整数,a%b 是余数
  4. a++ 先用后加,++a 先加后用
输入输出
  1. scanf 的变量前必须加 &
  2. scanf 格式串里的普通字符要原样输入
  3. %c 不跳过回车,连续读字符前加 getchar();
  4. %-5d 左对齐、%03d 补零、%9.3f 总宽 9 小数 3 位
选择结构
  1. = 是赋值,== 才是判断相等
  2. && 左边假就短路,|| 左边真就短路
  3. 多分支从上往下命中即停,条件要从「最严格」往「最宽松」写
  4. if (x>0); 多了个分号 = 语句体为空 = 判断失效
流程图
  1. 起止框椭圆、处理框矩形、判断框菱形、输入输出平行四边形
  2. 循环的标志是「有一条往回指的箭头」

PART 07报错急救表:编译不过时先查这张表

这些全部来自你四份实验报告的「常见错误与调试提示」,考试时也可能出成简答题。

报错 / 现象真正的原因怎么改
expected ';' before ...上一行语句末尾漏了分号看报错行的前一行末尾
undefined reference to 'main'函数名拼错或写成 MainC 区分大小写,改成 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 题(先做完再展开答案)

  1. 以下程序输出什么?printf("%d", 'A');
  2. int a=7, b=2; printf("%f", a/b); 输出什么?为什么?
  3. 写出三种让 7/2 得到 3.5 的写法。
  4. printf("%9.3f", 3.14159); 输出占几个字符、前面有几个空格?
  5. printf("%-5d", 42); 的结果是什么(用·表示空格)?
  6. scanf("%d,%d", &a, &b); 运行时输入 5 8 会怎样?
  7. 为什么连续读两个 %c 时容易出问题?怎么解决?
  8. char c='b'; c=c-32; 之后 c 是什么?
  9. 写一条语句输出 90%。
  10. int a=5; printf("%d %d", a++, ++a); 从「先加后用」角度解释为什么会这样。
  11. a=0, b=3; if (a && b++); 执行后 b 是多少?
  12. a=5; if (a=0) printf("真"); else printf("假"); 输出什么?为什么?
  13. 写一段判断 n 是偶数的代码。
  14. 成绩等级判断,为什么 >=90 必须写在 >=80 前面?
  15. 输入 100,用 %d 输出三位数逆序的结果是 1,怎么让它显示成 001?
  16. 判断闰年的完整条件是什么(用 % 和逻辑运算符写出来)?
  17. 4/3*3.14159*1*1*1 的结果约为多少?错在哪?
  18. 流程图里判断框用什么形状?输入输出框用什么形状?
  19. 怎么从流程图看出这是循环结构而不是顺序结构?
  20. int sum=0; sum=sum+5; 之后 sum 是多少?这一行的作用是什么?
  21. 写代码:输入秒数 3661,输出 1 小时 1 分 1 秒。
  22. if (x > 0); printf("正数"); 有什么问题?
  23. 三个数求最大值,不打擂台的话最容易漏掉哪种情况?
  24. float 和 double 哪个精度高?读 double 用什么格式符?
  25. printf("%c", 65); 输出什么?
  26. 找错:int a; scanf("%d", a); 错在哪?
  27. printf("%5.1f", 3.14159); 输出什么(用·表示空格)?
  28. 写一条语句,把 double x 四舍五入取整存到 int n 里。
  29. int i = 2; printf("%d", i++); printf("%d", i); 两次分别输出什么?
  30. 找错:if (a > b); { printf("a 大"); }
  31. char c = 'A'; printf("%c%d", c + 1, c); 输出什么?
  32. 写一段判断字符 ch 是否为小写字母的代码。
  33. printf("%d", 7 % 3 * 2); 输出什么?
  34. 找错:if (x = 5) printf("yes");
  35. 写出「总宽 9、左对齐、保留 2 位小数」的格式符。
展开答案
  1. 65(char 的本质是 ASCII 码,%d 按整数输出)
  2. 1.000000,因为 7/2 是整数除法,先得 3,再转成浮点
  3. (float)7/2、7/(float)2、7*1.0/2(或 7.0/2)
  4. 共 9 个字符,前面 3 个空格(3.142 只占 5 列,加上 4 个空格;注意 3.14159 四舍五入为 3.142)
  5. 42···(左对齐,右边补 3 个空格)
  6. a 得到 5,但 b 读不到(因为格式串要求逗号),b 是随机值
  7. 因为第一次输入后的回车符还留在缓冲区,会被第二个 %c 读走;在两次之间加 getchar();
  8. 'B'(98 − 32 = 66,ASCII 66 就是 B)
  9. printf("90%%");(两个百分号才输出一个)
  10. a++ 先取 5 再自增;++a 先把 a 加到 7 再取值,所以输出 5 7(具体顺序依编译器而定,考试一般不考未定义行为,记住「先用后加 / 先加后用」即可)
  11. b 还是 3。a 是 0(假),&& 短路,右边的 b++ 不执行
  12. 输出「假」。a=0 是赋值,整个表达式的值是 0,被判为假(这是 = 与 == 的经典陷阱)
  13. if (n % 2 == 0) printf("偶数");
  14. 多分支从上往下命中即停。如果 >=80 在前,95 分会先满足它,被判成 B,A 就永远取不到
  15. 用 printf("%03d", r);(宽度 3,空位补 0)
  16. (y%4==0 && y%100!=0) || y%400==0
  17. 约 3.14。4/3 先算成 1,所以结果只有正确答案的 75%
  18. 判断框是菱形,输入输出框是平行四边形
  19. 看有没有一条往回指的箭头(流程线回到前面的步骤)
  20. sum 是 5;这行是「累加」,等价于把 sum 自身加上 5 再存回去,循环求和时天天用
  21. h=t/3600; m=t%3600/60; s=t%60; printf("%d 小时 %d 分 %d 秒", h,m,s);
  22. if 后面多了分号,语句体变成空语句,printf 无论条件真假都会执行
  23. 三数全相等、或两数相等的情况(打擂台法天然不会漏)
  24. double 精度高;读 double 用 %lf,输出用 %f
  25. A(65 对应字符 A)
  26. 漏了取地址符,应写 scanf("%d", &a);
  27. ··3.1(3.1 占 3 列,在 5 列里右对齐,前面补 2 个空格)
  28. n = (int)(x + 0.5);(正数适用;负数要写成 (int)(x - 0.5))
  29. 先输出 2,再输出 3(i++ 先取值后自增)
  30. if 后面多了分号,条件等于空语句,花括号里的 printf 会无条件执行
  31. B65(c+1 得 66 按字符输出是 B,c 按整数输出是 65)
  32. if (ch >= 'a' && ch <= 'z') printf("小写");
  33. 2(7%3 得 1,再乘 2;% 和 * 同级从左往右)
  34. = 是赋值,表达式值为 5(恒真),永远打印 yes;应改成 ==
  35. %-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 的 & / == 与 = 」这三个最常丢分的点。
实操建议这门课光看不练没用。上面每个例题都配了完整可跑的代码,至少把带 ⭐ 味道的那几个亲手敲一遍:hello.c、改错题、逆序数、秒转换、球体积、闰年、成绩等级。敲过一遍,考试写代码的手感就回来了。

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;
为什么用打擂台而不是嵌套 if嵌套 if 要写 6 种比较情况,容易漏;打擂台只需 4 行,而且数字变多也不用改结构。

模板 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");
}
⚠ 模板 6 的两条铁律① 非法值(<0 或 >100)必须在最前面拦掉。② 条件必须从「最严格」往「最宽松」写;反过来写,A 永远取不到。

10.2 五道手写题(先自己在纸上写,再对答案)

这五道全部只用前五个任务的知识,不涉及循环和数组。建议每题限时 8 分钟。

手写 1输入圆的半径,输出周长和面积(保留两位小数)
参考代码
思路这是纯顺序结构:输入一个 r,算出两个结果,没有判断也没有循环。公式都只用到 r,所以按「输入 → 算 → 输出」三段写就行。
易错① 面积是 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 周长:12.57 面积:12.57

半径 2 时周长和面积数值相同,别以为算错了——2πr = πr² 在 r=2 时恰好相等。

手写 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;
}
运行结果(输入 2026)千位:2 百位:0 十位:2 个位:6
手写 3输入三个边长,判断能否构成三角形;若能,再判断是等边、等腰还是普通三角形
参考代码
思路分两层判断:外层先判「能不能构成三角形」,能构成再进内层判「是什么三角形」。这就是典型的 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;
}
测试数据3 3 3 → 等边;3 3 4 → 等腰;3 4 5 → 普通;1 2 5 → 不能构成
判断技巧只需检查「任意两边之和大于第三边」,三个条件用 && 串起来;只要有一个不满足就不构成三角形。
手写 4输入年份和月份,输出该月有多少天 综合
参考代码
思路把 12 个月分三类处理:2 月(28 或 29)、4/6/9/11 月(30 天)、其余(31 天)。只有 2 月受闰年影响,所以单独拿出来做内层判断。
易错① 闰年条件要写全 (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;
}
测试数据2024 2 → 29 天;2023 2 → 28 天;2024 4 → 30 天;2024 12 → 31 天

这题是「闰年 + 多分支」的组合,也是实验 4 任务 2 的升级版。2 月单独拿出来判,是因为只有它受闰年影响。

手写 5输入一个字符,判断它属于大写字母、小写字母、数字还是其他字符
参考代码
思路利用 ASCII 码的连续性做区间判断:大写 65—90、小写 97—122、数字 48—57,所以用 '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 → 大写;b → 小写;7 → 数字;@ → 其他
为什么用区间而不用具体值'A' <= ch && ch <= 'Z' 利用了 ASCII 码的连续性(大写 65—90、小写 97—122、数字 48—57),比列举 26 个字母省事得多。