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

本系列博客用于记录学习浙江大学翁恺老师的C语言程序设计,系列笔记链接如下:
C语言程序设计学习笔记:P1-程序设计与C语言
C语言程序设计学习笔记:P2-计算
C语言程序设计学习笔记:P3-判断
C语言程序设计学习笔记:P4-循环
C语言程序设计学习笔记:P5-循环控制
C语言程序设计学习笔记:P6-数据类型
C语言程序设计学习笔记:P7-函数
C语言程序设计学习笔记:P8-数组
C语言程序设计学习笔记:P9-指针
C语言程序设计学习笔记:P10-字符串
C语言程序设计学习笔记:P11-结构类型
C语言程序设计学习笔记:P12-程序结构
C语言程序设计学习笔记:P13-文件
C语言程序设计学习笔记:P14-链表


一、循环

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

代码实现

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);

解决方案

我们写出代码,可以看出需要一直判断划完后的数是否为0,如果不为0就需要继续。可以看出这事还是没完没了。那么我们也许需要这个东西: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
while (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)的算法流程应该是怎么样的:
①用户输入x;
②初始化n为0;
③x = x / 10,去掉个位;
④n ++;
⑤如果x>0,回到3;
⑥否则n就是结果。
我们有没有更好的结构使得先将事情做一轮然后再去判断呢?这就是我们的do-while循环。在进入循环的时候不做检查,而是在执行完一轮循环体的代码之后,再来检查循环的条件是否满足。如果满足则继续下一轮循环,不满足则结束循环。do-while的语法如下,注意不要忘了while后面的那个分号。
do
{
<循环体语句>
} while ( <循环条件> );

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

do-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的值是多少?
在这里插入图片描述
答案:0

3、以下代码片段执行结束后,变量i的值是多少?
在这里插入图片描述
答案: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


第一种情况代码实现

#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;
}

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


第二种情况代码实现

#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

  • 2
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

知初与修一

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

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

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

打赏作者

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

抵扣说明:

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

余额充值