C语言:语句——选择结构与循环结构

C语言:语句——选择结构与循环结构

一、选择结构

选择结构的核心是“根据条件真假执行不同代码”,C语言提供if系列和switch-case两种实现方式,适用于不同场景。

1.1 if系列语句:灵活的条件判断

if系列语句通过布尔表达式(真/假)控制代码执行,支持单分支、双分支、多分支和嵌套,灵活性极高。

(1)核心语法与逻辑拆解
语句类型语法格式核心逻辑
单分支ifif (条件) { 代码块; }条件为真则执行代码块,假则跳过
双分支if-elseif (条件) { 代码块1; } else { 代码块2; }条件为真执行代码块1,假则执行代码块2(二选一)
多分支if-else ifif (条件1) { ... } else if (条件2) { ... } else { ... }依次判断条件,满足第一个条件即执行对应代码块,后续条件不再判断(互斥)
嵌套ifif (外层条件) { if (内层条件) { ... } else { ... } }外层条件满足后,再判断内层条件(适合多维度判断)
(2)实例
① 单分支与双分支(基础场景)
    int score;
    printf("请输入成绩: ");
    scanf("%d", &score);
    // 单分支if:仅判断“及格”情况
    if (score >= 60 && score <= 100) {
        printf("恭喜,及格了!\n");    }
    // 双分支if-else:及格/不及格二选一
    if (score >= 90 && score <= 100) {
        printf("优秀!\n");
    } else {
    printf("继续努力!\n");    }

关键细节

  • 条件表达式必须是“布尔值”(C语言中0为假,非0为真);
  • 若代码块只有1行,{}可省略,但建议始终加上(避免后续扩展代码出错);
  • 多条件判断需用&&(逻辑与)、||(逻辑或)连接,注意优先级(&&高于||)。
② 多分支if-else if(范围判断)

适合“连续区间判断”(如成绩等级、年龄分段):

#include <stdio.h>

int main() {
    int score;
    printf("请输入成绩(0-100): ");
    scanf("%d", &score);
    
    // 多分支:互斥条件,从高到低判断
    if (score >= 90 && score <= 100) {
        printf("成绩等级: A(优秀)\n");
    } else if (score >= 80) { // 隐含条件:score < 90
        printf("成绩等级: B(良好)\n");
    } else if (score >= 70) { // 隐含条件:score < 80
        printf("成绩等级: C(中等)\n");
    } else if (score >= 60) { // 隐含条件:score < 70
        printf("成绩等级: D(及格)\n");
    } else if (score >= 0) { // 处理0-59的无效成绩
        printf("成绩等级: E(不及格)\n");
    } else {
        printf("输入无效!成绩应在0-100之间\n");
    }
    
    return 0;
}

逻辑优化
多分支判断时,建议按“条件范围从大到小/从小到大”排序,避免条件重叠;最后加else处理所有异常情况(如输入负数),增强程序健壮性。

③ 嵌套if(多维度判断)

适合“先满足外层条件,再判断内层条件”(如“成年+性别”判断):

int main() {
    int age;
    char gender;
    printf("请输入年龄: ");
    scanf("%d", &age);
    printf("请输入性别(M/F): ");
    scanf(" %c", &gender); // 空格用于吸收前一个输入的回车符
    // 外层判断“是否成年”,内层判断“性别”
    if (age >= 18) {
        if (gender == 'M' || gender == 'm') {
            printf("成年男性\n");
        } else if (gender == 'F' || gender == 'f') {
            printf("成年女性\n");
        } else {
            printf("性别输入错误\n");
        }
    } else {
        printf("未成年人\n");
    }
    

1.2 switch-case语句:高效的多值匹配

switch-case适用于“变量与多个固定值匹配”的场景(如菜单选择、月份判断),执行效率高于多分支if-else if,语法更简洁。

(1)核心语法与逻辑原理
switch (变量) {
    case1: 代码块1; break;
    case2: 代码块2; break;
    ...
    default: 默认代码块; break;
}

逻辑拆解

  1. 变量与case后的值进行“全等匹配”(仅支持整数/字符/枚举类型,不支持浮点数、字符串);
  2. 匹配成功后,从该case开始顺序执行,直到遇到breakswitch结束;
  3. 若所有case都不匹配,执行default(可选,但建议加上,处理异常情况)。
(2)关键特性:穿透性(灵活运用+避坑)

switch-case的“穿透性”是核心特性——若case后没有break,会继续执行下一个case的代码

① 穿透性

例如“按月份判断季节”:12、1、2月都是冬季,无需重复写代码:

    int month;
    printf("请输入月份(1-12): ");
    scanf("%d", &month);
        switch (month) {
        case 12:
        case 1:  // 穿透:case12匹配后,会执行case1、case2的代码
        case 2:
            printf("%d月是冬季\n", month);
            break; // 终止穿透
        case 3:
        case 4:
        case 5:
            printf("%d月是春季\n", month);
            break;
        case 6:
        case 7:
        case 8:
            printf("%d月是夏季\n", month);
            break;
        case 9:
        case 10:
        case 11:
            printf("%d月是秋季\n", month);
            break;
        default:
            printf("无效的月份!\n");
            break;
    }

② 避免无意穿透

若忘记写break,会导致“多case执行”的bug:

// 错误示例:case1后无break
switch (choice) {
    case 1:
        printf("查询余额\n"); // 执行后会继续执行case2的代码
    case 2:
        printf("存款\n");
        break;
}
// 若choice=1,会输出:查询余额 存款(不符合预期)
(3)字符类型的switch-case(大小写兼容)

通过case 'A': case 'a':的方式,可兼容大小写输入,无需额外判断:


    char grade;
    printf("请输入成绩等级(A-E): ");
    scanf("%c", &grade);
    
    switch (grade) {
        case 'A':
        case 'a':
            printf("优秀!\n");
            break;
        case 'B':
        case 'b':
            printf("良好!\n");
            break;
        case 'C':
        case 'c':
            printf("中等!\n");
            break;
        case 'D':
        case 'd':
            printf("及格!\n");
            break;
        case 'E':
        case 'e':
            printf("不及格!\n");
            break;
        default:
            printf("无效的等级!\n");
            break;
    }

1.3 if vs switch-case

对比维度if系列语句switch-case语句
匹配类型支持范围判断(如score >= 60)、复杂条件仅支持固定值匹配(如choice=1
灵活性高(可嵌套、多条件组合)低(仅固定值匹配)
执行效率多分支时较低(依次判断)较高(直接匹配case,无顺序依赖)
代码简洁性多分支时冗长多值匹配时简洁(避免重复条件判断)
适用场景成绩等级、年龄分段等范围判断菜单选择、月份、运算符等固定值匹配

二、循环结构

循环结构的核心是“满足条件时重复执行代码块”,C提供forwhiledo-while三种循环,以及breakcontinuegoto三种循环控制语句。

2.1 三种循环的核心差异与用法

三种循环的本质都是“条件判断+重复执行”,但语法结构和适用场景不同,核心差异在于“初始化、条件判断、增量更新”的位置。

(1)for

for循环将“初始化、条件判断、增量更新”集中在一行,结构清晰,适合“已知循环次数”的场景(如遍历数组、固定次数迭代)。

核心语法:
for (初始化表达式; 条件表达式; 增量表达式) {
    循环体;
}

执行流程

  1. 执行1次初始化表达式(如int i=0);
  2. 判断条件表达式:为真则执行循环体,为假则退出循环;
  3. 执行增量表达式(如i++);
  4. 回到步骤2,重复判断。
灵活用法拆解:

① 基础循环(递增、递减、步长非1):

#include <stdio.h>

int main() {
    // 1. 递增循环(1-10)
    printf("1-10的数字: ");
    for (int i = 1; i <= 10; i++) {
        printf("%d ", i);
    }
    printf("\n");
    
    // 2. 递减循环(10-1)
    printf("10-1的数字: ");
    for (int i = 10; i >= 1; i--) {
        printf("%d ", i);
    }
    printf("\n");
    
    // 3. 步长非1(1-10的奇数,步长=2)
    printf("1-10的奇数: ");
    for (int i = 1; i <= 10; i += 2) {
        printf("%d ", i);
    }
    printf("\n");
    
    return 0;
}

② 多循环变量(同步控制两个变量,利用逗号表达式):

// 同时递增i、递减j
for (int i = 0, j = 10; i < j; i++, j--) {
    printf("(%d, %d) ", i, j); // 输出:(0,10) (1,9) (2,8) (3,7) (4,6)
}

③ 省略表达式(灵活适配不同场景):

#include <stdio.h>

int main() {
    // 1. 完全省略(无限循环,需用break退出)
    printf("1. 完全省略表达式: ");
    int count = 0;
    for (;;) { // 初始化、条件、增量都省略
        printf("%d ", count++);
        if (count >= 5) break; // 必须手动退出
    }
    printf("\n");
    
    // 2. 省略初始化(初始化在循环外)
    printf("2. 省略初始化表达式: ");
    int i = 0;
    for (; i < 3; i++) { // 省略初始化
        printf("i=%d ", i);
    }
    printf("\n");
    
    // 3. 省略条件表达式(无限循环,靠break退出)
    printf("3. 省略条件表达式: ");
    for (int j = 0; ; j++) {
        printf("j=%d ", j);
        if (j >= 2) break;
    }
    printf("\n");
    
    // 4. 省略增量表达式(增量在循环体内)
    printf("4. 省略增量表达式: ");
    for (int k = 0; k < 3; ) { // 省略增量
        printf("k=%d ", k);
        k++; // 增量在循环体内
    }
    printf("\n");
    
    return 0;
}

注意:省略表达式时,;不能省略

(2)while

while循环将“条件判断”放在循环开头,语法简洁,适合“未知循环次数,仅知道终止条件”的场景(如用户输入控制、文件读取)。

核心语法:
while (条件表达式) {
    循环体;
}

执行流程:先判断条件,为真则执行循环体,否则直接退出(可能一次都不执行)。

① 基本循环(1-5):

#include <stdio.h>

int main() {
    int i = 1;
    printf("1-5的数字: ");
    while (i <= 5) {
        printf("%d ", i);
        i++; // 增量更新必须写在循环体内,否则会无限循环
    }
    printf("\n");
    
    return 0;
}

② 用户输入控制循环(输入0结束):

#include <stdio.h>

int main() {
    int number, sum = 0;
    printf("请输入数字(输入0结束): ");
    scanf("%d", &number);
    
    // 条件:number != 0(输入0时退出)
    while (number != 0) {
        sum += number;
        printf("当前总和: %d\n", sum);
        printf("请输入数字(输入0结束): ");
        scanf("%d", &number);
    }
    printf("最终总和: %d\n", sum);
    
    return 0;
}

避坑点:循环体内必须有“改变条件的语句”(如number = 0i++),否则会陷入无限循环。

(3)do-while 至少执行一次

do-while循环将“条件判断”放在循环末尾,无论条件是否为真,循环体至少执行一次,适合“必须先执行一次”的场景(如菜单交互、密码输入验证)。

核心语法:
do {
    循环体;
} while (条件表达式);

执行流程:先执行循环体,再判断条件,为真则继续循环,否则退出。

菜单交互(必须显示一次菜单)
#include <stdio.h>

int main() {
    int choice;
    // 先显示菜单,再判断是否退出
    do {
        printf("\n=== 菜单 ===\n");
        printf("1. 开始游戏\n");
        printf("2. 设置\n");
        printf("3. 退出\n");
        printf("请选择: ");
        scanf("%d", &choice);
        
        switch (choice) {
            case 1: printf("游戏开始!\n"); break;
            case 2: printf("进入设置\n"); break;
            case 3: printf("退出程序\n"); break;
            default: printf("无效选择,请重新输入!\n"); break;
        }
    } while (choice != 3); // 选择3时退出
    
    return 0;
}

关键差异:若用while实现,首次菜单需要手动写一次,而do-while直接简化代码。

2.2 循环控制语句:break、continue、goto

循环控制语句用于改变循环的默认执行流程,灵活运用可让循环更高效。

(1)break:终止当前循环
  • 作用:立即退出当前层循环(嵌套循环中不影响外层);
  • 适用场景:找到目标值后退出、满足异常条件时退出。
#include <stdio.h>

int main() {
    // 示例1:找到第一个能被7整除的数
    printf("找到第一个能被7整除的数: ");
    for (int i = 1; i <= 100; i++) {
        if (i % 7 == 0) {
            printf("%d\n", i); // 输出:7
            break; // 找到后立即退出循环
        }
    }
    
    // 示例2:嵌套循环中,break只退出内层
    printf("\n嵌套循环中的break:\n");
    for (int i = 1; i <= 3; i++) {
        for (int j = 1; j <= 3; j++) {
            if (i * j > 4) {
                printf("i=%d, j=%d时break(退出内层)\n", i, j);
                break; // 仅退出内层循环,外层继续执行
            }
            printf("i=%d, j=%d\n", i, j);
        }
    }
    
    return 0;
}
(2)continue:跳过本次循环
  • 作用:跳过循环体中continue后的代码,直接进入下一次循环(不终止循环);
  • 适用场景:跳过特定条件的处理(如跳过奇数、跳过零值)。
#include <stdio.h>

int main() {
    // 示例1:输出1-10的偶数(跳过奇数)
    printf("1-10的偶数: ");
    for (int i = 1; i <= 10; i++) {
        if (i % 2 != 0) {
            continue; // 跳过奇数,直接进入下一次循环
        }
        printf("%d ", i); // 仅偶数会执行此句
    }
    printf("\n");
    
    // 示例2:处理非零数字(跳过零值)
    printf("处理非零数字(翻倍输出): ");
    int numbers[] = {1, 0, 3, 0, 5};
    for (int i = 0; i < 5; i++) {
        if (numbers[i] == 0) {
            continue; // 跳过0,不处理
        }
        printf("%d ", numbers[i] * 2); // 输出:2 6 10
    }
    printf("\n");
    
    return 0;
}
(3)goto:无条件跳转(谨慎使用)
  • 作用:无条件跳转到代码中指定的“标签”(标签格式:标签名:);
  • 适用场景:多层循环快速退出、错误处理(替代多层break);
  • 注意:滥用goto会导致代码逻辑混乱(“面条代码”),仅在必要时使用。
#include <stdio.h>

int main() {
    printf("=== goto语句(错误处理示例) ===\n");
    int a, b;
    printf("请输入两个非零整数: ");
    scanf("%d %d", &a, &b);
    
    // 错误处理:若有一个为0,跳转到错误处理标签
    if (a == 0 || b == 0) {
        goto error_handler; // 跳转至error_handler标签
    }
    
    // 正常逻辑:计算除法
    printf("%d / %d = %.2f\n", a, b, (double)a / b);
    goto end; // 跳过错误处理,直接到程序结束
    
error_handler: // 标签(必须单独一行,后跟冒号)
    printf("错误:除数不能为零!\n");
    
end: // 程序结束标签
    printf("程序结束\n");
    
    return 0;
}

三、总结

1. 选择结构技巧

  • 范围判断用if-else if,固定值匹配用switch-case(效率更高);
  • switch-case中,每个case后必加break,避免无意穿透;
  • 嵌套if不超过3层(否则代码可读性差,可拆分为函数)。

2. 循环结构技巧

  • 已知循环次数用for,未知次数用while,必须执行一次用do-while
  • 循环体内必须有“改变条件的语句”,避免无限循环;
  • 多层循环中,用break退出内层,goto(谨慎使用)退出多层;
  • 遍历数组时,用for (int i = 0; i < len; i++)(结构化清晰)。

3. 注意事项

  • 条件表达式中,避免用=(赋值)代替==(等于);
  • scanf读取字符时,注意吸收前一个输入的回车符(加空格%c);
  • 循环控制语句(break/continue)仅影响当前层循环;
  • 处理数值计算时,先判断边界条件(如除零、数组越界)。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值