C语言基础 4 - 循环结构

Updated on in 编程语言 with 0 views and 0 comments

引言

在高级语言编程中,特别是C语言编程,使用循环结构的主要原因是为了提高代码的可读性、可维护性和执行效率。循环结构允许我们重复执行某段代码,而不必每次都手动编写相同的代码块。这在处理 重复任务 时特别有用,比如遍历数组、处理文件中的数据、进行数值计算等。

下面通过几个例子来引入循环结构:

例1:打印数字1到10

不使用循环结构:

#include <stdio.h>

int main() {
    printf("1\n");
    printf("2\n");
    printf("3\n");
    printf("4\n");
    printf("5\n");
    printf("6\n");
    printf("7\n");
    printf("8\n");
    printf("9\n");
    printf("10\n");
    return 0;
}

使用循环结构:

#include <stdio.h>

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

例2:计算1到100的和

不使用循环结构(几乎不可能手动写出所有相加的操作):

#include <stdio.h>

int main() {
    int sum;
    sum = 1 + 2 + 3 + ... + 100; // 不现实,因为需要写100行代码来相加 
    printf("Sum: %d\n", sum);
    return 0;
}

使用循环结构:

#include <stdio.h>

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

例3:遍历数组并打印每个元素

不使用循环结构(对于固定大小的数组,但非常不灵活):

#include <stdio.h>

int main() {
    int arr[] = {1, 2, 3, 4, 5};
    printf("%d\n", arr[0]);
    printf("%d\n", arr[1]);
    printf("%d\n", arr[2]);
    printf("%d\n", arr[3]);
    printf("%d\n", arr[4]);
    return 0;
}

使用循环结构:

#include <stdio.h>

int main() {
    int arr[] = {1, 2, 3, 4, 5};
    int length = sizeof(arr) / sizeof(arr[0]);
    for (int i = 0; i < length; i++) {
        printf("%d\n", arr[i]);
    }
    return 0;
}

总结

  1. 提高代码可读性:循环结构使得代码更加简洁,易于理解。
  2. 提高代码可维护性:如果需要修改循环次数或逻辑,只需更改循环控制语句,而不必修改多行代码。
  3. 提高执行效率:循环结构避免了重复编写相同的代码,减少了内存占用和提高了执行速度。

通过上面的例子可以看出,循环结构在C语言编程中非常重要,它极大地提高了编程的效率和灵活性。

注意事项

  • 在使用循环结构时,务必确保循环条件最终会变为假,以避免无限循环。
  • 可以通过break语句提前退出循环,通过continue语句跳过当前迭代并继续下一次迭代。
  • 在使用for循环时,初始化表达式、循环条件和迭代表达式都是可选的,但省略它们可能会导致不可预测的行为。

三种循环语句

for循环

  • for 循环是最常用的循环结构之一,它通常用于已知循环次数的场景。for(初始表达式; 循环条件; 迭代表达式) { 循环体 } 循环的语法如下:

  • 初始化表达式: 在循环开始前执行,通常用于初始化循环控制变量。

  • 循环条件: 在每次循环迭代前检查,如果条件为真(非零),则执行循环体;如果条件为假(零),则退出循环。

  • 迭代表达式: 在每次循环迭代结束时执行,通常用于更新循环控制变量。

  • 语法

    for (初始化表达式; 循环条件; 迭代表达式) {
        // 循环体
    }
    
  • 执行流程

    1. 计算初始表达式(只执行一次)

    2. 判断循环条件,若为真则执行循环体,否则跳出循环

    3. 执行循环体

    4. 计算迭代表达式

    5. 重复步骤 b

  • 示例:计算1到20的和

#include <stdio.h>
void main() {
    long int result = 0;
    for (int i = 1; i <= 20; i++) {
        result += i;	//即result=result + i;
        printf("和 = %ld\n", result);
    }
}
  • 注意事项:
    1. 循环体如果有一条以上的语句,应该用大括号{}括起来,如果只有一条语句,大括号{}可以省略。
    2. for语句中的表达式可以省略任意一个,也可以都省略,但“ ; ”不能省略。 需要特别注意是“;”会经常错误的写成逗号“,” ,或者在循环语句的小括号外面加“;”。

示例:计算1到20的和

#include <stdio.h>
void main() {
    long int result = 0;
    int i=1;//如果在外面定于了循环语句的初始值,或者其他特殊情况,循环语句可以省略
    for (; i <= 20; i++) //{
        result += i;	//即result=result + i;
    //}//如果循环体中只有一条语句,大括号可以省略,为了可读性,建议无论何时都添加大括号
    printf("和 = %ld\n", result);  
  
}

while循环

  • while循环是一种基本的循环控制结构,用于在给定条件为真的情况下重复执行一段代码。当循环次数未知时,while循环特别有用,因为你可以根据某个条件(而不是一个固定的计数器)来控制循环的执行。
  • whilefor循环不同,while循环没有初始化表达式和迭代表达式,这些操作需要在循环外部进行循环的语法如下:
  • 循环条件: 在每次循环迭代前检查,如果条件为真(非零),则执行循环体;如果条件为假(零),则退出循环。
  • 语法while(循环条件) { 循环体 }
while (循环条件) {
    // 循环体
}
  • 执行流程
    1. 判断循环条件,若为真则执行循环体,否则跳出循环
    2. 执行循环体
    3. 重复步骤 a

  • 注意
    • 循环体中必须有改变循环控制变量值的控制语句,否则可能导致死循环。
    • 循环体如果有一条以上的语句,应该用大括号括起来,如果只有一条语句,大括号可以省略。
  • 示例:
#include <stdio.h>
#include <stdbool.h>

int main() {
    int number;
    bool keepRunning = true;

    printf("Enter numbers (enter -1 to stop):\n");

    // 使用 while 循环读取用户输入,直到输入 -1
    while (keepRunning) {
        printf("Enter a number: ");
        scanf("%d", &number);

        if (number == -1) {
            keepRunning = false; // 输入 -1 时停止循环
        } else {
            printf("You entered: %d\n", number);
        }
    }

    printf("Loop ended. Goodbye!\n");

    return 0;
}

在这个示例中:

  1. 我们声明了一个整型变量number和一个布尔变量keepRunning
  2. keepRunning 初始化为true,表示循环开始时是活动的。
  3. 使用while 循环,条件为keepRunningtrue
  4. 在循环体内,使用scanf 读取用户输入的整数,并存储在number 变量中。
  5. 如果用户输入的是-1,则将keepRunning 设置为false,从而结束循环。
  6. 如果用户输入的不是-1,则打印出用户输入的数。
  7. 当循环结束时,打印一条消息表示循环已结束。

这个示例展示了如何使用 while 循环来处理不确定次数的迭代,直到满足某个特定条件(在本例中是用户输入 -1)为止。

do-while循环

  • do-while 循环与while循环类似,但有一个重要的区别:do-while循环至少会执行一次循环体,即使循环条件在第一次检查时就为假。do-while循环的语法如下:
  • 循环条件:在每次循环迭代后检查,如果条件为真(非零),则重复执行循环体;如果条件为假(零),则退出循环。
  • 语法do { 循环体 } while(循环条件);
do {
    // 循环体
} while (循环条件);
  • 执行流程
    1. 执行循环体
    2. 判断循环条件,若为真则重复步骤 a,否则跳出循环

  • 与while的比较:do-while循环至少执行一次循环体,而while循环可能一次也不执行。

    image.png

  • 示例:计算从23递减到1之前的所有数

    int x = 23;
    do {
        printf("%2d\n", x--);
    } while (!x);
    // 输出:23 22 21 20 19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1
    

选择三种循环的一般原则

  • 在选择循环结构时,通常根据循环的具体需求和特点来选择适合的循环类型。以下是选择三种循环(for循环、while循环、do-while循环)的一般原则:
  1. for循环
    适用场景:当循环次数已知或可以在循环开始前确定时,使用for循环。
    特点:for循环通常包括初始化表达式、条件表达式和迭代表达式。它适合用于需要明确循环次数的场景,如遍历数组、集合等。
    示例:
for (int i = 0; i < 10; i++) {
 // 循环体
}
  1. while循环
    适用场景:当循环次数未知,但循环条件可以在每次迭代前进行判断时,使用while循环。
    特点:while循环在进入循环体之前先判断条件,如果条件为真,则执行循环体;否则,跳出循环。它适合用于需要根据某些条件来决定是否继续循环的场景。
    示例:
int i = 0;
while (i < 10) {
 // 循环体
 i++;
}
  1. do-while循环
    适用场景:当循环体至少需要执行一次,且循环条件在每次迭代后进行判断时,使用do-while循环。
    特点:do-while循环先执行循环体,然后判断条件。如果条件为真,则继续循环;否则,跳出循环。它适合用于需要确保循环体至少执行一次的场景。
    示例:
int i = 0;
do {
 // 循环体
 i++;
} while (i < 10);
  • 总结
    • 如果循环次数已知或可以在循环开始前确定,使用for循环。
    • 如果循环次数未知,但需要根据条件来决定是否继续循环,使用while循环。
    • 如果循环体至少需要执行一次,并且循环条件在每次迭代后进行判断,使用do-while循环。
  • 在选择循环结构时,还需要考虑代码的可读性、维护性和效率等因素。根据具体的需求和场景,选择最合适的循环结构可以提高代码的质量和效率。
  1. 混合使用

当然很多时候同一函数中可以使用不同的循环结构实现,并且大多数相同任务可以使用不同循环结构实现。示例:

// 1、用while, do - while, for循环完成计算n!。要求n从键盘输入,并输出结果。

#include <stdio.h>
#include <limits.h>

int main() {
    int n;
    long long t;

    // 输入验证
    while (1) {
        printf("请输入一个非负整数n的值并求它的阶乘: ");
        if (scanf("%d", &n) != 1) {
            printf("输入无效,请输入一个整数。\n");
            // 清除输入缓冲区
            while (getchar() != '\n');
            continue;
        }
        if (n < 0) {
            printf("请输入一个非负整数。\n");
            continue;
        }
        if (n > 20) {
            printf("输入的数太大,可能导致溢出,请输入一个小于等于20的数。\n");
            continue;
        }
        break;
    }

    // for 循环计算阶乘
    t = 1;
    for (int i = 1; i <= n; i++) {
        t *= i;
    }
    printf("for循环计算n! = %lld\n", t);

    // while 循环计算阶乘
    t = 1;
    int i = 1;
    while (i <= n) {
        t *= i;
        i++;
    }
    printf("while循环计算n! = %lld\n", t);

    // do-while 循环计算阶乘
    t = 1;
    i = 1;
    do {
        t *= i;
        i++;
    } while (i <= n);
    printf("do-while循环计算n! = %lld\n", t);

    return 0;
}

循环嵌套

  • 定义:一个循环体内又包含另一个完整的循环结构,称为循环的嵌套。

  • 形式:可以是for、while、do-while的任意组合。
  • 执行:外层循环执行一次,内层循环执行一轮(即执行完自己的循环)。
  • 变量: 内层循环控制可以直接引用外层循环的相关变量,但不要轻易改变外层循环控制变量的值。
  • 示例:打印二维图形
// 用*号打印三角形
#include <stdio.h>

int i, j, k;

void printTriangle(int height) {
    for (i = 1; i <= height; i++) {
        // 打印每行前面的空格
        for (j = 0; j < height - i; j++) {
            printf(" ");
        }
        // 打印星号
        for (k = 0; k < 2 * i - 1; k++) {
            printf("*");
        }
        // 换行  
        printf("\n");
    }
}

int main() {
    int height;

    // 提示用户输入三角形的高度  
    printf("请输入三角形的高度: ");
    scanf("%d", &height);

    // 调用函数打印三角形  
    printTriangle(height);

    return 0;
}
// 输出:
//    *
//   ***
//  *****
// *******
//*********

编程实现 n!的倒数的和

//2、编程实现:Sn=1+1/2!+1/3!+....1/n!
#include <stdio.h>
#include <stdlib.h>

int main()
{
    int n;
    unsigned long long k = 1;
    double sum = 0;

    printf("请输入n的值(非负整数):");
    //判断输入n的值是否符合非负整数的要求
    if (scanf("%d", &n) != 1 || n < 0) {
        printf("输入无效,请输入非负整数。\n");
        return 1;
    }

    if (n == 0) {
        printf("1/0!的和sum= 1.000000\n");
        return 0;
    }

    for (int i = 1; i <= n; i++)
    {
        //判断n的阶乘是否超出变量范围溢出
        if (k > ULLONG_MAX / i) {
            printf("阶乘结果超出范围,终止计算。\n");
            return 1;
        }
        k *= i;
        sum += 1.0 / k;
        printf("k = %llu, sum = %.6f\n", k, sum);
    }
    printf("1/n!的和sum= %.6f\n", sum);

    return 0;
}

异常退出:流程控制语句

在循环结构中,循环体一般都要执行到循环条件不成立的时候才会退出循环。但是实际问题中,一些特殊的情况下,需要中途退出循环体,或者某次循环时不希望执行循环体中的某些语句,这时就需要使用到流程控制语句。

  • break语句:使程序运行时中途退出switch-case结构或者退出一个循环体。
  • continue语句:提前结束本次循环,跳过continue语句下面未执行的语句,继续进行下一次循环。

  • 示例
    • 使用break退出循环
#include <stdio.h>
void main() {
    int i, n;
    for (i = 1; i <= 5; i++) {
        printf("Please enter n: ");
        scanf("%d", &n);
        if (n < 0) break;
        printf("n = %d\n", n);
    }
    printf("Program is over!\n");
}
// 输入:-10 输出:Please enter n: -10 Program is over!

注意:

  • 在嵌套循环结构中,break语句只能退出包含break语句的那层循环体。
  • break语句不能用在除了switch语句和循环语句以外的任何其他语句。
  • 使用continue跳过某次循环
#include <stdio.h>
void main() {
    int i, n;
    for (i = 1; i <= 5; i++) {
        printf("Please enter n: ");
        scanf("%d", &n);
        if (n < 0) continue;
        printf("n = %d\n", n);
    }
    printf("Program is over!\n");
}
// 输入:
// 10 -10 20 -20 30 
// 输出:
// Please enter n: 10 n = 10 
// Please enter n: 20 n = 20 
// Please enter n: 30 n = 30 
// Program is over!

注意:

  • continue语句通常和if语句连用,只能提前结束本次循环,不能使整个循环终止。
  • continue语句只对循环起作用。
  • continue语句在for语句中结束本次循环,但for语句中的增量仍然执行。
  • 示例
#include <stdio.h>
int main()
{
    int a = 7, i;
    for (i = 1; i <= 3; i++)
    {
        if (a > 13)
            break;
        if (a % 2)
        {
            a += 3;
            continue;
        }
        a = a + 4;
    }
    printf("%d,%d", i, a);
    return 0;
}
//输出的结果是:3,14

循环编程应用

  1. 素数判断
    • 定义:素数就是只能被1和自身整除的正整数,1不是素数,2是素数。
    • 示例
#include <stdio.h>
#include <math.h>
void main() {
    int i, m, n;
    scanf("%d", &m);
    n = (int)sqrt(m);
    for (i = 2; i <= n; i++) {
        if (m % i == 0) break;
    }
    if (i > n) printf("%d is a prime number!\n", m);
    else printf("%d is not a prime number!\n", m);
}
// 输入:17 输出:17 is a prime number!
  1. 百元纸币兑换
    • 问题:用一张百元纸币兑换一元、五元和十元的纸币,要求兑换后纸币的总数为20张,问共有多少种换法?每种换法中各面值的纸币分别为多少张?
    • 示例
#include <stdio.h>

int main() {
    int num_one, num_five, num_ten;
    int total_combinations = 0;

        for (num_ten = 0; num_ten <= 20/2; num_ten++) {
            for (num_five = 0; num_five <= (20 - num_ten); num_five++) {
                for(num_one = 0;num_one <= 20 - num_ten - num_five;num_one++){
					if (100 == 10 * num_ten + 5 * num_five + num_one) {
						total_combinations++;
						printf("十元的张数:%d; 五元的张数:%d; 一元的张数:%d;\n", num_ten, num_five, num_one);
                	}
				} 
            }
        }

    printf("共有%d种换法!\n", total_combinations);
    return 0;
}
  1. 水仙花数
    • 定义:所谓“水仙花数”是指一个三位数,其各位数字立方和等于该数本身,如: $ 153=1^3+5^3+3^3 $。
    • 示例
#include <stdio.h>
void main() {
    int i, j, k;
    for (i = 1; i <= 9; i++) {
        for (j = 0; j <= 9; j++) {
            for (k = 0; k <= 9; k++) {
                if (i * 100 + j * 10 + k == i * i * i + j * j * j + k * k * k) {
                    printf("%d\n", i * 100 + j * 10 + k);
                }
            }
        }
    }
}
// 输出:153 370 371 407

总结

  • 循环结构是编程中的重要概念,通过循环可以简化重复执行的代码。
  • 循环四要素:循环控制变量初始值、循环条件的设置、循环语句的编写和循环控制变量的变化。
  • C语言提供了for、while、do-while三种基本的循环语句,每种语句都有其适用的场景。
  • 循环嵌套可以处理更复杂的问题,但需要注意逻辑的正确性和变量的作用域。
  • 流程控制语句break和continue可以用于中途退出循环或跳过某次循环,但需要谨慎使用以避免逻辑错误。

备注:

因个人习惯和能力所限,该文档内容若存在表述不合理或错误之处,请大家留言多多指正

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明


标题:C语言基础 4 - 循环结构
作者:谷国信
单位:北京邮电大学世纪学院
单位:北京谷梁科技有限公司
地址:http://blog.guoxinweb.com/articles/2024/12/23/1734921783130.html