当前位置:   article > 正文

C的实用笔记7——循环控制语句_控制循环次数

控制循环次数

目录

while循环控制语句

for循环控制语句

循环控制语句的简单使用

用break提前结束整个循环

用continue提前结束本次循环

循环嵌套

习题总结


while循环控制语句

while循环和if选择语句很像,都是在条件表达式为真的时候才执行复合语句中的代码。不同的是if语句只执行一遍,while循环可以根据需要指定循环次数。分为两种:

  1. while循环:while可以理解为当满足条件时,就一直做我们通过习题9、来巩固该知识点(代码心得在13、14、15、16)
  2. o while循环:与while不同的是,do while是先执行一次,然后再进行条件判断。按照我们平时的语言逻辑,do while可以理解为一直做某一件事直到什么事情发生就停止下来。因此,以下两种方式等价。

for循环控制语句

我们经过while循环语句的学习,可以认识到循环控制语句实际上有三个重要表达式

  1. 表达式一:循环开始前,条件的初始化
  2. 表达式二:条件的临界值
  3. 表达式三:一次循环后,条件的变化

 见下面例子。

                                

 实际上,我们可以将这三个表达式换一种写法,这时候就可以用for循环语句,for循环语句和while循环语句是无条件等价:
    for循环语句格式为:        for(表达式1; 表达式2; 表达式3) { 循环体; }    //注意是表达式之间用分号,不是逗号。再要注意 for(){} 后面不加分号

                                              

 for循环和while循环的流程图:

                                                     

 for循环的几个变体:见怪不怪

形式一(和while循环语句完全相同):表达式1挪到外面去,表达式3挪到循环体中去,表达式2不挪动。
  注意:记得分号保留。

                                                

形式二(死循环):没有表达式2,也就是没有判断条件
形式三(瞎搞):直接将定义语句写在表达式1中。
  注意:C99支持这种写法,Java和C++中也是这种写法。

                              

 形式四(空循环体):把表达式3写成逗号表达式
  注意:这种情况for语句后要加分号,表示循环体为空,这是因为不加分号,会默认下一条语句是循环体。

                          

 形式五(for循环的双循环变量法减少循环次数):把表达式1写成逗号表达式,写入两个循环变量 head 和 tail 。我们可以看习题11(习题9的改良),体会该用法。
注:用while循环当然也可以。

循环控制语句的简单使用

  1. 计算简单级数
    1. 简单正向级数:我们之前已经学习过了,可以看习题9习题11
    2. 简单交错级数:交错级数(也就是正一项,负一项),此时我们除了要定义循环变量外,还需要定义一个循环标志变量flag,它专门用来确定循环过程中每一项的正负号。我们可以通过习题12,来体会这一用法
  2. 辗转相除法计算两个整数的最大公因数、最小公倍数:见习题13
  3. 用循环实现遍历习题14习题15

用break提前结束整个循环

原本我们是通过循环的条件表达式来判断是否进入或者跳出循环,而break的作用就是当循环变量没有到达临界值时,可以提前结束循环。break被放置在循环体中,通常结合选择控制语句来使用

    例题:我们通过 习题16(捐款)习题17(判断素数),来巩固该知识点。

用continue提前结束本次循环

在本次循环中,continue用来跳过它后面的循环语句。continue被放在循环体中,通常也是结合选择控制语句来使用的。如果continue后面没有代码了,那么也起不到什么作用。

    例题:我们通过 习题18,来巩固该知识点。

循环嵌套

我们很容易想明白,第一点:循环嵌套肯定是要用到多个循环变量,但他的用法不同于我们双循环变量法减少循环次数中的那样;第二点:外层的循环肯定是要等内层的循环完成了,才会继续下去,可见循环的次数是相乘的关系。

    打个比方:我们在方格纸上写字,我们是不是要从上往下,从左往右写?那么,我们可以进行类比:写字就是一个两层的循环嵌套。当我们换行书写时,就相当于外层循环,行数是外层循环变量;当我们书写某一行时,就相当于内层循环,列数是内层循环变量。

    循环嵌套可以做什么?我们看以下习题来巩固该知识点:

  1. 输出矩阵: 习题19(九九乘法表)
  2. 遍历求解多元线性方程组习题20(百元买鸡问题)。
  3. 多条件下遍历所有可能情况:习题21(考试排考)。

习题总结

1、代码心得

  1. 用scanf从键盘获取值时,要注意内存越界,因为变量的数据类型限定了它所能存储的数值大小。
  2. if() .... 选择控制语句中,括号里的条件语句在计算机中终究会变成1和0,1代表你说的是真的,0代表你说的是假的,因此括号里的条件语句可以是表达式,表达式的值如果是非0数值,则表达式为真;表达式的值如果是0值,则表达式为假。
  3. 两个等号“==”才表示等于关系,一个等号“=”则是赋值的意思,混着用会发生逻辑上的判断错误
  4. 我们一开始写程序,如果问题有点复杂,那么我们可以用自然语言先在编辑器中写下个思路,写的时候像程序那样缩进显示,方便我们理清思路,写完后,再往里面添加程序即可。注意一点,如果仅仅为了写程序,可以用自然语言,像跟别人谈话一样,这样写程序快;如果为了做示意图,我们可以采用流程图的方式来展现。可读性上自然语言更适合人类,而直观性上流程图更好。更复杂一点,如果是在业务场景里面,我们就得用xmind这类思维导图了,因为自然语言和流程图无法满足我们庞大的需求了。
  5. 有的公司会规定写代码的规范,比如变量名前面写个'c',代表字符型;前面写个'i',代表整型。等等。
  6. if ... else if ... else .. 多分支选择语句中逻辑稍微有点复杂,所以一定要注意大括号的对齐
  7. if语句的嵌套使用时,if也总是和离它最近的else配对,所以在实现复杂选择控制时要养成加大括号的习惯。同时,我们用自然语言或者思维导图理解后,嵌套语句先从最外层的if...else...开始写,即写了一个if后不要着急写复合语句里面的内容,而是现将与if配对的else打上去,防止出错
  8. 对于简单的双分支if语句,我们其实可以也可以用条件运算符来写。
  9. 使用switch语句时,最好不要把case后面的break漏掉,如果漏掉,那么执行完上一个case后不会退出,反而会继续向下运行其他case下的代码,所以必要的时候,即当你的expression满足case1或case2时希望做相同的事情,可以如下书写:                                                                                                                                                                           
  10. switch语句中,括号里的expression不会变成1或0,因为这个表达式要去和case中的具体情况作配对。
  11. switch语句中,括号里的表达式必须是整型或者字符型,他不会识别浮点型和字符串。
  12. 使用switch时,我们通常会用到除法运算符
  13. 循环语句中,括号里的条件表达式和if语句中的条件表达式一样,最后都会变成1或0
  14. 死循环内如果有动态内存申请,那么极有可能把内存消耗殆尽。如果我们遇到了死循环,我们要在命令提示符中按ctrl C,才能强制结束程序。
  15. 我们使用是循环控制语句时,通常要定义一个循环变量(要有初始值),它放在循环体中,目的是控制循环的次数,因此常常在循环体中用自加自减运算符赋值及扩展运算符,来改变循环变量的值,使用时要注意循环的次数,因为循环变量从0开始和从1开始是不一样的。
  16. 循环语句中,如果一个变量只是为了循环(控制循环次数),那么我们也不关心他叫什么名字,习惯叫诸如:i、j、k这种变量名;如果一个变量在循环中起到某种作用,那么需要给它起上一个通俗的名字,并且打上注释,说明其含义,以及它是一个循环变量。
  17. 我们定义变量时,尽量将它初始化,这是一个编程习惯;否则,以“用循环方法求级数的和”这类问题(比如习题9、习题11)为例,我们可以预见如果不给sum赋初值,那么这个变量的值就是随机的。

习题9:计算级数 12+22+32+ ··· ···  的前10项和。

  1. 思路:循环变量也参与求和运算且它从1开始(因为从12开始加)
  2. 代码:
    1. #include <stdio.h>
    2. int main(int argc, char const *argv[])
    3. {
    4. int times = 1; //既作为循环变量,又作为求和变量
    5. int sum = 0; //和,这里一定要初始化
    6. while (times <= 10)
    7. {
    8. sum = sum + times*times;
    9. times++;
    10. }
    11. printf("1^2+2^2+...+10^2的值为: %d\n", sum);
    12. return 0;
    13. }

习题11:计算级数 12+22+32+ ··· ···  的前terms项和,这里terms要求用户输入。

  1. 思路:对习题9改良(用双循环变量法减少循环次数)、同时要考虑terms为奇数时会多加一项
    1. 1. 输入简单级数的求和项数
    2. 2. 双循环变量法,head <= tail 时进入循环
    3. 2.1 从级数首、尾同时求和
    4. 2.2 改变两个循环变量
    5. 3. 判断i和j是否差2(因为项数存在奇偶,若是奇数项,循环结束后i比j大2,偶数项则没问题)
    6. 3.1 如果是
    7. 那么,循环求和结果减去重复项
    8. 4. 显示求和结果

  2. 代妈:
    1. #include <stdio.h>
    2. int main(int argc, char const *argv[])
    3. {
    4. int terms; //级数求和项数
    5. int sum = 0;
    6. int head, tail; //双循环变量
    7. puts("确认你想求和的项数");
    8. scanf("%d", &terms);
    9. for ( head = 1, tail = terms; head <= tail; head++, tail--)
    10. {
    11. sum += head*head + tail*tail;
    12. }
    13. if (head - tail == 2)
    14. {
    15. sum -= (head-1)*(head-1);
    16. }
    17. printf("1^2+2^2+...+%d^2的值为: %d\n", terms, sum);
    18. return 0;
    19. }

习题12:计算交错级数: 的前10项和:

  1. 思路:由于每一项与用于控制循环次数的变量i不存在直接关系但是可以找到i与分母的关系,所以这类问题还要考虑其他变量,第一个是代表每一项绝对值的变量term,第二个是代表每一项符号的变量flag。
    1. 1. while循环,在i <= 10的时候进入循环
    2. 1.1 改变循环变量term的值(此时term是级数的第i项的绝对值)
    3. 2.2 求和
    4. 2.3 改变循环变量flag的值(此时flag是级数的第i项前的符号)
    5. 2.4 改变循环变量i
    6. 2. 打印结果

  2. 代码:
    1. #include <stdio.h>
    2. int main(int argc, char const *argv[])
    3. {
    4. int i = 1; //循环变量,仅用于控制循环次数
    5. double term = 1; //代表某一项的循环变量
    6. double sum = 0;
    7. double flag = 1; //表示符号的循环变量
    8. while (i <= 10)
    9. {
    10. term = 1.0/(2*i-1);
    11. sum += flag*term;
    12. printf("%lf\n", term); //小技巧,相当于断点调试功能
    13. flag = -flag;
    14. i++;
    15. }
    16. printf("sum = %lf\n", sum);
    17. return 0;
    18. }

习题13:输入两个整数,用辗转相除法求解它们的最大公因数,最小公倍数 

  1. GCD算法详解:并以求98和63的最大公因数为例。①九章算术中说道【更相减损术】: “可半者半之,不可半者,副置分母、子之数,以少减多,更相减损,求其等也。以等数约之。”,翻译为:(如果需要对分数进行约分,那么)可以折半的话,就折半(也就是用2来约分)。如果不可以折半的话,那么就比较分母和分子的大小,用大数减去小数,互相减来减去,一直到减数与差相等为止,用这个相等的数字来约分。②线性代数/一元多项式环/整除关系中说道【辗转相除法】:两个一元多项式f(x)、g(x),一定有f(x)=h(x)g(x)+r(x),此时求解f(x)和g(x)的最大公因式,可以转换为求解g(x)和r(x)的最大公因式。
  2. 思路:我们以辗转相除法为例
    1. 1. 输入两个整数,分别保存在dividend(被除数)和divisor(除数)中
    2. 2. 保存两个整数的乘积
    3. 3. 判断除数是否大于被除数
    4. 3.1 如果是
    5. 那么,交换它们,保证被除数大于除数
    6. 4. 取出这两个数的余数,记为rem
    7. 5. while循环,当rem不为0时进入循环
    8. 5.1 改变循环变量dividend,上一次除数作为下一次的被除数
    9. 5.2 改变循环变量divisor,上一次余数作为下一次的除数
    10. 5.3 改变循环变量rem
    11. 6. rem为0,循环结束,此时的除数就是最大公因数,输入的两个数的乘积除以这个最大公因数就是最小公倍数
    12. 7. 打印输入的两个数的最大公因数和最小公倍数

  3. 代妈:
    1. #include <stdio.h>
    2. int main(int argc, char const *argv[])
    3. {
    4. int dividend; //被除数,作为循环变量
    5. int divisor; //除数,作为循环变量
    6. int rem; //余数,作为循环变量
    7. int dataSmall; //临时变量, 保证被除数比除数大
    8. int product; //被除数和除数的乘积
    9. puts("请输入两个数");
    10. scanf("%d %d", &dividend, &divisor);
    11. product = dividend * divisor;
    12. if (divisor > dividend)
    13. {
    14. dataSmall = dividend;
    15. dividend = divisor;
    16. divisor = dataSmall;
    17. }
    18. rem = dividend % divisor;
    19. while (rem != 0)
    20. {
    21. dividend = divisor;
    22. divisor = rem;
    23. rem = dividend % divisor;
    24. }
    25. printf("这两个数的最大公因数为%d\n", divisor);
    26. printf("这两个数的最小公倍数为%d\n", product / divisor);
    27. return 0;
    28. }

习题14:将一个正整数每位加5,若相加超过9,则保留个位,最后逆序输出,比如输入2645后,输出0917。

  1. 思路:结合取余运算符和除法运算符取出一个正整数的每一位
    1. 1. 输入正整数x
    2. 2. while循环,在x不等于0时进入循环
    3. 2.1 取出x的最后一位,加5,再取个位
    4. 2.2 打印刚才得到的数
    5. 2.3 改变循环变量x,舍弃掉x的最后一位
  2. 代妈:
    1. #include <stdio.h>
    2. int main(int argc, char const *argv[])
    3. {
    4. int x; //输入的数,作为循环变量
    5. int y; //每一位转化后的数
    6. printf("请输入一个正整数:");
    7. scanf("%d", &x);
    8. while (x != 0)
    9. {
    10. y = ((x % 10) + 5) % 10;
    11. printf("%d", y);
    12. x = x / 10;
    13. }
    14. return 0;
    15. }

 

习题15:列出0~999中所有的水仙花数,若一个正整数等于其各位数字的立方和,那么这个数称为水仙花数。

  1. 思路:结合取余运算符和除法运算符取出一个正整数的每一位
    1. 1. for循环, 让i从0遍历到999
    2. 1.1 获取i的个位
    3. 1.2 获取i的十位
    4. 1.3 获取i的百位
    5. 1.4 判断是否是水仙花数
    6. 1.4.1 如果是
    7. 那么,打印出来
  2. 代妈:
    1. #include <stdio.h>
    2. int main(int argc, char const *argv[])
    3. {
    4. int i; // 0~999的数
    5. int a, b, c; //分别存储i的个位、十位、白位
    6. for (i = 0; i <= 999; i++)
    7. {
    8. a = i % 10; // 个位
    9. b = i / 10 % 10; // 十位
    10. c = i / 100; // 百位
    11. if (i == a * a * a + b * b * b + c * c * c)
    12. printf("%d是个水仙花数\n", i);
    13. }
    14. return 0;
    15. }

习题16:不限次数捐款,但是当捐款总数超过10万元后,不再接受捐赠,最后统计捐款总额、人数。

  1. 思路:捐款总额超过10万元后用break提前退出循环 
    1. 1. for循环,循环变量是捐赠人数(从1开始),可以缺少表达式2(死循环)
    2. 1.1 输入本次捐赠数目
    3. 1.2 计入捐款总额之中
    4. 1.3 判断总额是否大于10万元
    5. 1.3.1 如果是,
    6. 退出循环
    7. 2. 打印当前捐款总额和捐款人数

  2. 代码:
    1. #include <stdio.h>
    2. int main(int argc, char const *argv[])
    3. {
    4. int numOfPeople;
    5. float totalMoney = 0;
    6. float donations;
    7. for ( numOfPeople = 1; ;numOfPeople++)
    8. {
    9. puts("请输入捐款的数目");
    10. scanf("%f", &donations);
    11. totalMoney = totalMoney + donations;
    12. if (totalMoney >= 100000)
    13. {
    14. break;
    15. }
    16. }
    17. printf("累计捐款%.2f元,超过10万元,不再接受捐款\n", totalMoney);
    18. printf("总捐款人数是:%d\n", numOfPeople);
    19. return 0;
    20. }

习题17:输入一个正整数,判断它是否是素数,若一个数只能被1和其自身整除,那么这个数就是素数,否则为合数。

  1. 思路:①如果这个数能被某个数整除,那么用break提前退出循环,因为它已经是合数了;②使用sqrt函数可以减少遍历次数,因为对于一个正整数m,若能进行因式分解,那么这两个数的分布一定是一个在2到√m,另一个在√m到m。因此循环变量divisor从2到√m。
    1. 1. 输入一个正整数ddata
    2. 2. for循环遍历,循环变量divisor从2开始,小于等于ddata的算术平方根时进入循环
    3. 2.1 判断这个正整数是否能整除divisor
    4. 2.1.1 如果能,
    5. 那么,它不是质数,令质数标志=0
    6. break,退出循环
    7. 3. 判断质数标志是否为1
    8. 3.1 如果是,
    9. 那么,该数是质数
    10. 3.2 否则,
    11. 那么,该数是合数

  2. 代码:
    1. #include <stdio.h>
    2. #include <math.h>
    3. int main(int argc, char const *argv[])
    4. {
    5. int ddata; //输入的整数
    6. int divisor; //被除数,作为循环变量
    7. int primeYesOrNot = 1; //先默认是质数
    8. printf("请输入一个整数:\n");
    9. scanf("%d", &ddata);
    10. for (divisor = 2; divisor <= sqrt(ddata); divisor++){
    11. if (ddata % divisor == 0)
    12. {
    13. primeYesOrNot = 0;
    14. break;
    15. }
    16. }
    17. if (primeYesOrNot == 1){
    18. printf("%d是质数\n", ddata);
    19. }else{
    20. printf("%d是合数\n", ddata);
    21. }
    22. return 0;
    23. }

习题18:统计10个非零的输入值的和。也就是当输入的值是0时,要求这次重新输入,最后计算这些值的和。

  1. 思路:while循环语句、continue。
    1. 1. while循环,10
    2. 1.1 输入整数
    3. 1.2 判断输入的整数是否是0
    4. 1.2.1 如果是
    5. 那么,要求用户重新输入
    6. continue,回到循环开头,不执行1.31.4
    7. 1.3 求和
    8. 1.4 改变循环变量
    9. 2. 打印输入数的和

    代码:

    1. #include <stdio.h>
    2. int main(int argc, char const *argv[])
    3. {
    4. int times = 0; //循环变量
    5. int m; //键盘输入的值
    6. int sum; //求和
    7. while (times < 10)
    8. {
    9. printf("请输入第%d个非零整数\n", times+1);
    10. scanf("%d", &m);
    11. if (m == 0)
    12. {
    13. puts("请重新输入");
    14. continue;
    15. }
    16. sum += m;
    17. times++;
    18. }
    19. printf("结果是%d\n", sum);
    20. return 0;
    21. }

习题19:输出下三角矩阵“99乘法表”。

  1. 思路:循环嵌套、由于是下三角矩阵,所以需要注意每一行的列数等于该行的行号、注意对齐方式
    1. 1. for循环,当行号i<=9时,进入循环
    2. 1.1 for循环,当列号j<=行号i时,进入循环
    3. 1.1.1 打印i*j的大小
    4. 1.2 打印完一行后换行
  2. 代码:
    1. #include <stdio.h>
    2. int main(int argc, char const *argv[])
    3. {
    4. int i; //行
    5. int j; //列
    6. for(i = 1; i <= 9; i++){
    7. for(j = 1; j <= i; j++){
    8. printf("%d*%d=%-2d ",i, j, i*j);
    9. }
    10. putchar('\n');
    11. }
    12. return 0;
    13. }

习题20(百元买鸡问题):用100元去买100只鸡,假设母鸡3元/只,公鸡2元/只,小鸡0.5元/只,请问有几种购买方案?

  1. 思路: 
    1. 1. for循环,当公鸡数x <=33时,进入循环
    2. 1.1 for循环,当母鸡数y <=50时,进入循环
    3. 1.1.1 用x、y这两个主变量确定小鸡数z这个自由变量(方程一)
    4. 1.1.2 判断x、y、z是否满足方程二
    5. 1.1.2.1 如果满足,
    6. 那么,显示公鸡、母鸡、小鸡分别有多少个

  2. 代码:
    1. #include <stdio.h>
    2. int main(int argc, char const *argv[])
    3. {
    4. int x, y, z;
    5. for (x = 0; x <= 33; x++){
    6. for (y = 0; y <= 50; y++){
    7. z = 100 - x - y;
    8. if (3*x+2*y+0.5*z == 100){
    9. printf("公鸡%d只,母鸡%d只,小鸡%d只\n", \
    10. x, y, z);
    11. }
    12. }
    13. }
    14. return 0;
    15. }

 

习题21(考试排考问题):高校期末有英语、计算机、高等数学这三门考试,排考要求如下:①周一到周五考试;②每天最多一门考试;③高数考试时间这三门里最早;④计算机不能在周四考;

  1. 思路:有三门课,并且这三门课没有直接的关系,因此我们可以认为这三门课都是主变量,要用三层循环
    1. 1. for循环,循环变量math从1开始,<=3时进入循环
    2. 1.1 for循环,循环变量english从math+1开始,<=5时进入循环
    3. 1.1.1 for循环,循环变量computer从math+1开始,<=5时进入循环
    4. 1.1.1.1 判断计算机和英语是否不在一天,并且计算机不在周四
    5. 1.1.1.1.1 如果是,
    6. 那么,打印方案情况
    7. 让count自加1,用于保存方案个数
    8. 2. 打印一共有几种方案

  2. 代码:
    1. #include <stdio.h>
    2. int main(int argc, char const *argv[])
    3. {
    4. int math, english, computer;
    5. int count = 0; //排考方案数
    6. for (math = 1; math <= 3; math++){
    7. for (english = math + 1; english <= 5; english++){
    8. for (computer = math + 1; computer <= 5; computer++){
    9. if (computer != english && computer != 4){
    10. count++;
    11. printf("周%d考高数,周%d考英语,周%d考计算机\n", math, english, computer);
    12. }
    13. }
    14. }
    15. }
    16. printf("总共有%d种排考方案\n", count);
    17. return 0;
    18. }

 

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/一键难忘520/article/detail/896457
推荐阅读
相关标签
  

闽ICP备14008679号