- 一、循环
- 1.1 循环
- 1.2 while循环
- 1.3 do-while 循环
- 小测验
- 二、循环应用
- 2.1 循环计算
- 2.2 猜数游戏
- 2.3 算平均数
- 2.4 整数求逆
- 小测验
一、循环 1.1 循环
现在我有一个题目:程序读入一个4位以下(含4位)的正整数,然后输出这个整数的位数。如输入352,输出3。
人的方式:眼睛一看就知道了,我们一眼就可以看出352是三位数。
计算机的方式:计算机最不擅长的就是一眼看出来结果,因此一个合适的方法便是判断数的范围来决定它的位数。由于352∈[100,999],因此352是三位数。
因此,我们写出代码如下。通过级联的if来依次判断输入的数字是否大于最大的三位数、最大的两位数、最大的一位数,从而得到数字的位数。
#includeint 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("%dn", 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("%dn", n);
那么我们也许需要这个东西:while。当x大于0时,我们需要一直去做这个事。
#includeint main() { int x; int n=0; scanf("%d", &x); n++; x /= 10; while (x > 0) { n++; x /= 10; } printf("%dn", n); return 0; }
我们进行测试,可以看出结果正确。
单看语法的话,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;
}
我们来试一试。
#includeint main() { int x; int n=0; scanf("%d", &x); while (x > 0) { n++; x /= 10; } printf("%dn", n); return 0; }
当我们输入0时,结果为0,明显错误。
因此,这个程序需要一些特殊的代码来判断输入为0时的情况,即必须先执行一次循环体内的操作。
我们来看下上面判断整数位数的代码(包括输入为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循环相同的是,条件满足时执行循环,条件不满足时结束循环。因此,判断整数位数的代码可以写成下面这样。
#includeint main() { int x; int n=0; scanf("%d", &x); do { n++; x /= 10; }while (x > 0); printf("%dn", 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
题目1:求一个数是2的多少次幂。(设置输入的这个数是2的整数次幂)
#includeint main() { int x=64; int ret = 0; int t = x; //使用一个变量保存x,因为后面需要打印原始的x,后面x的值会改变 while (x > 1) { ret++; x /= 2; } printf("log2 of %d is %dn", t, ret); return 0; }
题目2:我们再看个例子,下面我有一段代码。
#includeint main() { int count = 100; while ( count>= 0 ) { count--; printf("%d ", count); } printf("发射n"); return 0; }
看着这段代码,我们有以下几个小问题:
①这个循环需要执行多少次?
②循环停下来的时候,有没有输出最后的0?
③循环结束后,count的值是多少?
小套路:如果要模拟运行一个很大次数的循环,可以模拟较少的循环次数,然后作出推断。我们先将count设置为3来看看。可以看出循环执行了4次,输出了最后的0,循环结束后count的值为-1。
题目:现在我们想做一个猜数游戏。让计算机来想一个数,然后让用户来猜,用户每输入一个数,就告诉它是大了还是小了,直到用户猜中为止,最后还要告诉用户它猜了多少次。
看到这个问题我们可以知道因为需要不断重复让用户猜,所以需要用到循环,核心重点是循环的条件,尤其是循环终止的条件。我们用文字描述出我们设计代码的思路:
1、计算机随机想一个数,记在变量number里;
2、一个负责计次数的变量count初始化为0;
3、让用户输入一个数字a;
4、count递增(加一);
5、判断a和number的大小关系,如果a大,就输出“大”;如果a小就输出“小”;
6、如果a和number是不相等的(无论大还是小),程序转回到第3步;
7、否则,程序输出“猜中”和次数,然后结束。
我们写出相应代码
#include#include #include int main() { 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次,具体原因我们后面分析。
题目:让用户输入一系列的正整数,最后输入-1表示输入结束,然后程序计算出这些数字的平均数,输出输入的数字的个数和平均数。
看到这个问题,我们进行思考:
①需要一个记录读到的整数的变量
②平均数要怎么算?只需要每读到一个数,就把它加到一个累加的变量里,到全部数据读完,再拿
它去除读到的数的个数就可以了
③需要一个变量记录累加的结果
④需要一个变量记录读到的数的个数
程序的算法流程如下图所示:
我们写出对应代码如下:
#includeint 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; }
我们进行测试,可以看出结果正确。
题目:输入一个正整数,输出逆序的数。如输入48102,输出20184。
这个问题会存在两种情况。①对于一些以0结束的正整数,如700,输出7。②对于一些以0结束的正整数,如700,输出007
1、对于第一种情况,我们代码如下:
#includeint 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=%dn", x, digit, ret); x /= 10; } printf("%d", ret); return 0; }
进行测试,可以看出结果正确。
2、对于第二种情况,我们代码如下:
#includeint 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



