Day06:循环结构
定义
代码的重复执行,就叫做循环
循环的分类
- 无限循环:其实就是死循环,程序设计中尽量避免无限循环。程序中的无限循环必须可控。
- 有限循环:循环限定循环次数或者循环的条件。
循环的构成
- 循环条件
- 循环体
当型循环的实现
特点:先判断后执行,如果条件不满足,一次都不执行
代表:while和for
while
语法:
c
while(循环条件) // a>b&&b>c
{
循环许局;//如果是单语句,可以省略{}、如果是复合语句,不可以省略{}
}
说明:
1.循环条件的返回值必须是布尔类型(条件表达式只能是关系表达式或逻辑表达式)。在C语言中,布尔类型为真使用 非0
,布尔类型为假使用 0
.如果引入 #include <stdbool.h>
,也可以用true和false来表示。
2.{}包起来的内容整体称之为 循环体
。
3.我们要在循环体中控制循环条件 的变化,否则会产生死循环。
执行过程:
特点:先判断,后执行,循环体语句有可能一次不执行
案例
c
#include <stdio.h>
/*
如何编程来计算1+2+3...+100(累加求和)
*/
int main()
{
//定义一个变量,保存累加的和
int sum = 0;
//定义一个循环变量
int i = 1;
while(i<=100)//循环条件,这里可以有关系表达式、逻辑表达式、整型常量
{
//累加运算
//sum =sum +i;
sum += i;
i++;
//给循环变量赋值,用来影响循环条件
}
printf("1-100的累加和是:%d\n",sum);
return 0;
}
死循环
c
while(1)//我们会在死循环进行必要的限制
for
原则上,for循环能实现的while循环一定可以实现,for循环可以看做是while循环的一种特殊写法。
语法:
c
for(①表达式1;②表达式2;③表达式3)
{
①循环体语句; --如果是单语句,可以省略{};如果复合语句,必须保留{}
}
说明:
1.()中可以只保留两个 ;;
,举例for(;;)
2.①(表达式1)是循环变量,我们需要赋初值,循环变量可以是列表,多个循环变量使用逗号分隔,举例:int i=0,j=0
3.②(表达式2)是循环条件,用来限制循环的次数,循环条件支持关系表达式,如果加入逻辑表达式,会变成复合表达式,举例:i<10 &&j<=i
4.③(表达式3)改变循环条件,支持列表,这里可以使用赋值表达式,举例: i++,j++
5.执行顺序:①②④③→②④③→②④③→...→②
执行过程:
特点:
先判断,后执行,循环语句可能一次不执行
c
#include <stdio.h>
int main()
{
for(int i=2;i<100;i+=2)
{
sum+=i;
}
printf("偶数和的结果是:%d",sum);
return 0;
}
总结
- for语句使用语法规则上,降低/避免因为忘记循环条件更新操作;而引起的产生无限循环的几率。
- 应用场合:for语句往往应用于次数事先可以确定的场景。
死循环
c
for(;;);
for(表达式1;;表达式2);
循环实现三要素
- 循环变量的初始值
- 循环条件
- 循环变量的更新
案例
c
#include <stdio.h>
#include <math.h>
/**
* 需求:for循环案例-求斐波拉契数列前20个数
* 分析:1,1,2,3,5,8...
*/
int for_test2()
{
int f1 = 1;// 前一个数,默认是1,因为第一个是1
int f2 = 1;// 后一个数,默认是1,因为第二个是1
int i = 1;// 循环变量
for(; i <= 10; i++)
{
printf("%12d%12d\n",f1,f2);
// 一行显示两个数,每两个换行 1 1 2 3 5 8
//if(i % 2 == 0)
//{
// printf("\n");
//}
f1 += f2; // f1 = 2 = 1 + 1
f2 += f1; // f2 = 3 = 1 + 2
}
}
int main(int argc,char *argv[])
{
for_test2();
}
return 0
直到型循环的实现
特点:先执行,后判断
代表:do...while
do...while
语法:
c
do
{
循环体;
}while(循环条件);
说明:
1.循环条件的返回值必须是布尔类型,在C语言中,布尔类型为真使用 非0
来表示。
2、{}包起来的内容整体称之为 循环体
3、我们要在 循环体中控制循环条件的变化,否则会产生死循环。
执行过程:
特点;先执行,后判断,不管满不满足条件,都要先执行一次
goto
语法:
c
goto 标签(label);
标签:标明
注意事项
1.可读性: goto 语句会破坏代码的结构和可读性,使得代码难以理解和维护。因此,应尽量避免使用。
2.替代方案:大多数情况下,可以使用循环、条件语句、函数等结构来替代 goto 语句,使代码更加清晰和易于管理。3.嵌套限制:虽然 goto 语句可以跨函数跳转(即跳转到另一个函数中的标签),但这种用法是不合法的,并且会导致编译错误。goto 语句只能在同一函数内部跳转。
4.错误处理:在某些情况下, goto 语句可以用于错误处理,例如从嵌套的多层循环中跳出。但即使在这种情况下,也应谨慎使用,并考虑是否有更好的替代方案。
循环的嵌套
3种循环(while、do...while、for)可以相互嵌套,在前一个循环结构的内部又存在一个完整的循环结构。如:
案例:
c
#include<stdio.h>
/*
需求:嵌套for循环案例-求100~200之间的所有素数
分析:只能被1和自身整除的数叫做素数
*/
int main()
{
// 创建一个变量,存放100~200之间的自然数
int num = 100;
// 循环变量,默认从2开始,因为自然数除以1没有意义
int i;
// 定义标志位:用来记录1~自身之间的能整除的次数,用来校验该自然数是否为素数
// 第1层for循环:生成100~200之间的自然数
for(;num <= 200;num++)
{
// 每个自然数在判别之前,需要重置标志位
is_flag = 1;
// 第2层for循环:验证该自然数能否被除了1~自身之间的数整除,能整除,就改变is_flag的值
// for(i = 2;i < num -1;i++
for(i = 2;i < num / 2;i++)
{
// 校验是否能整除
if(num % i == 0)
{
is_flag = 0;
break;// 只校验第一个能整除的数
}
}
// 根据标志位,判断该自然数是否是素数
if (is_flag) // 条件判断:is_flag == 1 缩写 is_flag(推荐) is_flag == 0 缩写 !is_flag
{
printf("%-4d",num);
}
}
printf("\n")
return 0;
}
循环结构的典型应用场景
-
求累和:举例 1+2+3+...+100的和
-
求累乘:举例123*...*100的积
-
求均值:举例(1+2+3+...+100)/100的值
-
求极值:举例、12,34,56,67中的最大值或者最小值
-
元素遍历:常用于数组元素的遍历
基础算法模型
-
累加和
-
定义一个变量(sum),并赋初值为0;
-
该变量累加(+=)每一个数据项(i);
-
当访问完每一个数据项,此时该变量的取值就是累加和的结果。
-
-
累乘
- 定义一个变量,并赋初值为1;
- 用该变量累乘(*=)每一个数据项;
- 当访问完每一个数据项,此时该变量的取值就是累乘的结果
-
极值(多用于数组)
- 定义一个变量,并赋初值为第一个数据项;
- 从第二个数据项开始,依次于该变量进行比较,如果大于/小于该变量,则将当前数据项的数据赋值给该变量。
- 当访问完每一个数据项,此时该变量的取值就是求极值的结果。
-
break和continue
-
break
功能:
①用在switch中,用来跳出switch的case语句:如果case没有break,可能会产生case穿透。
②用在循环中(while、do...while、for),提前结束循环,也就是跳出整个循环。
说明:
①break不能用于循环语句和switch语句之外的任何其他语句之中。
②break只能终止并跳出最近一层的循环结构。
流程图:
案例1:
c#include <stdio.h> /** * 需求:break案例-输出1~100以内的偶数,只能输出前10个 */ int break_test() { for(int i = 1,count = 1; i <= 100; i++) { if(i % 2 == 0) { if(count > 10) { break; } count ++;// 用来计数 printf("%d\t",i); } } printf("\n"); } int main(int argc,char *argv[]) { break_test(); return 0; }
-
continue
功能:continue语句不会结束整个循环,而是跳过本次循环尚未执行的语句,进入下一次循环。
说明:
①仅用于循环语句中。
② 在嵌套循环的情况下,continue语句只对包含它的最近的一层循环起作用。
图示:
案例:
c#include <stdio.h> /* 求1-100以内的偶数和 */ int continue_test1() { int sum = 0; for(int i = 1; i<=100;i++) { if(i%2 !==0) { comtinue; } sum+=i; } printf("1-100以内的偶数和是%d\n",sum); } int main() { continue_test1(); }
-
跳出多层循环
跳出多层循环是不能直接使用break和continue实现的,因为它们只能跳出单层循环,跳出多层循环,需要我们自定一定标志位进行跳出(标志位也可以配合break使用)。
案例:
c#include <stdio.h> int fun0() { // 定义一个标志位 int is_flag = 1;// 默认循环成立 // 定义一个变量,用来接收控制台输入 char fu; // 循 while(is_flag) { printf("外层循环执行的内容..\n"); while(is_flag) { printf("内存循环执行的内容..\n"); scanf("%c",&fu); if(fu == 'Y' || fu == 'y') { is_flag = 0; } } } } int fun1() { // 定义一个标志位 int is_flag = 1;// 默认循环成立 // 定义一个变量,用来接收控制台输入 char fu; // 循环 while(is_flag) { printf("外层循环执行的内容..\n"); while(1) { printf("内存循环执行的内容..\n"); scanf("%c",&fu); if(fu == 'Y' || fu == 'y') { is_flag = 0; break; } } } } int main() { fun0(); fun1(); }
注意:
层循环执行的内容...\n");
while(1)
{
printf("内存循环执行的内容...\n");
scanf("%c",&fu);
if(fu == 'Y' || fu == 'y')
{
is_flag = 0;
break;
}
}
}
}
int main()
{
fun0();
fun1();
}
注意: 如果是多层循环(嵌套循环),进的时候是从外到内,跳出的时候是从内到外。
-
-
-
上机题
- 计算n以内所有正奇数的和 ? n值通过键盘输入
- 计算 1 + 1/(2 * 3) + 1/(3 * 4) + .+ 1/(n * (n + 1)) = ?直到最后一相值小于0.00001为至。
- 计算1+1/2 - 1/3 + 1/4 - 1/5 .+1/n= ? n通过键盘输入(int k = -1)
- 计算n的阶乘 ? n值通过键盘输入
- 输出半径为1~10的圆面积,面积大于100时停止
- 求输入的十个整数中正数的个数及其平均值
- 打印出100以内能整除7之外的的自然数
- 打印乘法表
- 我国古代数学家张丘建在《算经》一书中提出的数学问题:鸡翁一值钱五,鸡母一值钱三,鸡 雏三值钱一。百钱买百鸡,问鸡翁、鸡母、鸡雏各几何?
- 从键盘上输入多个无符号整型数据,直到 0 结束 ,输出所输入数据中的最大值。