C语言程序设计学习笔记:P4-循环


一、循环

1.1 循环

现在我有一个题目:程序读入一个4位以下(含4位)的正整数,然后输出这个整数的位数。如输入352,输出3。

人的方式:眼睛一看就知道了,我们一眼就可以看出352是三位数。
计算机的方式:计算机最不擅长的就是一眼看出来结果,因此一个合适的方法便是判断数的范围来决定它的位数。由于352∈[100,999],因此352是三位数。

因此,我们写出代码如下。通过级联的if来依次判断输入的数字是否大于最大的三位数、最大的两位数、最大的一位数,从而得到数字的位数。

#include <stdio.h>
int main()
{
    
    
	int x;
	int n=1;

	scanf("%d", &x);
	if (x > 999)
	{
    
    
		n=4;
	}
	else if (x > 99)
	{
    
    
		n = 3;
	}
	else if (x > 9)
	{
    
    
		n = 2;
	}
	else
	{
    
    
		n = 1;
	}

	printf("%d\n", n);
	return 0;
}

我们进行测试,可以看出结果正确。
在这里插入图片描述


但是这个代码也有局限性:

如果输入任意范围的正整数怎么办?如果是5位数、6位数、7位数…,那我们得一直增加if的个数,这如何才是个头?我们知道,如果让你看到352这个数,可以一眼就知道是三位数。但是如果人看到123812843267518273618273612675317这个数,能一眼看出是多少位吗?答案是明显不能的,那我们就会去数数,一路数过来。

关于数数,人是怎么做的:

人数数的过程是这样的:从左往右数,一次划掉一个数字,并将位数加1。举个例子,输入352,那么我们首先划去第一位的3,保留后面的52并将位数加1。

计算机怎么做:

计算机该怎样实现这个功能呢?要完成上面操作我们可以让352 %100 —> 52,此时成功划去3并保留52,接着重复上面操作。那么,对于刚才那个非常大的数,要划去第一个数,需要
123812843267518273618273612675317%
100000000000000000000000000000000->
23812843267518273618273612675317
问题便是怎么得到那个
100000000000000000000000000000000?


思路:
可以看出从左往右划不现实,无法得知应该去模哪一个数。如果换一下,从右边开始划,直到没数可以划,同时在这个过程中计数,这样就能够得到正确的结果。

123812843267518273618273612675317 / 10->12381284326751827361827361267531
12381284326751827361827361267531 / 10->1238128432675182736182736126753
1238128432675182736182736126753 / 10->123812843267518273618273612675


我们写出代码,可以看出需要一直判断划完后的数是否为0,如果不为0就需要继续。可以看出这事还是没完没了。

int x;
int n = 0;

scanf("%d", &x);

n++;
x /= 10;
if < x>0)
{
    
    
	n++;
	x/=10;
	if (x > 0)
	{
    
    
		n++;
		x/=10;
		if ...
	}
}

printf("%d\n", n);

那么我们也许需要这个东西:while。当x大于0时,我们需要一直去做这个事。

#include <stdio.h>
int main()
{
    
    
	int x;
	int n=0;
	scanf("%d", &x);
	n++;
	x /= 10;
	while (x > 0)
	{
    
    
		n++;
		x /= 10;
	}

	printf("%d\n", n);
	return 0;
}

我们进行测试,可以看出结果正确。
在这里插入图片描述

1.2 while循环

单看语法的话,while和if非常相似,只用把判断条件前面的if改为while即可。不同的是,括号里面的操作if只执行1次,而while要重复地执行。

//if:
if (x > 0)
{
    
    
	x /= 10;
	n++;
}

//while
if (x > 0)
{
    
    
	x /= 10;
	n++;
}

while的流程图可以如下图所示:
在这里插入图片描述


括号里面反复执行的叫做循环体。循环体内一定要有改变条件的机会,不然会一直在循环里面出不来。如下面这个例子,由于x大于0且x的值不会改变,因此n会一直加下去。

int x = 10;
int n = 0;
while (x > 0)
{
    
    
	n++;
}
printf("%d", n);

在上面一节我们写过一段判断整数位数的代码。while前面的两行代码与循环体内的代码一样,那我们能够把外面的代码放进来吗?

n++;
x /= 10;
while (x > 0)
{
    
    
	n++;
	x /= 10;
}

我们来试一试。

#include <stdio.h>
int main()
{
    
    
	int x;
	int n=0;
	scanf("%d", &x);
	while (x > 0)
	{
    
    
		n++;
		x /= 10;
	}

	printf("%d\n", n);
	return 0;
}

当我们输入0时,结果为0,明显错误。
在这里插入图片描述
因此,这个程序需要一些特殊的代码来判断输入为0时的情况,即必须先执行一次循环体内的操作。

1.3 do-while 循环

我们来看下上面判断整数位数的代码(包括输入为0)的算法流程应该是怎么样的:

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


我们有没有更好的结构使得先将事情做一轮然后再去判断呢?这就是我们的do-while循环。在进入循环的时候不做检查,而是在执行完一轮循环体的代码之后,再来检查循环的条件是否满足。如果满足则继续下一轮循环,不满足则结束循环。do-while的语法如下,注意不要忘了while后面的那个分号。

do
{
<循环体语句>
} while ( <循环条件> );

其流程图如下图所示:
在这里插入图片描述


do-while循环和while循环很像,区别是do-while在循环体执行结束的时候才来判断条件。也就是说,无论如何循环都会执行至少一遍,然后再来判断条件。与while循环相同的是,条件满足时执行循环,条件不满足时结束循环。因此,判断整数位数的代码可以写成下面这样。

#include <stdio.h>
int main()
{
    
    
	int x;
	int n=0;
	scanf("%d", &x);
	do
	{
    
    
		n++;
		x /= 10;
	}while (x > 0);

	printf("%d\n", n);
	return 0;
}

小测验

1、while循环的条件满足的时候循环继续,而do-while的条件满足的时候循环就结束了。
答案:错误

2、以下代码片段执行结束后,变量i的值是多少?

int i =10;
while ( i>0 ) {
    
    
    i /=2;
}

答案:0

3、以下代码片段执行结束后,变量i的值是多少?

int i = 1;
do {
    
    
	i += 5} while (i<17);

答案:21

二、循环应用

2.1 循环计算

题目1:求一个数是2的多少次幂。(设置输入的这个数是2的整数次幂)

#include <stdio.h>
int main()
{
    
    
	int x=64;
	int ret = 0;
	int t = x;  //使用一个变量保存x,因为后面需要打印原始的x,后面x的值会改变
	while (x > 1)
	{
    
    
		ret++;
		x /= 2;
	}

	printf("log2 of %d is %d\n", t, ret);
	return 0;
}

题目2:我们再看个例子,下面我有一段代码。

#include <stdio.h>

int main()
{
    
    
	int count = 100;
	while ( count>= 0 ) {
    
    
		count--;
		printf("%d ", count);
	}
	printf("发射\n");

	return 0;
}

看着这段代码,我们有以下几个小问题:

①这个循环需要执行多少次?
②循环停下来的时候,有没有输出最后的0?
③循环结束后,count的值是多少?


小套路:如果要模拟运行一个很大次数的循环,可以模拟较少的循环次数,然后作出推断。我们先将count设置为3来看看。可以看出循环执行了4次,输出了最后的0,循环结束后count的值为-1。
在这里插入图片描述

2.2 猜数游戏

题目:现在我们想做一个猜数游戏。让计算机来想一个数,然后让用户来猜,用户每输入一个数,就告诉它是大了还是小了,直到用户猜中为止,最后还要告诉用户它猜了多少次。

看到这个问题我们可以知道因为需要不断重复让用户猜,所以需要用到循环,核心重点是循环的条件,尤其是循环终止的条件。我们用文字描述出我们设计代码的思路:

1、计算机随机想一个数,记在变量number里;
2、一个负责计次数的变量count初始化为0;
3、让用户输入一个数字a;
4、count递增(加一);
5、判断a和number的大小关系,如果a大,就输出“大”;如果a小就输出“小”;
6、如果a和number是不相等的(无论大还是小),程序转回到第3步;
7、否则,程序输出“猜中”和次数,然后结束。


我们写出相应代码

#include <stdio.h>
#include <stdlib.h>
#include <time.h>

int main()
{
    
    
/*
需要使用stdlib.h和time.h两个库。
每次召唤rand()就得到一个随机的整数。
加上srand(time(0))是为了让得到的随机整数更加真实。
将 随机数%n 会得到一个∈[0, n-1]的整数。根据这个来产生1-100之间的数。
*/
	srand(time(0));
	int number = rand()%100+1;
	int count = 0;
	int a = 0;
	printf("我已经想好了一个1到100之间的数。");
	//用do-while比较好,因此一定会执行一次
	do {
    
    
		printf("请猜这个1到100之间数:");
		scanf("%d", &a);
		if ( a > number ) {
    
    
			printf("你猜的数大了。");
		} else if ( a < number ) {
    
    
			printf("你猜的数小了。");
		}
		count ++;
	} while (a != number);
	printf("太好了,你用了%d次就猜到了答案。\n", count);

	return 0;
}

我们来测试一下,可以看出结果正确。实际上,猜100内的整数最多用7次,具体原因我们后面分析。
在这里插入图片描述

2.3 算平均数

题目:让用户输入一系列的正整数,最后输入-1表示输入结束,然后程序计算出这些数字的平均数,输出输入的数字的个数和平均数。

看到这个问题,我们进行思考:

①需要一个记录读到的整数的变量
②平均数要怎么算?只需要每读到一个数,就把它加到一个累加的变量里,到全部数据读完,再拿
它去除读到的数的个数就可以了
③需要一个变量记录累加的结果
④需要一个变量记录读到的数的个数


程序的算法流程如下图所示:

在这里插入图片描述


我们写出对应代码如下:

#include <stdio.h>

int main()
{
    
    
	int sum = 0;
	int count = 0;
	int number;

	scanf("%d", &number);
	while ( number != -1 ) {
    
    
		sum += number;
		count ++;
		scanf("%d", &number);
	}

	printf("The average is %f.\n", 1.0 * sum / count);

	return 0;
}

我们进行测试,可以看出结果正确。
在这里插入图片描述

2.4 整数求逆

题目:输入一个正整数,输出逆序的数。如输入48102,输出20184。

这个问题会存在两种情况。①对于一些以0结束的正整数,如700,输出7。②对于一些以0结束的正整数,如700,输出007

1、对于第一种情况,我们代码如下:

#include <stdio.h>

int main()
{
    
    
	int x;
	scanf("%d", &x);
	int digit;
	int ret = 0;

	while ( x> 0 ) {
    
    
		digit = x%10;
		ret = ret*10 + digit;
		printf("x=%d,digit=%d,ret=%d\n", x, digit, ret);
		x /= 10;
	}
	printf("%d", ret);
	
	return 0;
}

进行测试,可以看出结果正确。
在这里插入图片描述

2、对于第二种情况,我们代码如下:

#include <stdio.h>

int main()
{
    
    
	int x;
	scanf("%d", &x);
	int digit;
	int ret = 0;

	while ( x> 0 ) {
    
    
		digit = x%10;
		printf("%d", digit);
		ret = ret*10 + digit;
		x /= 10;
	}
	
	return 0;
}

进行测试,可以看出结果正确。
在这里插入图片描述

小测验

1、以下哪种运算能从变量x中取得十进制最低位的数字
A. x / 10
B. x % 10
C. x * 10
D. 10 / x
答案:B

2、当需要累加一些值的时候,用来记录累加结果的变量应该被初始为:
答案:0

猜你喜欢

转载自blog.csdn.net/InnerPeaceHQ/article/details/121344166
今日推荐