一、选择结构 & 条件判断

1. if

if(值为真或假的表达式){语句}
else if(){...}
else {...}

2. switch

switch (整型&字符型表达式) {
    case 常量1:
        语句1;
        break; // 跳出 switch 结构
    case 常量2:
        语句2;
        break;
    case 常量3:
        语句3;
        // 如果这里不写 break,程序会继续"穿透"向下执行 case 4
    case 常量4:
        语句4;
        break;
    default:
        语句N; // 当以上 case 都不匹配时执行(可选)
        break;
}

P.S. break 的作用是执行完当前分支后立即跳出 switch 结构,因此可利用贯穿特性

3. 条件编译

编译:把 C 语言翻译为二进制指令


宏:编译前的"查找并替换"机制,通过 #define 定义

① 无参数

用于给某个常量或固定文本起一个有意义的名字,提高代码的可读性和可维护性。

#define PI 3.1415926
#define MAX_SIZE 100

int main() {
    double area = PI * 5 * 5; // 在编译前,PI 会被直接替换为 3.1415926
    int arr[MAX_SIZE];        // MAX_SIZE 被直接替换为 100
    return 0;
}

② 有参数

外观看起来像函数,但本质上依然是直接替换代码,不会产生函数调用的开销(如压栈、跳转等)。

#define SQUARE(x) ((x) * (x))

int main() {
    int result = SQUARE(5); // 预处理后展开为:((5) * (5))
    return 0;
}

作用:在程序编译之前,根据指定的条件来决定"哪些代码需要被编译进最终的可执行文件,哪些代码需要被直接忽略",可以减小程序体积并提升运行效率。


#ifdef / #ifndef:根据宏是否被定义来选择"单选开关"

#include <stdio.h>

#define DEBUG // 定义一个名字叫 DEBUG 的"开关"

int main() {
    // 2. 预处理器在这里做判断:DEBUG 被定义了吗?
    #ifdef DEBUG
    printf("【调试模式】当前变量 x 的值为 100\n"); // 如果贴了 DEBUG 标签,就编译下面这行代码
    #else
    printf("【发布模式】程序正在运行...\n"); // 如果没有贴 DEBUG 标签,就编译下面这行代码
    #endif // 这个判断区域到此结束

    return 0;
}

P.S. 用途:节省手动去删掉大项目开发阶段中上百个 printf 打印变量调试程序的时间,只需要把最顶上的 #define DEBUG 这一行删掉或注释掉,全套调试代码就会瞬间全部"消失"。


#if / #elif / #else:根据表达式的常数值选择"多选列表"

e.g. 通过修改数字,来决定让代码去适应哪一个操作系统(Windows、Linux 还是 macOS)

// 1. 设置系统类型:1 代表 Win,2 代表 Linux,3 代表 Mac
#define SYSTEM_TYPE 2

// 2. 预处理器根据 SYSTEM_TYPE 的数值进行多条件判断
#if SYSTEM_TYPE == 1
    // 如果是 1,只保留 Windows 专用的头文件
    #include <windows.h>

#elif SYSTEM_TYPE == 2
    // 如果是 2,只保留 Linux 专用的头文件
    #include <unistd.h>

#else
    // 如果都不是(比如 3),保留其他系统的代码
    // 这里可以写 macOS 或通用代码

#endif // 结束判断

P.S. 不同操作系统,自带的函数库(头文件)不同。


防止头文件重复包含的标准写法(Header Guard)

P.S. 避免重复定义的错误

#pragma once // 告诉编译器:这个文件不管被调用几次,你只许看 1 次!

// 下面正常写你的代码...
typedef struct {
    int id;
} Student;

二、循环结构

1. while

先判断,后执行。用于不确定具体要循环多少次,只知道"只要条件满足就一直做"的场景。

while (条件表达式) {
    // 循环体代码
}

2. do - while 循环

直到型循环:先无条件执行一次循环体,后判断。用于无论如何都必须至少执行一次的场景(比如菜单显示、用户输入校验)。

do {
    // 循环体代码
} while (条件表达式); // 注意:末尾必须有分号 ;

3. for 循环

已知循环次数。

for (初始化表达式; 条件表达式; 循环后更新表达式) {
    // 循环体代码
}

4. 循环控制关键字:break 与 continue

  • break(彻底终止)

    • 效果:立即强行跳出整个循环,不再执行后续的任何循环迭代。
    • 示例:寻找某个数字,找到后立刻用 break 结束搜索。
  • continue(跳过本次)

    • 效果:结束本次循环的执行,但不退出循环结构。
    • 示例:打印 1~10 中的奇数,遇到偶数时用 continue 跳过打印。