C语言(四)循环结构;一些例题

本文深入讲解了循环结构的基础概念和多种循环类型,包括while循环、do-while循环、for循环及其应用实例。通过丰富的示例代码介绍了如何利用这些循环解决实际问题,如计算数字位数、猜数游戏、求平均数等。

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. 人们往往会考虑循环终止的条件。
Created with Raphaël 2.2.0 开始 计算机随机想一个数,记在number里 用户输入猜的数 count++ 判断a是否等于number 输出cnt猜的次数 结束 告诉用户大了还是小了 yes no

循环的条件是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

Created with Raphaël 2.2.0 sum=0,cnt=0 读num num!=-1? sum+=num, cnt++ 计算和打印结果 end yes no

注意转化成浮点数来求平均值。
浮点数转化方法: 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=13+33+53;
给定一个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. 请写1个支付宝接龙红包程序. 随机产生1-100的随机数,作为红包金额. 让用户不断的去猜,直到猜正确为止.最后发给用户的红包金额是 红包金额/猜得次数. 2. 循环录入5个人的年龄并计算平均年龄,如果录入的数据出现负数或大于100的数,立即停止输入并报错. 3. 实现要求用户一直输入QQ号码和密码,只要不是123456、888888就一直提示要求重新输入,如果正确则提登录成功. 4. 1-100之间不能够被7整除的数的和. 5. 求1-200之间的所有的整数的累加和 6. 求1-100之间6的倍数的个数 7. 输入班级人数,然后依次输入学员成绩,计算班级学员的平均成绩和总成绩 8. 2006年培养学员80000人,每年增长25%,请问按此增长速度,到哪一年培训学员人数将达到20万人?*** 9. 从键盘输入10个数,求出最大数 10. 1000~ 5000之间有多少整数,其各位数字之和为5,分别是哪些数(例如整数2003的各位数字之和为 2+0+0+3 ,等于5)), 并统计满足条件的整数有多少个。 11. 求1-100中 是7的倍数 的数值之和 12. 求1-1000之间的所有的奇数之和 13.猜数字游戏. 随机产生1个1-100之间的数 让用户猜 当用户输入的数比产生的随机数大 就输出 猜大了 并让用户继续输入新的数.。 当用户输入的比产生的随机数小的时候 就输出 猜小了 并且继续猜 当用户刚好输入的就是这个随机数的时候 提示成功 并显示用户猜了多少次. 14. 老师问学生,这道题你会做了吗? 如果学生答"会了(y)",则可以放学. 如果学生不会做(n),则老师再讲一遍,再问学生是否会做了......直到学生会为止,才可以放学. 直到学生会或老师给他讲了10遍还不会,都要放学 15. 写1个程序. 随机的产生1个2位数的加法运算.让用户输入这个运算的结果 然后判断这个结果是否正确. 来10次. 每个人默认有10分. 产生10个加法运算.操作数的范围在0-100之间. 每产生1个加法运算 就让用户输入结果.判断是否正确. 当回答正确的时候就为用户加1分. 错误的时候就扣1分. 当10道题目回答完毕之后 就显示用户得的分数. ***
以下是几个C语言循环结构例题及代码: ### 例题1:找出100 - 999之间的水仙花数 ```c #include <stdio.h> int main(){ int i = 100; while (i < 1000){ int n1 = i % 10; int n2 = i / 10 % 10; int n3 = i / 100 % 10; if(i == n1*n1*n1 + n2*n2*n2 + n3*n3*n3){ printf("%d ", i); } i++; } return 0; } ``` 此代码使用`while`循环遍历100到999之间的所有整数,对于每个整数,分离出其个位、十位和百位数字,判断是否满足水仙花数的条件(即该数等于其各位数字的立方和),若是则输出该数[^2]。 ### 例题2:输入一个在100 - 160之间的整数 ```c #include<stdio.h> int main() { int num; do { printf("请输入一个整数:\n"); scanf("%d",&num); }while(num<100||num>160); printf("%d\n",num); return 0; } ``` 该代码使用`do-while`循环,不断提示用户输入一个整数,直到输入的整数在100到160之间,然后输出该整数[^3]。 ### 例题3:计算1到20的阶乘之和 ```c #include <stdio.h> int main(){ int sum = 0; int n = 1; for(int i = 1;i <= 20;i++){ n = n * i; sum = sum + n; } printf("阶乘结果:%d",sum); return 0; } ``` 这里使用`for`循环,计算1到20每个数的阶乘,并将这些阶乘累加起来,最后输出阶乘之和[^4]。 ### 例题4:输入一个数,将其各位数字反转输出 ```c #include <stdio.h> #include <string.h> #include <stdlib.h> #include <limits.h> int main(int argc, const char *argv[]) { int n , sum=0, temp; printf("请输入一个数:"); scanf("%d",&n); temp = n; if(n<INT_MIN|| n>INT_MAX/10){ printf("越界\n"); return 0; } while(n!=0){ int nb = n%10; sum = sum*10+ nb; n=n/10; } printf("%d\n",sum); return 0; } ``` 此代码使用`while`循环,将输入的整数的各位数字反转,若输入的数越界则输出提示信息,否则输出反转后的数字[^5]。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

灰海宽松

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值