循环结构
0、引入
如果想要输出 1 行 *****************
printf("*****************\n");
如果想要输出 5 行 *****************
printf("*****************\n");
printf("*****************\n");
printf("*****************\n");
printf("*****************\n");
printf("*****************\n");
如果想要输出 1W 行 *****************,不难;使用 CV 比较麻烦;没必要,实际上只做了重复的一个事情
可不可以通过某种方式告诉计算机,让计算机来做 "重复的事情",而不是我们自己 CV 操作
---> 循环结构
循环的本质 ---> 重复!!!
当需要重复执行某些相同/相似的语句时,优先考虑使用 循环结构!!!
C 语言中有以下三种循环语句:
while
do-while
for
goto 语句本身不是循环语句,但是可以达到一个循环的效果!!!
1、goto
语法:
标志:
需要重复执行的语句块;
goto 标志;
goto 标志:
无条件的跳转到 标志位置继续往后执行
标志:
用来标识某个位置,标志 需要符合 C 语言标识符的定义,且不能为关键字;一般顶格写.
eg:
语句块1;
FLAG:
printf("*****************\n");
goto FLAG;
语句块2;
上述写法会导致一直进行跳转,也就是会一直重复执行 printf("*****************\n"); 不会结束,也就不会执行下面的语句块2.
为了不进入 死循环,goto 语句一般会与 if 语句联用,来实现指定循环次数.
标志:
需要重复执行的语句块;
if(XXX)
{
goto 标志;
}
// 其它语句块
如果 XXX 的值非零,就会执行 goto 语句;如果值为 0,不执行 goto 语句(循环结束)
eg:
int count = 0; // 定义变量时,优先初始化;使用时确保有一个准确的值
flag:
printf("*****************\n");
count++;
if(count < 10) // count <= 9,一定要注意判断的临界值!!!
{
goto flag;
}
练习:
使用 goto 语句,实现输出 1~20
2、while
语法:
while(操作数)
{
要循环的语句块; // 循环体
}
操作数:
可以是任意合法的 常量/变量/表达式/其它组合方式
循环体:
要循环的语句块,可以是 0/1/多条语句;建议不管多少条语句都加上 {};不加 {} 默认负责一条语句(复合语句)
先判断 while 后面括号中值的情况
如果 非0 时,就会执行 循环体,执行完循环体之后,又会判断 while 后面括号中的值是否 非0
......
直到while 后面括号中值为 0 / 循环体遇到 break,才会结束当前 while
eg:
while(1); // ; 空语句,一直执行空语句
{
printf("*****************\n");
}
int a = 10;
while(a)
a--; // 循环体只有 一条语句
printf("a = %d\n",a); // 一次 a = 0
int b = 10;
while(b)
printf("b = %d\n",b); // 循环体只有 一条语句,一直输出 b = 10
b--; // 执行不到的
eg:
求 1~100 的和
0 + 1 = 1
1 + 2 = 3
3 + 3 = 6
...
当前数总和 = 之前的和 + 当前数 ---> 100 次
重复的操作,考虑使用 循环实现
int i = 1; // 当前数的值
int sum = 0; // 当前数总和
while(i <= 100) // 判断 i: 1~101,进入循环i: 1~100
{
sum = sum + i; // 当前数总和 = 之前的和 + 当前数
i++; // 当前数 + 1
}
printf("sum = %d,i = %d\n",sum,i); // 5050 101
int i = 0; // 当前数的值
int sum = 0; // 当前数总和
while(i < 100) // 判断 i: 0~100,进入循环i: 0~99
{
i++; // 当前数 + 1
sum = sum + i; // 当前数总和 = 之前的和 + 当前数
}
printf("sum = %d,i = %d\n",sum,i); // 5050 100
练习:
输入一个正整数(< 15),求该数的阶乘(llu)
3、do-while
语法:
do
{
要循环的语句块; // 循环体
}while(操作数); // 注意这个分号不能省略!!!
操作数:
可以是任意合法的 常量/变量/表达式/其它组合方式
循环体:
要循环的语句块,可以是 0/1/多条语句;建议不管多少条语句都加上 {};不加 {} 默认负责一条语句(复合语句)
先执行完循环体,再判断 while 后面括号中值的情况
如果 非0 时,就会执行 循环体,执行完循环体之后,又会判断 while 后面括号中的值是否 非0
......
直到while 后面括号中值为 0 / 循环体遇到 break,才会结束当前 do-while
while 和 do-while 的区别:
do-while 至少会执行一次循环体再判断执行;while 先判断再执行(可能一次都不执行循环体)
eg:
使用 do-while 求和 1~100
int i = 1; // 当前数的值
int sum = 0; // 当前数总和
do
{
sum = sum + i; // 当前数总和 = 之前的和 + 当前数
i++; // 当前数 + 1
}while(i <= 100); // 判断 i: 1~101,进入循环i: 1~100
printf("sum = %d,i = %d\n",sum,i); // 5050 101
练习:
1、使用 do-while 求 0~1000 内偶数的和
2、输入两个正整数 x,y;求 x,y 的最小公倍数(while/do-while)
eg:
4的倍数 4 8 12 16 ...
6的倍数 6 12 18 24 ...
4,6 的最小公倍数为 12
最小公倍数的范围一定是 max[x,y] ~ x*y
穷举法:
把所有的情况一一列举出来,进行判断是否满足要求
①确定范围
max[x,y] ~ x*y
4,6 ---> 6~24
②操作计算
判断 6 是不是 4和6 的公倍数;如果是,找到了最小公倍数,如果不是
判断 7 是不是 4和6 的公倍数;如果是,找到了最小公倍数,如果不是
判断 8 是不是 4和6 的公倍数;如果是,找到了最小公倍数,如果不是
...
判断 23 是不是 4和6 的公倍数;如果是,找到了最小公倍数,如果不是
只能为 24
优化穷举的数值!!!
max(x,y) 大的数的倍数是不是小的数的倍数即可
判断 6 是不是 4和6 的公倍数;如果是,找到了最小公倍数,如果不是
判断 12 是不是 4和6 的公倍数;如果是,找到了最小公倍数,如果不是
判断 18 是不是 4和6 的公倍数;如果是,找到了最小公倍数,如果不是
判断 24 是不是 4和6 的公倍数;如果是,找到了最小公倍数,如果不是
4、for
语法:
for(操作数1;操作数2;操作数3) // 必须两个分号,不能少
{
循环体语句;
}
※※说明:
① 三个操作数可以是 常量/变量/表达式/任意组合
② 操作数1 一般称之为 "初始条件",最先执行的且只会执行一次
可以是变量的定义 / 初始化(eg: int a / int a = 2333)
③ 操作数2 一般称之为 "判断条件",决定是否执行 循环体语句
操作数2 值非0就执行 循环体语句;否则不执行,结束 for 语句
④ 操作数3 一般称之为 "改变条件",用来改变某些值,使 判断条件 趋向于不成立
⑤ 这三个操作数,可以省略 任意一个/两个/三个,分号一定不能省略
省略 操作数2,表示 "判断条件" 值非0 (需要使用 break,才能结束 for 语句)
⑥ 先执行 操作数1 有且一次,然后 判断 操作数2("判断条件") 的值是否非 0
如果 其值非0,就执行 循环体语句,再执行 操作数3("改变条件")
再判断 操作数2("判断条件")的值是否非 0,如果 其值非 0,就执行循环体语句,再执行 操作数3("改变条件")
.....
直到 操作数2("判断条件")的值为 0 / 循环体语句中遇到 break 也会结束当前的 for 语句
⑦ for 后面的语句块(循环体),用 {} 括起来;默认 只负责一个语句
eg:
使用 for 求 0~1000 内奇数的和
int i = 1; // 当前奇数的值
int sum = 0; // 当前奇数总和
for(;i < 1000;)
{
sum = sum + i; // 当前奇数总和 = 之前奇数的和 + 当前奇数
i += 2; // 当前奇数 + 2
}
printf("sum = %d,i = %d\n",sum,i);
练习:
使用 for 语句输出所有的 "水仙花数"
"水仙花数": 是一个三位数,且各个位数的立方和为本身的数
123 ---> 1 2 3
1*1*1 + 2*2*2 + 3*3*3 = 36 != 123 // 123 不是水仙花数
1 <--- 123/100 百位数值
2 <--- 123/10%10 十位数值
3 <--- 123%10 个位数值
分析:
int sum = 0; int sum = 0; int sum = 0;
int i = 1; int i = 1; int i = 1;
while(i <= 100) do for(;i <= 100;)
{ { {
sum += i; sum += i; sum += i;
i++; i++; i++;
} }while(i <= 100); }
总结上述可知:
循环语句可以相关转换!!!注意判断的临界值!!!
5、break 和 continue
continue
只能出现在循环语句中;用于跳出本次循环(continue 后续的循环体语句不会执行),继续下一次循环
break
出现在循环语句中;用于跳出当前循环语句
eg:
int i,count1 = 0;
printf("break test\n");
for(i = 0;i < 5;i++)
{
count1++;
if(count1 == 3)
{
break; // 结束 for 循环
}
printf("count1 = %d\n",count1);
}
printf("continue test\n");
int count2 = 0;
for(i = 0;i < 5;i++)
{
count2++;
if(count2 == 3)
{
continue; // coun2 == 3 不输出 结果
}
printf("count2 = %d\n",count2);
}
思考:
for(int i = 0;i < 5;)
{
if(i == 3)
{
break;
}
i++;
}
上述循环执行几次??? ---> 3次
for(int i = 0;i < 5;)
{
if(i == 3)
{
continue;
}
i++; // 当 i == 3 执行不到这里!!!
}
上述循环执行几次??? ---> 死循环
6、循环嵌套
循环语句的循环体中又出现了 循环语句,一般只有 二级嵌套;经典写法:
int count = 0;
for(int i = 0;i < 4;i++) // 外循环
{
for(int j = 0;j < 5;j++) // 内循环
{
count ++;
}
}
printf("count = %d\n",count); // count = 20
for(int i = 0;i < 4;i++) // 外循环
{
for(int j = 0;j < 5;j++) // 内循环
{
printf("%d-%d\t",i,j);
}
printf("\n");
}
练习:
输出 九九乘法表
总结
1.循环语句默认负责一个语句
普通的一条语句
复合语句 诸如 if switch while .....
建议写 {}
2.循环语句相互之间的转换
3.注意临界值
4.相关语句使用的注意事项