【C语言-分支结构】啃透C语言的分支结构,这些搞明白了代码才有灵魂

开发技术 作者: 精灵星空 SKY315.COM 更新于: 浏览: 229
码字发文不易,转载请注明出处【精灵星空 SKY315.COM】

下面我把C语言分支结构的所有知识点从头到尾过一遍,配上几个经典例子,看完你要是还迷糊,那就再看一遍。

C语言在线编程环境:https://sky315.com:8080/c/。

一、分支结构就两种,搞明白区别就赢了八成

C语言的分支结构其实就两大类:if语句和switch语句。它们都能实现“根据条件走不同的路”,但适用的场景不一样。

if语句——条件判断的万能选手

if语句有四种形态,从简单到复杂:

  • 单分支:if (条件) { 要做的事 }——条件成立就干,不成立就拉倒。

  • 双分支:if (条件) { 真的时候干这个 } else { 假的时候干那个 }——两条路,必选一条。

  • 多分支:if (条件1) { ... } else if (条件2) { ... } else if (条件3) { ... } else { ... }——多个条件挨个试,谁先成立就进谁。

  • 嵌套if:if里面再套if,层层递进。

if语句的执行逻辑就一句话:条件为真(非0)就进,条件为假(0)就跳过。C语言里没有专门的布尔类型(C99才有_Bool),条件判断全靠数值——0就是假,非0就是真。这点跟其他语言不一样,得记住。

switch语句——多选一的精准武器

        switch (表达式) {
            case 常量1:
                语句块1;
                break;
            case 常量2:
                语句块2;
                break;
            default:
                默认语句块;
                break;
        }

switch适合一个表达式的值等于哪个常量就执行哪个分支。它的特点是:表达式的值必须是整型或字符型,不能是浮点数,也不能是字符串。每个case后面跟的是常量,不能是变量。

switch有个最要命的特性:穿透。 如果一个case后面没有break,执行完这个case会继续往下执行下一个case,直到遇到break或者switch结束。这个特性有时候是坑,有时候反倒是你要的效果。

二、if-else配对问题,这个坑不知道要吃大亏

先看一段代码,你猜else跟哪个if配对?

        if (a > 0)
            if (b > 0)
                printf("a和b都大于0\n");
        else
            printf("a不大于0\n");

很多人看缩进以为else跟第一个if配对,但C语言不看缩进,它看的是语法规则。规则是:else总是和它上面最近的那个未配对的if配对。所以这里的else实际上是跟if (b > 0)配对,不是跟if (a > 0)配对。

想让它跟第一个if配对?加花括号:

        if (a > 0) {
            if (b > 0)
                printf("a和b都大于0\n");
        } else {
            printf("a不大于0\n");
        }

花括号把内层if框起来了,else就够不着它了,只能老老实实跟外层if配对。写if语句的时候,该加花括号就加,别偷懒,否则这种配对问题会让你调Bug调到怀疑人生。

三、典型例题挨个讲,每个都比光看语法管用

下面上几个经典例子,你挨个看懂,分支结构的基本功就差不多了。

例1:成绩等级划分——最基本的if-else if多分支

输入一个百分制成绩,输出对应的等级:90以上是A,80-89是B,70-79是C,60-69是D,60以下是E。

        int score;
        scanf("%d", &score);

        if (score >= 90) {
            printf("A\n");
        } else if (score >= 80) {
            printf("B\n");
        } else if (score >= 70) {
            printf("C\n");
        } else if (score >= 60) {
            printf("D\n");
        } else {
            printf("E\n");
        }

关键是条件的顺序。你可能觉得写成if (score >= 60 && score < 70)更严谨,其实没必要——因为if-else if是从上到下匹配,一旦匹配成功,后面的else if就不再判断了。score=85的时候,第一个条件90不满足,第二个80满足,进去之后后面的70、60根本不会执行。

如果你把顺序反过来,先判断if (score >= 60),那85分就会被打成D,因为60这个条件先成立了。条件顺序决定了结果,写的时候脑子里得过一遍执行流程。

例2:判断闰年——条件组合怎么玩

闰年的规则:能被4整除但不能被100整除,或者能被400整除。

        int year;
        scanf("%d", &year);

        if ((year % 4 == 0 && year % 100 != 0) || (year % 400 == 0)) {
            printf("%d是闰年\n", year);
        } else {
            printf("%d不是闰年\n", year);
        }

这题考的是逻辑运算符的优先级和组合。&&优先级比||高,所以上面那个条件不加括号其实也能正确解析,但加了括号让代码更清晰。写分支条件的时候,括号不要舍不得用,多写几个括号让优先级一目了然,比让读你代码的人猜来猜去强多了。

例3:分段函数——多个if的写法区别

数学上分段函数很常见,比如:

  • x < 0 时,y = -1

  • x = 0 时,y = 0

  • x > 0 时,y = 1

这个用if-else if写:

        if (x < 0) {
            y = -1;
        } else if (x == 0) {
            y = 0;
        } else {
            y = 1;
        }

注意这里不能写成三个独立的if:

        // 错误写法
        if (x < 0) y = -1;
        if (x == 0) y = 0;
        if (x > 0) y = 1;

三个独立if的话,每个条件都会判断一遍,虽然结果没错(因为三个条件互斥,不会同时成立),但效率不如if-else if。更关键的是,如果条件不互斥,三个独立if可能会执行多个分支,而if-else if只会执行第一个匹配的。 这两种写法有本质区别。

例4:简单计算器——switch的经典应用

输入两个数和运算符(+、-、*、/),输出计算结果。

        float a, b;
        char op;
        scanf("%f %c %f", &a, &op, &b);

        switch (op) {
            case '+':
                printf("%.2f\n", a + b);
                break;
            case '-':
                printf("%.2f\n", a - b);
                break;
            case '*':
                printf("%.2f\n", a * b);
                break;
            case '/':
                if (b != 0) {
                    printf("%.2f\n", a / b);
                } else {
                    printf("除数不能为0\n");
                }
                break;
            default:
                printf("不支持的运算符\n");
                break;
        }

这个例子把switch用得很标准。每个case后面都有break,防止穿透。default处理了“用户瞎输入”的情况。除法这里还嵌套了一个if判断,处理除零的异常——分支结构嵌套是家常便饭,不要觉得嵌套就复杂了,一层一层分析就行。

顺便说一句,不加break的switch有时候是有用的,比如你想让多个case执行同样的操作:

        switch (grade) {
            case 'A':
            case 'B':
                printf("优秀或良好\n");
                break;
            case 'C':
                printf("及格\n");
                break;
            default:
                printf("不及格\n");
                break;
        }

输入'A'或者'B'都会打印同样的内容,这就是利用穿透达到“或”的效果。但这种写法新手容易懵,等熟练了再用,不熟练就老老实实每个case写break。

例5:三个数排序——if嵌套帮你理清逻辑

输入三个整数,按从小到大的顺序输出。

        int a, b, c, temp;
        scanf("%d%d%d", &a, &b, &c);

        if (a > b) {
            temp = a; a = b; b = temp;
        }
        if (a > c) {
            temp = a; a = c; c = temp;
        }
        if (b > c) {
            temp = b; b = c; c = temp;
        }
        printf("%d %d %d\n", a, b, c);

这个写法很巧妙。第一个if保证a <= b,第二个if保证a <= c,所以a就成了最小值。前两个if执行完,a确定是最小的,剩下b和c谁大谁小再比一下。三个if依次执行,逻辑层层推进。这种题看着简单,但能帮你理解分支是怎么通过顺序执行解决问题的。

例6:判断三角形类型——条件的排列组合

输入三条边长,判断能不能构成三角形,如果能,再判断是等边、等腰还是一般三角形。

        int a, b, c;
        scanf("%d%d%d", &a, &b, &c);

        // 先判断能不能构成三角形
        if (a + b > c && a + c > b && b + c > a) {
            // 能构成三角形,再判断类型
            if (a == b && b == c) {
                printf("等边三角形\n");
            } else if (a == b || a == c || b == c) {
                printf("等腰三角形\n");
            } else {
                printf("一般三角形\n");
            }
        } else {
            printf("不能构成三角形\n");
        }

外层判断能不能构成,内层判断是什么类型,这就是分支嵌套的典型场景。逻辑层次要清晰,先大后小,先判断必要条件,再判断充分条件。

四、几个常见坑,提前踩过就长记性了

坑1:赋值号当等号用

        if (a = 5) {
            printf("a等于5\n");
        }

这个语法是对的,不会报错,但意思全变了。a = 5是赋值,把5赋给a,整个表达式的值就是5,5是非0为真,所以这个if永远成立。你本来想判断a == 5,结果写成赋值,Bug就这么埋下了。很多老手都栽过这个跟头,有个小技巧:把常量写在左边,写成if (5 == a),万一你少写一个等号变成if (5 = a),编译器直接报错,因为常量不能赋值。

坑2:else悬空问题,前面讲过了,不啰嗦。

坑3:switch里漏了break

这个太常见了,你写着写着就忘了,结果程序跑出来结果莫名其妙。每次写完switch,从头检查一遍是不是每个case后面都有break(除非你故意要穿透)。

坑4:浮点数直接比较相等

        float x = 0.1 + 0.2;
        if (x == 0.3) {
            // 你以为会进来,其实大概率进不来
        }

浮点数存储有误差,0.1+0.2不一定等于0.3。分支条件里尽量避免用浮点数的==或!=比较,改成判断差值是否小于一个很小的数,比如if (fabs(x - 0.3) < 1e-6)。

坑5:if-else if和多个独立if的混淆

这个前面讲过了,记清楚:多个独立if可能执行多个分支,if-else if最多只执行一个分支。

五、总结几句

分支结构说到底就是让程序有了“判断能力”,能根据不同情况做不同的事。if语句灵活万能,适合范围判断、复杂条件;switch语句干脆利落,适合单值匹配。

练到什么程度算过关? 拿到一个需求,你能判断出来该用if还是switch,能写对条件表达式,能理清嵌套层次,能把边界条件想全了——这就算分支结构真正掌握了。

还是那句话,光看没用,打开编译器自己敲。每个例子自己写一遍,改改条件换换数据跑一跑,出几次错修几次,这些东西就长在你身上了。