C语言第四讲——条件语句

简介: C语言第四讲——条件语句

流程图里面有哪些结构

在流程图中,常见的结构包括以下几种:

  1. 「起始/结束符号」(Start/End Symbol):表示流程的开始和结束。通常用椭圆形表示开始和结束。
  2. 「处理符号」(Process Symbol):表示执行某个操作或处理某些数据的步骤。通常用矩形表示。
  3. 「判断符号」(Decision Symbol):表示进行条件判断的步骤。根据判断条件的真假,流程会分支到不同的路径。通常用菱形表示。
  4. 「连接线」(Connector):连接各个符号,表示流程的顺序和逻辑关系。
  5. 「输入/输出符号」(Input/Output Symbol):表示输入或输出数据的步骤。输入通常用平行四边形表示,输出通常用椭圆形表示。
  6. 「循环符号」(Loop Symbol):表示循环结构,用于表示某个步骤需要重复执行的情况。通常用弧线表示。

而在我们的C语言中,每一段(或函数)程序都可以用一个流程图来表示。

起始结束符号其实就是我们的main函数里面,我们之前讲了句法规则里面,就包含了处理语句,输入输出语句和顺序执行语句。

目前还剩下条件判断语句和循环语句,那么在这一讲,我们将学习条件判断语句的写法。

IF语句

在C语言中,if语句是一种条件判断语句,用于根据指定条件执行不同的代码块。if语句的基本语法如下:

if (condition) {
    // 如果条件为真(非零),执行这里的代码
} else {
    // 如果条件为假(零),执行这里的代码(可选部分)
}
  • condition 是一个表达式,用于进行条件判断。如果condition的值为非零(即真),if语句后面的代码块将被执行;如果condition的值为零(即假),else语句后面的代码块(如果存在)将被执行。

例如,下面的代码演示了一个简单的if语句:

#include <stdio.h>

int main() {
    int num = 10;

    if (num > 0) {
        printf("The number is positive.\n");
    } else {
        printf("The number is non-positive.\n");
    }

    return 0;
}

在这个例子中,如果num的值大于0,程序将输出"The number is positive.";否则,它将输出"The number is non-positive."。在if语句中,可以使用各种比较运算符(如><>=<===!=)来构建条件表达式。

需要注意的是,else部分是可选的,可以不在if语句中包含else。如果省略else,当条件为假时,程序将跳过if语句后面的代码,继续执行if语句之后的代码。

多个if语句并排

#include <stdio.h>

int main() {
    int num = 10;

    if (num > 0) {
        printf("The number is positive.\n");
    }

    if (num % 2 == 0) {
        printf("The number is even.\n");
    }

    return 0;
}

嵌套的if语句

#include <stdio.h>

int main() {
    int num = 10;

    if (num > 0) {
        printf("The number is positive.\n");

        if (num % 2 == 0) {
            printf("The number is positive and even.\n");
        } else {
            printf("The number is positive but odd.\n");
        }
    } else {
        printf("The number is non-positive.\n");
    }

    return 0;
}

if-else if-else结构

#include <stdio.h>

int main() {
    int num = 10;

    if (num > 0) {
        printf("The number is positive.\n");
    } else if (num < 0) {
        printf("The number is negative.\n");
    } else {
        printf("The number is zero.\n");
    }

    return 0;
}

if-else if-else结构中,程序首先检查第一个条件(num > 0),如果为真,执行对应的代码块,并且跳过后面的else ifelse部分。如果第一个条件为假,程序继续检查下一个条件(num < 0),如果为真,执行相应的代码块,以此类推。如果所有条件都为假,执行else部分的代码块。

这种结构可以用于处理多个不同情况下的条件判断,使代码更加清晰和易读。

编写if语句的注意事项

在编写if语句时,有一些注意事项可以帮助确保代码的正确性和可读性:

  1. 「条件表达式的正确性:」 确保if语句中的条件表达式(放在圆括号内的部分)是一个可以求值的表达式,并且能够得到truefalse结果。比如,不要把赋值语句(如num = 10)误写成相等比较(如num == 10)。
  2. 「花括号的使用:」 尽量始终使用花括号({})来明确if语句的代码块,即使if语句只包含一条语句。这样做可以避免因缩进错误引发的逻辑错误。
// 推荐的写法
if (condition) {
    // code to be executed
}

// 避免的写法(不推荐)
if (condition)
    // code to be executed (only this line)

3.「条件表达式的括号:」 虽然在C语言中,条件表达式的括号是可选的,但为了可读性和代码的明确性,建议在条件表达式外侧加上括号。

// 推荐的写法
if ((x > 0) && (y < 10)) {
    // code to be executed
}

// 避免的写法(不推荐)
if (x > 0 && y < 10) {
    // code to be executed
}

4.「逻辑运算符的正确使用:」 当使用逻辑运算符(如&&||)连接多个条件时,确保逻辑表达式的顺序和括号的使用符合预期,以避免逻辑错误。

5.「处理多个条件的顺序:」 当有多个if-else if-else条件时,确保条件的顺序是按照优先级排列的,以避免条件判断失效或者多个条件同时满足时执行了错误的分支。

6.「注释:」 如果if语句的逻辑比较复杂,可以使用注释来解释条件的含义和预期行为,增加代码的可读性。

7.「避免嵌套过深:」 尽量避免嵌套过多的if语句,深度过深的嵌套会降低代码的可读性和可维护性。如果嵌套过多,可以考虑使用函数进行逻辑的封装。

多路判断Switch语句

switch语句是C语言中用于多路判断的一种控制语句。它可以根据一个表达式的值,从多个选项中选择一个分支执行。switch语句的基本语法如下:


switch (expression) {
    case constant1:
        // code to be executed if expression equals constant1
        break;
    case constant2:
        // code to be executed if expression equals constant2
        break;
    // more cases can be added as needed
    default:
        // code to be executed if expression doesn't match any constant
}
  • expression 是一个整数表达式(可以是变量、常量、或者表达式),其值将与case后面的常量进行比较。
  • case constant1:case constant2: 是分支标签,表示当expression的值等于constant1constant2时,执行相应的代码块。
  • break; 语句用于结束switch块,防止程序继续执行后面的分支。如果没有break;语句,程序将会继续执行下一个case分支,直到遇到break;switch语句结束。
  • default: 是可选的,用于处理expression不匹配任何case时的情况。它类似于if-else语句中的else分支。

下面是一个使用switch语句的示例:

#include <stdio.h>

int main() {
    int day = 3;

    switch (day) {
        case 1:
            printf("Monday\n");
            break;
        case 2:
            printf("Tuesday\n");
            break;
        case 3:
            printf("Wednesday\n");
            break;
        case 4:
            printf("Thursday\n");
            break;
        case 5:
            printf("Friday\n");
            break;
        default:
            printf("Weekend\n");
    }

    return 0;
}

在这个例子中,day的值为3,因此switch语句匹配到case 3:,输出"Wednesday"。如果day的值不在1到5之间,将匹配到default分支,输出"Weekend"。

case穿透

在C语言中,switch语句中的"case穿透"(case fall-through)可能导致程序逻辑错误或不易维护的代码。为了避免潜在的问题,以下是关于case穿透的一些注意事项:

  1. 「明确使用break语句:」 在每个case标签的最后,通常应该使用break语句,以确保在匹配到一个case后执行相应的语句后立即跳出switch语句。如果不使用break,程序会继续执行下一个case标签的语句,直到遇到breakreturngoto、函数结束或者大括号结束(即switch语句的结束)。
switch (day) {
    case 1:
        printf("Monday\n");
        break; // 使用break结束当前的case块
    case 2:
        printf("Tuesday\n");
        break;
    // ...
}

2.「避免不必要的穿透:」 在设计switch语句时,应该尽量避免不必要的case穿透。如果两个case标签下的代码是相似的,可以将共享的代码提取为一个函数或者使用其他方式避免重复。

switch (option) {
    case 1:
    case 2:
        handleOption1And2(); // 共享的处理代码可以提取为一个函数
        break;
    case 3:
        handleOption3();
        break;
    // ...
}

3.「在default标签前使用break:」 如果default标签位于switch语句的中间,确保在default标签前面加上break,以避免不必要的穿透。因为default通常是switch语句中的最后一个分支,如果不加break,可能会导致与预期不符的结果。

switch (day) {
    case 1:
        printf("Monday\n");
        break;
    default:
        printf("Other day\n");
        break; // 在default标签前使用break
}

4.「注释case穿透的意图:」 如果有意使用case穿透,应该在代码中添加注释,明确指出这种做法的意图,以便其他人阅读代码时能够理解穿透的原因。

switch (grade) {
    case 'A':
    case 'B':
        printf("Excellent\n");
        // Intentional fall-through for 'A' and 'B' grades
        break;
    // ...
}

通过以上的注意事项,可以更加安全和清晰地使用switch语句,避免因为case穿透而引发的错误和混乱。

Case 穿透的实现原理

switch语句中的case穿透并不是一个bug,而是C语言中的一种设计特性。C语言的switch语句是由编译器实现的,它按照标准的语法规则进行工作。

switch语句的实现中,编译器通常会将case标签的值转换为跳转表(jump table)或者一系列的条件分支(conditional branches)。跳转表是一个数组,其中每个元素对应一个case标签的值,而数组的内容是对应case标签的代码块的入口地址。当switch语句的表达式的值被计算后,编译器会使用该值来索引跳转表,从而直接跳转到相应的case标签的代码块,这样可以实现高效的分支选择。

case穿透是因为在这个跳转表或条件分支中,并没有包含break语句。如果在一个case标签下没有break,程序会继续执行下一个case标签的代码块,直到遇到breakreturngoto、函数结束或者大括号结束(即switch语句的结束)。这种行为是C语言的标准规定,允许程序员在需要的时候使用case穿透。

也就是说,某个case对应的值会存储索引这个值以下的所有程序代码,并没有按照case进行严格隔开,case语句本身只用于第一次构建switch数组,在接下来的执行过程中,并不会再次判断,所以要求我们在每个case后面必须带上自己的break语句,不然就会出现case 穿透。

目录
相关文章
|
3月前
|
程序员 C语言
C语言中的条件语句技术详解
C语言中的条件语句技术详解
|
3月前
|
C语言
C语言条件语句
C语言条件语句
30 0
|
3月前
|
C语言
C语言循环及条件语句
C语言循环及条件语句
29 0
|
3月前
|
存储 程序员 编译器
【新手解答5】深入探索 C 语言:宏中的文本、标识符和字符串 + 递归运算、条件语句、循环 + `switch-case` 与多项条件和枚举的差别
【新手解答5】深入探索 C 语言:宏中的文本、标识符和字符串 + 递归运算、条件语句、循环 + `switch-case` 与多项条件和枚举的差别
69 0
|
C语言
C语言循环及条件语句
C语言循环及条件语句
94 0
|
C语言
C语言之if条件语句
C语言的if,if-else if,if-else if-else语句
569 0
C语言之if条件语句
|
6天前
|
存储 C语言
【C语言函数】static和extern关键字修饰
【C语言函数】static和extern关键字修饰
|
6天前
|
C语言 C++
|
15天前
|
机器学习/深度学习 C语言
九/十:《初学C语言》— 扫雷游戏实现和函数递归基础
【8月更文挑战第5天】本篇文章用C语言采用多文件编写实现了一个基础的扫雷游戏(附源码),并讲解了关于函数递归的基础概念及其相对应的习题练习(附源码)
29 1
九/十:《初学C语言》— 扫雷游戏实现和函数递归基础
|
17天前
|
存储 编译器 程序员
八:《初学C语言》— 函数的基本概念
【8月更文挑战第3天】本篇文章详细讲解了库函数与自定义函数的区别、函数的嵌套调用及链式访问、函数的声明和定义、static和extern等基础知识
17 1
八:《初学C语言》— 函数的基本概念