【C语言】循环语句(while循环、do-while循环、for循环、break、continue、goto语句)

1.while循环

C语言中的while循环是一种常用的控制结构,用于重复执行某段代码,直到满足某个条件为止。

1.1.基本语法

while循环的基本语法如下:

while(条件){
    //循环体
}
  • 条件:一个布尔表达式,用于判断是否继续执行循环。
  • 循环体:当条件为true时,执行的代码块。

执行流程:

  1. 首先计算“条件”的值。
  2. 如果“条件”为true,执行循环体。
  3. 执行完循环后,再次计算“条件”,重复步骤2。
  4. 如果“条件”为false,退出循环,执行循环后的代码。

1.2.注意事项

  1. 条件判断:while循环的条件必须是一个布尔表达式。如果条件始终为true,会导致死循环。
  2. 变量初始化:在循环开始前,确保相关变量已经被正确初始化。
  3. 循环变量更新:在循环体内,通常需要更新循环变量,以确保循环能够终止。
  4. 空循环:如果循环体为空,必须用 ; 表示空语句
  5. 应用场景:适用于需要重复执行某段代码,直到满足某个条件的场景。

1.3.示例演示

1.3.1.累加计算

#include <stdio.h>

int main() {
    int sum = 0; // 初始化累加和
    int i = 1;   // 初始化计数器
    while (i <= 10) { // 条件:i <= 10
        sum += i; // 累加
        i++;      // 更新计数器
    }
    printf("Sum from 1 to 10 is: %d\n", sum);
    return 0;
}

输出:

Sum from 1 to 10 is: 55

1.3.2.死循环

#include <stdio.h>

int main() {
    while (1) { // 条件始终为true
        printf("This is an infinite loop.\n");
        // 按Ctrl+C可以终止程序
    }
    return 0;
}

1.3.3.嵌套while循环

#include <stdio.h>

int main() {
    int i = 1; // 外层循环计数器
    while (i <= 3) {
        int j = 1; // 内层循环计数器
        while (j <= 2) {
            printf("(%d, %d) ", i, j);
            j++; // 更新内层计数器
        }
        i++; // 更新外层计数器
    }
    return 0;
}

输出:

(1, 1) (1, 2) (2, 1) (2, 2) (3, 1) (3, 2)

2.do-while循环

C语言中的do-while循环是一种后测试循环,它的特点时循环体至少会执行一次,然后再判断条件是否满足继续执行。这种循环结构在某些场景下非常有用,比如需要确保某些代码至少执行一次的场景。

2.1.基本语法

do-while循环的语法如下:

do {
    // 循环体
} while (条件);
  • 循环体:必须放在do和while之间,并用花括号{}包裹。
  • 条件:一个布尔表达式,用于判断是否继续执行循环。
  • 分号:while后面必须有一个分号 ; ,否则会导致语法错误。

执行流程

  1. 首先执行循环体。
  2. 然后计算条件的值。
  3. 如果条件为true,重复步骤1;否则退出循环。

2.2.注意事项

  1. 核心特点:无论条件是否为true,循环体都会执行一次。
  2. 条件判断:条件必须是一个布尔表达式。如果条件始终为true,会导致死循环。
  3. 循环变量更新:在循环体内,通常需要更新循环变量,以确保循环能够终止。
  4. 分号不可省略:while后面必须有一个分号 ; ,否则会导致编译错误。
  5. 空循环体:如果循环体为空,必须用空语句{ }表示。

2.3.与while循环的对比

特性do-whilewhile
执行顺序先执行循环体,再判断条件先判断条件,再决定是否执行循环体
适用场景至少执行一次的操作(如输入验证)条件可能为假但需跳过循环的情况

2.4.示例演示

2.4.1.嵌套do-while循环

#include <stdio.h>

int main() {
    int i = 1; // 外层循环计数器
    do {
        int j = 1; // 内层循环计数器
        do {
            printf("(%d, %d) ", i, j);
            j++; // 更新内层计数器
        } while (j <= 2);
        i++; // 更新外层计数器
    } while (i <= 3);
    return 0;
}

输出:

(1, 1) (1, 2) (2, 1) (2, 2) (3, 1) (3, 2)

2.4.2.输入验证(强制合法输入)

#include <stdio.h>
int main() {
        int num;
        do {
            printf("请输入一个正整数:");
            scanf("%d", &num);
        } while (num <= 0);  // 若输入非法值,重复提示输入 
        printf("输入有效:%d\n", num);
        return 0;
}

:用户必须输入大于0的整数才能退出循环

2.4.3.逆向显示整数值

#include <stdio.h>
int main() {
        int number = 1234;
        do {
            printf("%d", number % 10);  // 取末位数字 
            number /= 10;               // 移除末位 
        } while (number > 0);          // 输出:4321 
        return 0;
}

:若number初始为0,循环体仍会执行一次,输出0

3.for循环

for循环是C语言中最常用的循环结构之一,特别适合用于需要明确循环次数的场景。

3.1.基本语法

for循环的语法如下:

for (初始化; 条件判断; 更新表达式) {
    // 循环体
}
  • 初始化:在循环开始前执行一次,通常用于初始化循环变量。
  • 条件判断:每次循环开始前都会检查的条件,如果条件为true,继续执行循环体;否则退出循环。
  • 更新表达式:每次循环体执行完毕后执行,通常用于更新循环变量。

执行流程:

  1. 执行初始化部分。
  2. 检查条件判断的值。
  3. 如果条件为true,执行循环体。
  4. 执行更新表达式。
  5. 重复步骤2-4,直到条件为false。

3.2.注意事项

1. 初始化、条件判断和更新表达式:

  • 这三个部分用分号 ; 分隔,缺一不可。
  • 初始化部分通常用于声明和初始化循环变量。
  • 条件判断部分是一个布尔表达式。
  • 更新表达式通常用于递增或递减循环变量。

2. 空循环体:如果循环体为空,可以用 ; 表示空语句,例如:

for (i = 0; i < 10; i++);

3. 死循环:如果条件判断始终为true,会导致死循环。例如for (;;)。

4. 循环变量的作用域:在C语言中,for循环的初始化部分声明的变量作用域仅限于整个for循环。

5. 灵活性:for循环的三个部分可以为空,但分号不能省略。例如:

for (;;); // 死循环

3.3.示例演示

3.3.1.累加计算

#include <stdio.h>

int main() {
    int sum = 0;
    for (int i = 1; i <= 10; i++) {
        sum += i;
    }
    printf("Sum from 1 to 10 is: %d\n", sum);
    return 0;
}

输出:

Sum from 1 to 10 is: 55

3.3.2.打印乘法表

#include <stdio.h>

int main() {
    for (int i = 1; i <= 9; i++) {
        for (int j = 1; j <= i; j++) {
            printf("%d*%d=%d ", j, i, i * j);
        }
        printf("\n");
    }
    return 0;
}

输出:

3.3.3.计算1~100之间3的倍数的数字之和

#include <stdio.h>
int main(){
    int i = 0;
    int sum = 0;
    for(i = 1; i <= 100; i++){
        if(i % 3 == 0)
        sum += i;
    }
    printf("%d\n", sum);
    return 0;
}

可优化为:

//如果能直接产⽣3的倍数的数字就省去了多余的循环和判断
#include <stdio.h>
int main(){
    int i = 0;
    int sum = 0;
    for(i = 3; i <= 100; i += 3){
    sum += i;
    }
    printf("%d\n", sum);
    return 0;
}

4.break语句

在C语言中,break 语句是一个重要的流程控制语句,主要用于中断循环或switch语句的执行。

4.1.基本用法

4.1.1.在switch语句中使用

  • 用于防止case穿透(fall-through)
  • 执行到break会立即退出整个switch结构
switch(grade) {
    case 'A':
        printf("Excellent");
        break;  // 跳出switch
    case 'B':
        printf("Good");
        break;
    default:
        printf("Invalid");
}

4.1.2.在循环结构中使用

  • 用于提前终止循环(while/for/do-while)
  • 执行到break会立即跳出当前所在层的循环
for(int i=0; i<10; i++) {
    if(i == 5) {
        break;  // 当i=5时终止循环
    }
    printf("%d ", i);  // 输出0 1 2 3 4
}

4.2.注意事项

4.2.1.仅影响最近一层结构

  • 在嵌套循环中,break只能跳出当前所在层的循环
for(int i=0; i<3; i++) {
    for(int j=0; j<3; j++) {
        if(j == 1) break;  // 仅跳出内层循环
        printf("(%d,%d) ", i, j);
    }
}
// 输出:(0,0) (1,0) (2,0)

4.2.2.不能用于if语句

  • 如果break出现在非循环/非switch的if语句中,会导致编译错误

4.2.3.慎用break

  • 过度使用会降低代码可读性,建议优先使用合理的循环条件

4.2.4.switch中的break陷阱

  • 忘写break会导致case穿透现象:
switch(n) {
    case 1: printf("One");
    case 2: printf("Two");  // 当n=1时会连续输出OneTwo
}

4.3.示例演示

4.3.1.查找数组元素

int arr[] = {2,4,6,8,10};
int target = 8;
for(int i=0; i<5; i++) {
    if(arr[i] == target) {
        printf("Found at index %d", i);
        break;  // 找到后立即退出循环
    }
}

4.3.2.输入验证

while(1) {  // 无限循环
    printf("Enter 0 to exit: ");
    int num;
    scanf("%d", &num);
    if(num == 0) {
        break;  // 用户输入0时退出循环
    }
}

4.3.3.跳出多层循环

对于需要跳出多层循环的场景,可以使用以下方法:

int flag = 0;
for(int i=0; i<3; i++) {
    for(int j=0; j<3; j++) {
        if(condition) {
            flag = 1;
            break;
        }
    }
    if(flag) break;  // 通过标志变量跳出外层循环
}

4.4.最佳实践

  • 在switch语句中始终添加break,除非明确需要穿透效果
  • 在循环中使用break时,尽量让终止条件明显
  • 对于复杂逻辑,优先考虑重构代码而不是过度使用break

5.continue语句

在C语言中,continue 语句是另一种关键的流程控制语句,专门用于 循环结构 中跳过当前迭代的剩余代码,直接进入下一次循环。

5.1.基本用法

5.1.1.核心作用

  • 在循环(while/for/do-while)中跳过本次迭代的后续代码,立即开始下一次循环。
  • 与break(完全终止循环)不同,continue仅跳过当前迭代。

5.1.2.语法形式

while(condition) {
    // 代码A
    if(skip_condition) {
        continue;  // 跳过代码B,直接回到循环条件判断
    }
    // 代码B
}

5.1.3.适用场景

  • 过滤不需要处理的数据
  • 提前结束某些特定条件下的操作
  • 优化循环逻辑,避免深层嵌套

5.2.注意事项

5.2.1.循环类型影响行为

  • for循环:continue会跳过循环体剩余代码,但仍执行增量表达式(如i++)
for(int i=0; i<5; i++) {
    if(i == 2) continue;
    printf("%d ", i);  // 输出 0 1 3 4(i=2时跳过打印,但i仍会自增)
}
  • while/do-while循环:continue直接跳转到循环条件检查,可能导致死循环:
int i = 0;
while(i < 5) {
    i++;
    if(i == 3) continue;  // 若此处未修改循环变量,可能陷入死循环
    printf("%d ", i);
}

5.2.2.不能用于非循环结构

  • 在switch或纯if语句中使用continue会导致编译错误。

5.2.3.避免逻辑混淆

  • 过度使用continue可能使代码可读性下降,需确保逻辑清晰。

5.3.示例演示

5.3.1.跳过奇数打印

for(int i=1; i<=10; i++) {
    if(i % 2 != 0) {
        continue;  // 跳过奇数
    }
    printf("%d ", i);  // 输出 2 4 6 8 10
}

5.3.2.输入验证过滤负数

int sum = 0, num;
for(int i=0; i<5; i++) {
    printf("Enter positive number: ");
    scanf("%d", &num);
    if(num < 0) {
        printf("Negative ignored!\n");
        continue;  // 跳过负数的累加
    }
    sum += num;
}
printf("Total: %d", sum);

5.4.常见陷阱

5.4.1.修改循环变量前使用 continue

int i = 0;
while(i < 5) {
    if(i == 2) {
        continue;  // 死循环!i永远无法自增到3
    }
    i++;
}

5.4.2.误用 continue 代替条件判断

  • 不推荐写法
for(...) {
    if(condition) continue;
    else {
        // 复杂逻辑
    }
}
  • 推荐改写为:
for(...) {
    if(!condition) {
        // 清晰的条件分支
    }
}

5.5.最佳实践


5.5.1.明确循环变量修改时机

  • 在 while 循环中使用 continue 时,确保循环变量在 continue 前已更新。

5.5.2.优先使用正向逻辑

  • 尽量减少 continue 的使用,改用正向条件判断以提高可读性:
// 不推荐
for(...) {
    if(should_skip) continue;
    // 业务代码
}

// 推荐
for(...) {
    if(!should_skip) {
        // 业务代码
    }
}

5.5.3.注释说明跳过原因

  • 对复杂的 continue 条件添加注释,说明跳过逻辑:
if(data == INVALID_FLAG) {
    continue;  // 跳过无效数据(协议规定0xFFFF为无效标记)
}

6.goto语句

goto语句是C语言中一种无条件跳转控制语句,允许程序跳转到同一函数内的指定标签处执行。尽管在现代编程中其使用备受争议,但在特定场景下仍具实用价值。

6.1.基本用法

6.1.1.语法结构

  • 标签定义:在代码中通过标签名:定义跳转目标。
  • 跳转指令:使用goto 标签名;实现跳转。
  • #include <stdio.h>
    
    int main() {
        printf("Start\n");
        goto my_label;    // 跳转到标签处
        printf("Skipped\n");
    
    my_label:            // 标签定义
        printf("Jumped here\n");
        return 0;
    }
    /* 输出:
     * Start
     * Jumped here
     */

    6.1.2.适用场景

  • 错误处理与资源清理:在函数中多处错误退出时,集中释放资源。
  • 跳出深层嵌套循环:替代多层break,简化代码逻辑。
  • 状态机实现:有限状态机(FSM)中切换状态。

6.2.注意事项

6.2.1. 结构化编程限制

  • 破坏代码逻辑:过度使用导致“面条代码”(Spaghetti Code),难以跟踪流程。
  • 替代方案优先:优先使用break、continue、函数返回或错误码处理逻辑。

6.2.2. 作用域限制

  • 同一函数内跳转:goto不能跨函数跳转。
  • 变量初始化问题:不可跳过变量的初始化。
int main() {
    goto label;
    int x = 10;  // 编译器报错:跳过初始化
label:
    printf("%d", x); 
    return 0;
}

6.2.3.跳转目标合法性

  • 禁止跨作用域跳转:不能从外部跳入循环、条件语句或switch内部。
for (int i=0; i<3; i++) {
inner:
    printf("Loop\n");
}
goto inner;  // 错误:跳入循环作用域

6.2.4.资源泄漏风险

未释放资源:跳转前需确保已释放已分配的内存、文件句柄等。

FILE *fp = fopen("file.txt", "r");
if (error) {
    goto exit;  // 错误:未关闭文件直接跳转
}
exit:
    // 此处应添加 fclose(fp);
    return;

6.3.示例演示

6.3.1.集中错误处理

#include <stdio.h>
#include <stdlib.h>

int main() {
    FILE *fp1 = NULL, *fp2 = NULL;
    
    fp1 = fopen("file1.txt", "r");
    if (!fp1) {
        perror("Open file1 failed");
        goto cleanup;  // 跳转到清理
    }

    fp2 = fopen("file2.txt", "w");
    if (!fp2) {
        perror("Open file2 failed");
        goto cleanup;  // 跳转到清理
    }

    // 正常业务逻辑...

cleanup:  // 统一释放资源
    if (fp1) fclose(fp1);
    if (fp2) fclose(fp2);
    return 0;
}

6.3.2.跳出多层嵌套循环

for (int i=0; i<5; i++) {
    for (int j=0; j<5; j++) {
        if (i == 2 && j == 3) {
            goto exit_loops;  // 直接跳出所有循环
        }
        printf("(%d,%d) ", i, j);
    }
}
exit_loops:
printf("\nExited loops.\n");
/* 输出:
 * (0,0) (0,1) ... (2,0) (2,1) (2,2) 
 * Exited loops.
 */

6.3.3.错误示范(死循环)

int x = 0;
start:
    printf("%d ", x);
    x++;
    if (x < 5) goto start;  // 合法但可读性差,等同于循环
// 输出:0 1 2 3 4

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值