C语言学习笔记 - 61.流程控制15 - 复习算法思维与程序掌握方法

一、本节学习定位

本节内容是对上一节知识的回顾与方法总结,重点不是新增复杂语法,而是明确 C 语言学习中的一个核心问题:程序不是单纯由语法堆砌而成,程序设计首先依赖算法思路,其次才是用 C 语言语法表达算法。

在 C 语言入门阶段,很多题目看起来只是简单的数字处理,例如:

  • 对三个数排序;

  • 交换两个变量的值;

  • 判断条件后执行不同语句;

  • 按一定流程修改变量。

这些题目虽然代码不长,但都需要先明确算法步骤。如果算法没有想清楚,直接动手写代码,往往很难写出正确程序。


二、程序设计的核心:算法优先

1. 程序设计的基本认识

从学习角度看,一个程序可以理解为:

复制代码
程序 = 算法 + 可执行的程序语言表达

其中,算法 是解决问题的步骤和方法,C 语言是表达算法的工具。

也就是说,写程序时不能只关注语法是否会写,还要先解决以下问题:

  1. 题目要解决什么问题;

  2. 输入数据是什么;

  3. 输出结果是什么;

  4. 中间需要经过哪些处理步骤;

  5. 每一步之间的先后顺序是什么;

  6. 是否需要判断、循环、交换、排序等操作。

如果没有清晰的解题思路,通常不应急着写代码。


三、例 1:两个变量的值互换

1. 问题描述

给定两个变量 ab,要求交换它们的值。

例如:

复制代码
交换前:a = 3, b = 5
交换后:a = 5, b = 3

2. 错误交换方式

初学者容易写出如下代码:

复制代码
a = b;
b = a;

这段代码是错误的。原因是执行第一句后,a 的原值已经丢失。

假设初始值为:

复制代码
a = 3, b = 5

执行过程如下:

步骤 语句 a 的值 b 的值 说明
初始 - 3 5 原始数据
第 1 步 a = b; 5 5 a 的原值 3 丢失
第 2 步 b = a; 5 5 b 仍然得到 5

最终结果不是交换,而是两个变量都变成了 b 的原值。


3. 正确交换方式:借助第三个变量

交换两个变量时,必须先用第三个变量保存其中一个变量的原值。

复制代码
int t;

t = a;
a = b;
b = t;

这三句代码应当熟练掌握,因为变量交换在排序、数组处理和算法题中经常使用。

4. 完整示例程序

复制代码
#include <stdio.h>

int main(void)
{
    int a;
    int b;
    int t;

    printf("请输入两个整数:");
    scanf("%d%d", &a, &b);

    printf("交换前:a = %d, b = %d\n", a, b);

    t = a;  // 第一步:保存 a 的原值
    a = b;  // 第二步:把 b 的值赋给 a
    b = t;  // 第三步:把原来 a 的值赋给 b

    printf("交换后:a = %d, b = %d\n", a, b);

    return 0;
}

5. 程序执行过程分析

假设输入:

复制代码
3 5

变量变化如下:

步骤 执行语句 a b t 说明
初始 输入后 3 5 未确定 ab 保存输入值
第 1 步 t = a; 3 5 3 t 保存 a 的原值
第 2 步 a = b; 5 5 3 b 的值赋给 a
第 3 步 b = t; 5 3 3 将原来 a 的值赋给 b

最终实现交换:

复制代码
a = 5, b = 3

四、例 2:对三个整数从小到大排序

1. 问题描述

输入任意三个整数 abc,要求按照从小到大的顺序输出。

例如:

复制代码
输入:8 3 5
输出:3 5 8

这个问题的关键不是 printfscanf,而是要先明确排序算法。

2. 基本算法思路

可以通过多次比较和交换完成排序:

  1. 如果 a > b,交换 ab,保证 a <= b

  2. 如果 a > c,交换 ac,保证 a 是三个数中较小的;

  3. 如果 b > c,交换 bc,保证 b <= c

  4. 最终得到 a <= b <= c

3. 完整示例程序

复制代码
#include <stdio.h>

int main(void)
{
    int a;
    int b;
    int c;
    int t;

    printf("请输入三个整数:");
    scanf("%d%d%d", &a, &b, &c);

    if (a > b)
    {
        t = a;
        a = b;
        b = t;
    }

    if (a > c)
    {
        t = a;
        a = c;
        c = t;
    }

    if (b > c)
    {
        t = b;
        b = c;
        c = t;
    }

    printf("从小到大排序结果:%d %d %d\n", a, b, c);

    return 0;
}

4. 程序讲解

代码片段 功能
scanf("%d%d%d", &a, &b, &c); 输入三个整数
if (a > b) 判断 ab 是否逆序
t = a; a = b; b = t; 交换两个变量的值
if (a > c) 保证 a 不大于 c
if (b > c) 保证 b 不大于 c
printf(...) 输出排序后的结果

5. 示例跟踪

输入:

复制代码
8 3 5

执行过程:

步骤 a b c 说明
初始 8 3 5 输入原始数据
判断 a > b 3 8 5 8 > 3,交换 ab
判断 a > c 3 8 5 3 > 5 不成立,不交换
判断 b > c 3 5 8 8 > 5,交换 bc

最终输出:

复制代码
3 5 8

五、看懂程序的三步法

看懂程序和掌握程序不是同一个概念。看懂程序是掌握程序的前提,但仅仅看懂还不等于能够独立写出程序。

看懂一个程序,可以按三步进行。

1. 第一步:看流程

流程是指程序中语句的执行顺序,即先执行哪一句,后执行哪一句。

例如:

复制代码
if (a > b)
{
    t = a;
    a = b;
    b = t;
}

阅读这段程序时,应先明确流程:

  1. 先判断 a > b 是否成立;

  2. 如果条件成立,执行花括号中的三条交换语句;

  3. 如果条件不成立,跳过花括号中的语句;

  4. 程序继续执行后面的代码。

如果不清楚程序流程,就无法真正理解程序。


2. 第二步:看每条语句的功能

知道执行顺序之后,还要理解每条语句的具体作用。

例如:

复制代码
t = a;
a = b;
b = t;

这三条语句不能只看作普通赋值,而要理解其功能:

语句 功能
t = a; 保存 a 的原值
a = b; b 的值赋给 a
b = t; 把原来 a 的值赋给 b

其中,=赋值运算符,表示把右边表达式的值赋给左边变量。


3. 第三步:代入数据试运行

如果仍然不理解程序,可以选择一组具体数据,逐句跟踪变量变化。

例如对三个数排序程序,可以代入:

复制代码
a = 8, b = 3, c = 5

然后逐句分析每个 if 是否成立,以及变量值如何变化。通过代入数据,可以把抽象代码转化为具体过程,更容易发现程序逻辑。


六、看懂程序与掌握程序的区别

对比项 看懂程序 掌握程序
核心目标 明白程序为什么这样写 能够独立写出并调试程序
主要方式 阅读、分析、代入数据 修改、敲写、调试、复现
判断标准 能解释每条语句的作用 不看答案也能写出正确代码
常见问题 以为看懂就会写 实际敲代码时仍然出错
正确做法 先理解流程和语句功能 再通过多次练习形成熟练度

结论:看懂只是第一步,真正掌握必须经过实际敲代码和调试。


七、掌握一个小算法程序的六步法

对于涉及算法的小程序,建议按以下步骤学习。

1. 尝试独立解决

拿到题目后,先自己分析:

  • 输入是什么;

  • 输出是什么;

  • 是否需要比较;

  • 是否需要交换;

  • 是否需要循环;

  • 是否需要辅助变量;

  • 程序流程如何安排。

如果能够独立写出程序,说明算法思路比较清晰。


2. 无法解决时查看答案

如果程序涉及算法,而自己短时间内没有思路,不必长时间死磕。此时可以查看参考答案。

重点不是抄答案,而是理解:

  1. 答案为什么这样设计;

  2. 每个变量起什么作用;

  3. 每个判断条件为什么这样写;

  4. 每次交换、赋值、循环的目的是什么;

  5. 代码执行后变量如何变化。


3. 把答案看懂

看答案时应按"三步法"分析:

  1. 看程序流程;

  2. 看每条语句的功能;

  3. 代入具体数据试运行。

例如两数交换程序,不仅要记住:

复制代码
t = a;
a = b;
b = t;

还要明白为什么必须先执行 t = a;


4. 尝试修改程序并观察结果

看懂答案后,不应马上闭着眼睛默写,而应尝试修改代码,观察输出变化。

例如可以修改排序程序中的条件:

复制代码
if (a > b)

改为:

复制代码
if (a >= b)

然后观察当两个数相等时,程序是否仍然正确。

也可以尝试去掉花括号:

复制代码
if (a > b)
    t = a;
    a = b;
    b = t;

这段代码看起来相似,但实际上只有 t = a;if 控制,后两句会无条件执行,因此逻辑会出错。


5. 照着答案敲写并调试

理解答案后,要亲自敲一遍代码。

实际敲代码时可能出现:

  • 拼写错误;

  • 分号遗漏;

  • 花括号不匹配;

  • scanf 中少写 &

  • 条件判断写错;

  • 变量名写错;

  • 输出格式不匹配。

调试错误是学习 C 语言不可缺少的过程。程序能运行,不代表过程没有意义;程序出错时,正是理解语法细节和程序流程的机会。


6. 不看答案独立复现

最后一步是不看答案,独立把程序写出来。

如果当天能写出,说明已经初步掌握;但还需要隔几天再次练习。第一次复现通常最困难,第二次会明显轻松,后续通过复习逐步形成稳定记忆。


八、极少数无法理解的程序如何处理

如果某个程序经过分析、代入数据、修改实验和调试后,仍然无法完全理解,可以先记住其基本结构,后续学习更多语法和算法后再回头理解。

但这种情况不应太多。对于入门阶段的大多数程序,只要按以下顺序处理,通常都可以理解:

  1. 理清流程;

  2. 理解语句功能;

  3. 代入数据;

  4. 修改验证;

  5. 敲写调试;

  6. 独立复现。


九、在 VSCode 中练习本节代码的建议

使用 VSCode 配置好 C/C++ 环境后,可以按以下流程练习本节程序。

1. 新建 C 源文件

建议文件名:

复制代码
swap.c

或:

复制代码
sort_three_numbers.c

2. 编写代码

将示例代码复制到 .c 文件中,注意文件扩展名必须是 .c

3. 使用终端编译

Windows 下,如果使用 GCC,可在 VSCode 终端中执行:

复制代码
gcc swap.c -o swap.exe

或者:

复制代码
gcc sort_three_numbers.c -o sort_three_numbers.exe

4. 运行程序

复制代码
./swap.exe

或者:

复制代码
./sort_three_numbers.exe

5. 修改程序并重新运行

建议尝试:

  1. 修改输入数据;

  2. 修改 if 条件;

  3. 故意去掉花括号,观察逻辑错误;

  4. 故意漏写 &,观察 scanf 的错误;

  5. 调换交换语句顺序,观察变量值变化。

这种练习方式可以帮助理解"看懂"和"掌握"的区别。


十、本节要点总结

  1. C 语言程序设计不能只学语法,更要先有算法思路。

  2. 对三个数排序、两个数交换等题目,核心都在于先明确处理步骤。

  3. 两个变量交换必须借助第三个变量,典型写法是:

    t = a;
    a = b;
    b = t;

  4. 看懂程序可分为三步:看流程、看语句功能、代入数据试运行

  5. 看懂程序不等于掌握程序,掌握程序还需要修改、敲写、调试和独立复现。

  6. 学习小算法程序时,不必长时间盲目死磕;如果没有思路,应通过可靠答案学习算法。

  7. 调试错误不是浪费时间,而是加深理解的重要环节。

  8. 程序需要隔几天重复练习,才能真正形成稳定掌握。


参考出处

  1. 《C程序设计(第五版)》谭浩强,第 3 章"最简单的 C 程序设计------顺序程序设计"

  2. 《C程序设计(第五版)》谭浩强,第 4 章"选择结构程序设计"

  3. 郝斌《C语言自学入门教程》对应内容:算法意识、两数交换、三数排序、程序阅读方法与程序掌握方法。