C语言_4 循环结构;一些例题

简介: 循环结构;一些例题的讲解

4.1.1 循环

写程序在写的是步骤,一步一步走。
判断一个数的位数
人vs计算机
人一看就出来了,很快啊
计算机:判断数的范围来确定数的位数(100~999范围内是三位数)但人对数字处理比文字弱
但是位数太多也不能用这种方法了。改用一步步查位数的方法。
所以从最左边开始约,每次约一位,

if(n!=0)
{
    n/=10;i++;
}
if(n!=0)
{
    n/=10;i++;
}

……不过这样也是无限循环。
所以我们可以引入新函数,while。条件满足,就会不断重复大括号里的内容。
(尝试的时候不要拿太大的数去试,计算机里的整数是有范围的。)

4.1.2 while循环

数字位数的算法

  1. 用户输入x;
  2. 初始化n为0;
  3. X/=10,去掉个位;
  4. cnt++;
  5. 如果x>0,回到3;
  6. 否则cnt就是结果。

do-while循环:进入循环的时候不做检查,而是执行完一轮循环体的代码之后再来检查循环条件是否满足,满足的话继续,不满足的话结束循环
(while();最后一定要有分号!!!)
while和do while很像,区别在于do while在循环体执行结束时才来判断条件。也就是说无论如何,循环都会执行至少一遍。

4.1.3 do-while循环

if和while的区别在于,if判断只一次,不管结果如何都结束了。
While一定要有结束循环的条件!!否则会一直循环,超时
While可以翻译为当。循环有可能一次都没有被执行。条件成立是循环成立的条件。
如何看出程序运行结果?
人脑模拟计算机的运行,在纸上列出所有变量,随着程序的进展不断重新计算变量的值。当程序运行结束时,留在表格最下面的就是程序的最终结果。
测试程序常常使用边界数据,如有效范围两端的数据、特殊的倍数等等。
(此题求位数,特殊数据可以是个位数、10、0、负数)
然后可以发现,0是1位数,但是用while算法的话算出来是0位数。那我们可以用do-while就能得到1位数了。
或者if(x>0),做while;else位数=1,单独列出x=0的情况。
另一种调试方法:在适当的位置加上printf输出
作用不只有输出数据。比如在while括号内加一个printf(“in loop”);证明程序到这个地方了,也就是进入while循环了(还可以看循环了几次)

4.2.1 循环计算

编程难在小问题。
如:有的时候可能需要保存原始数据。
求log2x:x/=2,计数(当x>1时)
但是如果printf(“log2 of %d is %d.”,x,计数);最后输出的x总是1,因为循环算完的时候x总是1
所以我们开始要把原始的x保存一下。又是一个小细节~诸如此类,还有很多。
如:

  • While可以用do while吗?
  • 为什么计数从0开始,可以从1开始吗?
  • 为什么while判断条件是x>1?
  • 循环最后输出的是多少?
#include<stdio.h>
int main()
{
    int x,ret=0;
    scanf("%d",&x);
    int t=x;
    while(x>1){
        x/=2;
        ret++;
    }
    printf("log2 of %d is %d.",t,ret);
    return 0;
}

其实都是相互牵扯的。
1、 当x=1的时候,结果是0.也就是说我们希望当x=1时不要进入这个循环。
2、 计数ret是我们希望进入这个循环是最小的数。
如果想改成while(x>2),那我们的计数ret就要相应改成初始值=1.但是x=1时条件不满足。为了兼顾两种情况,还得用上面的方法。
也可以ret=-1,while(x>0)
编程肯定会有很多不同的方法。
对于很大次数的循环,我们可以模拟较少的循环次数,然后做出推断,解决上面提到的四个问题。因为很多小细节,要多加注意。

4.2.2 猜数游戏

计算机想一个数,用户来猜,猜不对的话告诉用户大了还是小了,最后猜中了告诉用户猜了多少次。

1) 因为要不断重复去猜,所以我们要用到循环
2) 实际写出程序之前,我们可以先用文字描述出程序的思路。
3) 核心重点是循环的条件。
4) 人们往往会考虑循环终止的条件。

flowchat
st=>start: 开始
i=>inputoutput: 用户输入猜的数
ocnt=>operation: count++
o=>operation: 计算机随机想一个数,记在number里
c=>condition: 判断a是否等于number
e=>end: 结束
o2=>inputoutput: 告诉用户大了还是小了
oe=>operation: 输出cnt猜的次数

st->o->i->ocnt->c
c(yes)->oe->e
c(no)->o2(right)->i

循环的条件是a!=number
用函数rand()召唤随机整数
使用方法:

//先加入两个头文件#include<stdlib.h>和#include<time.h>
#include<stdio.h>
#include<stdlib.h>
#include<time.h>
int main()
{
    srand(time(0));//Main里加上srand(time(0));  先不用管什么意思
    int a=rand();//如果想要a是100以内的整数:用取余即可(a%=100)
    int number=rand()%100+1;//这样召唤出来的数范围是1~100
    //不管怎样用户都要进入这个循环,输入至少一个数;所以应该用do-while循环。
}

4.2.3 算平均数

读入一系列正整数,输入-1时终止。然后输出他们的平均数
变量->算法->流程图->程序
num:我们需要读到的那一个数。
sum(总和):每读到一个数把他加到sum里就完事了
另一个变量count记录累加的次数,最后算平均数÷count

flowchat
st=>start: sum=0,cnt=0
i1=>inputoutput: 读num
c=>condition: num!=-1?
o=>operation: sum+=num, cnt++
op=>inputoutput: 计算和打印结果
e=>end: end
st->i1->c
c(yes)->o->i1
c(no,left)->op->e

注意转化成浮点数来求平均值。
浮点数转化方法: 1.0*sum/count

4.2.4 整数逆序

整数分解方法:%10得到个位数,/10;再%10得到十位数……
整数逆序问题注意结尾0的处理;
如果不用考虑0的话,我们可以每得到一位就输出一位。%10一下输出一下,/10,再%10输出一下,很快啊
考虑0:那就应该把逆序数算出来在输出了。搞一个ret=0,每次ret=ret*10+n%10;

5.1.1 for循环

阶乘n!=n*(n-1)*(n-2)*……*2*1
程序:输入n,输出n!
需要借助一个变量i从1~n.这里的循环,我们用for来处理。
for循环像一个计数器。达到一个数之前一直进行循环,在过程中i++i--
for(int i=0;i<n;i++)n次循环
求和时,初始值为0;求积时,初始值为1
still, 可以尝试细节。
比如阶乘,第一项是1,乘不乘不变。如果去掉的话,可以吗?对all n有影响吗?
或者把方向反过来,从n乘到1可以吗?

5.1.2 循环的计算和选择

循环的起点终点对结果都有影响
有固定次数,明确起点与终点:for
至少执行一次:do while
可能一次不执行:while

5.2.1 循环控制

设定判定变量isprime=1;
如果出现可以整除,isprime=0;break;
break:结束循环
continue:可以跳过此循环剩下的部分,进入下一轮循环
在这里插入图片描述

5.2.2 嵌套的循环

如:输出100内的素数,for里有for(第一个for遍历1~100,第二个检验该数是不是素数)

int x;//再scan x
int isprime=1;
for(int i=2;i<x;i++){
    if(x%i==0){
        isprime=0;
        break;
    }
}//再根据isprime是不是1判断x是不是素数

除了特别设计,每一层循环的控制变量应该不一样(i),要注意。所以在第一层循环每层开始的时候重新赋值或定义int i,免得上次循环完的i这次拿来接着用,乱套了。
/t可以对齐,具体以后再讲

5.2.3 从嵌套的循环中跳出

凑硬币:用1,2,5元凑出100
如果我们想,发现了一种合适的就结束:在if内加break跳出(下图是错误示例)

for(one=1;one<x*10;one++)
{
    for(two=1;two<x*10/2;two++)
    {
        for(five=1;five<x*10/5;five++)//break跳出的是这层循环,而没有跳出上面的两层循环
        {
            if(one+two*2+five*5==x*10)
            {
                printf("可以用%d个一角加%d个两角加%d个五角得到%d元\n",one,two,five,x);
                break;
            }
        }
    }
}

但是图中的break只跳出了第三层for循环;接着又进到了第二层for循环(图中蓝色位置),Break和continue都只能在他那一层循环里做;
如何一直跳出呢?

方法一:连环跳
加一个判定变量exit=0;
if内写 exit=1;
在两个for后面都写上if(exit)break;

//接力break
int x,one,two,five,x;
int exit=0;
scanf("%d",&x);
for(one=1;one<x*10;one++)
{
    for(two=1;two<x*10/2;two++)
    {
        for(five=1;five<x*10/5;five++)
        {
            if(one+two*2+five*5==x*10)
            {
                printf("可以用%d个一角加%d个两角加%d个五角得到%d元\n",one,two,five,x);
                exit=1;
                break;
            }
        }
        if(exit==1)break;
    }
    if(exit==1)break;
}

方法二:goto out

//goto
int x,one,two,five,x;
int exit=0;
scanf("%d",&x);
for(one=1;one<x*10;one++)
{
    for(two=1;two<x*10/2;two++)
    {
        for(five=1;five<x*10/5;five++)
        {
            if(one+two*2+five*5==x*10)
            {
                printf("可以用%d个一角加%d个两角加%d个五角得到%d元\n",one,two,five,x);
                goto out;
            }
        }
    }
}
out:
return 0;

(除了这种多重break的结构建议使用goto,别的地方不建议。)

5.3.1 前n项和

求1+1/2+1/3+……+1/n.
在这个循环里,起点数字1,终点数字n都是明确的

#include<stdio.h>
int main()
{
    int n;
    double sum=0.0;
    scanf("%d",&n);
    for(int i=1;i<=n;i++)
    {
        sum+=1.0/i;
    }
    printf("f(%d)=%f",n,sum);
    return 0;
}

例2:1-1/2+1/3-1/4+……
解决方案:定义一个sign=1;

sum+=sign*1.0/i;
sign=-sign;

技巧:如果我们double sign=1.0,算式中就出现小数了,就不用*1.0了。

5.3.2 整数分解

比如输入:12345
输出:1 2 3 4 5
考虑之前逆序输出的方法,我们可以先把这个数逆过来之后再逆序输出(鬼才)
即:

  1. 先求x的逆序数t
  2. 逆序逐位输出t

这种方法的缺陷在于:对于末尾有0出现的数字(如700)只能得到7
我们可以回想3位数的题,我们用三位数/100得到最高位数字。
所以我们知道位数之后,可以正序逐位得到每一位的数字。

可以先一个while循环求出x的位数和mask(位数),(还是记得提前把x保存下来)然后正序输出。
123456 / 100000 = 1
123456%100000 = 23456
23456 / 10000 = 2
……

5.3.3 求最大公约数

算法1:枚举。

循环t++
if(u/t==0&&v/t==0)gcd=t;//不断刷新gcd
if(t==u||t==v)break;//并输出gcd;

效率更高的算法2:辗转相除

  1. 如果b=0,计算结束,a就是最大公约数;
  2. 否则,让a=b,b=a%b;
  3. 回到第一步

(可以使用之前提到过的变量表格法来人工运行)

6.0.1 求符合给定条件的整数集

给定<=6的正整数A,从A开始的连续四个数字,请输出所有由它们组成的无重复数字的三位数。
输出满足条件的三位数,从小到大,且每行6个整数,行末无多余空格。
如:输入A=2
234 235 243 245 253 254
324 325 342 345 352 354
423 425 432 435 452 453
523 524 532 534 542 543

int i,a,j,k,cnt=0;
   scanf("%d",&a);
   i=a;
   //思路:i,j,k都从a开始,从小到大逐渐增加到a+3,三者不能相等
   
   while(i<=a+3){
       j=a;
       while(j<=a+3){
           k=a;
           while(k<=a+3){
              if(i!=j&&j!=k&&i!=k){
                  printf("%d%d%d",i,j,k);
                  cnt++;
                  if(cnt==6){
                      printf("\n");
                      cnt=0;
                  }
                  else printf(" ");
              }
              k++;
           }
           j++;
       }
       i++;
   }

在这里插入图片描述

6.0.2 水仙花数

水仙花数指一个N位正整数(N>=3),它的每位上的数字的N次幂之和等于它自己。如:153=1^3^+3^3^+5^3^;
给定一个N(3<=N<=7),按顺序输出所有N位水仙花数。
输入:3
输出:
153
370
371
第一个循环:遍历所有N位数。
第二个循环来求和,循环里面第三个循环来求每一位的N次幂(N次循环),最后if判断是否==sum。

6.0.3 打印乘法口诀表

在这里插入图片描述

a*b,a、b两重循环。
还要注意对齐问题。如果结果是一位数,输出两个空格;两位数输出一个空格。

6.0.4 统计素数并求和

给定M和N区间内的素数的个数并对它们求和。

读题后得知:包含两头[M,N]
先定义isprime=1;当可以被比他小的数整除的时候就isprime=0。
这道题很好做。注意特殊情况,如m=1时,循环直接不判断,isprime=1
可以在m~n循环开始前判断,if(m==1)m++;

6.0.5 猜数游戏

输入要猜的数字和猜的最大次数,大了输出too big,小了输出too small,直到猜对或者次数用光或者用户输入负数为止
还有就是注意不同次数猜到的输出结果也有区别。
一次猜到:BINGO!
两次猜到:LUCKY YOU!
三次以上猜到:GOOD GUESS!
//也不难,1.考的是语文的阅读理解;2.你是否有足够的耐心。(文中条件太多)

6.0.6 n项求和

2/1+3/2+5/3+8/5+……的前n项之和(从第二项开始,每一项的分子是前一项的分子和分母之和,分母是前一项的分子)

dividend=2;//分母
divisor=1;//分子
for(i=1;i<=n;i++){
    sum+=dividend/divisor;
    t=dividend;
    dividend+=divisor;
    divisor=t;
}
printf("%.2f/n",sum);

因为分子分母变大的相当快,所以出于范围考虑,也建议使用double储存dividend(分子)和divisor(分母)
(inf是越界,即无穷;nan是无效数字)

6.0.7 约分最简分式:

输入一个分式,如32/45,输出最简形式。

  1. scanf("%d/%d")这样处理输入
  2. 辗转相除法寻找最大公约数;

念数字:比如输入-12:fu yi er
先判断-的情况之后switch case很好办。以后学会数组之后会有更优解。

求a的连续和:

输入a,n,计算a+aa+aaa+……+n个a的和
循环的每一轮a1=a1*10+a。

目录
相关文章
|
1月前
|
C语言
【C语言】循环结构程序设计(第二部分 -- 习题讲解)
【C语言】循环结构程序设计(第二部分 -- 习题讲解)
|
1月前
|
C语言
C语言循环结构
C语言循环结构
10 0
|
3月前
|
机器学习/深度学习 C语言
【C语言必知必会 | 子系列第五篇】深入剖析循环结构(1)
【C语言必知必会 | 子系列第五篇】深入剖析循环结构(1)
64 0
【C语言必知必会 | 子系列第五篇】深入剖析循环结构(1)
|
3月前
|
算法 C语言 数据安全/隐私保护
【C语言必知必会 | 第八篇】一文带你精通循环结构
【C语言必知必会 | 第八篇】一文带你精通循环结构
15 0
|
3月前
|
人工智能 C语言
【C语言必知必会| 第七篇】循环结构入门,这一篇就够了
【C语言必知必会| 第七篇】循环结构入门,这一篇就够了
19 0
|
4月前
|
C语言
c语言经典例题讲解(输出菱形,喝汽水问题)
c语言经典例题讲解(输出菱形,喝汽水问题)
51 0
C4.
|
1月前
|
程序员 C语言
C语言循环结构与程序设计
C语言循环结构与程序设计
C4.
23 0
|
1月前
|
C语言
在C语言中,for语句是一种常用的循环结构控制语句
在C语言中,for语句是一种常用的循环结构控制语句
8 0
|
1月前
|
C语言
c语言循环结构
c语言循环结构
11 0
|
1月前
|
C语言
C语言循环结构
C语言循环结构
24 0
C语言循环结构