人生就是日复一日地不断重复,既有相同的事情,也有相似的事情,却无论如何也无法回到最初。想要在生活的每一刻都能有新的发现,恐怕只是一个美好的愿望。
本章将会为大家介绍程序设计中的重复流程——循环。
C语言中提供了3种循环执行程序语句:do语句,while循环,for循环。首先我们来看一下do语句。
do语句
首先我们对上两节介绍的代码中(显示输入的整数是奇数还是偶数)进行一下修改。
输入一个整数,显示出它是奇数还是偶数。然后询问是否重复同样的操作,并按照要求进行处理。
\\输入的整数是奇数还是偶数呢?
#include <stdio.h>
int main()
{
int retry;
do{
int num;
printf("请输入一个整数:");
scanf("%d",&num);
if(num%2)
puts("这个整数是奇数。");
else
puts("这个整数是偶数。");
printf("要重复一次吗?[yes~~~0/no~~~9]:");
scanf("%d",&num);
}while(retry==0);
return 0;
}
do是“执行”的意思,while是“在······期间”的意思。根据do语句的处理流程,只要()中的表达式的判断结果不是0,语句就会循环执行。
另外,do语句循环的对象语句称为循环体。
▶下面也要讲的while语句和for语句所循环的语句也称为循环体。
在上述代码中,如果读取到的变量retry的值为0,那么控制编排大师retry==0的判断结果就为1。因为1不等于0,所以身为复合语句的循环体会再次执行。也就是说,判断结果不为0的话,程序会返回到复合语句的开头,然后重新执行复合语句。
如果读取到的变量retry的值不为0,那么控制表达式retry==0的判断结果就为0,do语句就结束了。
下面我们用我们所学的switch与do···while来写一个石头剪刀布的程序。
\\根据读取的整数值显示所出的拳(只接受0,1,2)
#include <stdio.h>
int main()
{
int hand;
do{
printf("请选择出什么拳【0···拳头/1···剪刀/2···布】:");
scanf("%d",&hand);
}while(hand<0||hand>2)
printf("你选择了:");
switch(hand)
{
case 0:printf("石头。"); break;
case 1:printf("剪刀。"); break;
case 2:printf("布。 "); break;
}
return 0;
}
首先我们来试一下。如果读取的数值是0,1,2这些“合法的值”,就会显示“石头”“剪刀”“布”。而如果输入3或者-3这样“非法的值”,就会提醒你再次输入。
我们在来看一下判断do语句的循环是否继续的控制表达式。
hand<0||hand>2
我们前面讲过,这是逻辑或语句,只要满足一条则就为真。如果hand的值是0,1,2中的一个,则do语句执行结束。换句话说,do语句执行结束的时候,hand的值一定是0,1,2中的一个。
当然我们也可以把条件写成下面这种形式。
!(hand>=0&&hand<=2)
这里的!被称为逻辑非运算符是判断操作数是否等于0的单目运算符。
逻辑非运算符 !a 当a的值是0的时候值为1,当a的值不是0的时候值为0.
我们再用所学知识来求多个整数的和及平均值。
\\不停地输入整数,显示其和及平均值
#include <stdio.h>
int main()
{
int sum=0;
int count=0;
int retry;
do{
int t;
printf("请输入一个整数:");
scanf("%d",&t);
sum=sum+t;
count++;
printf("是否继续?<yes···0/no···9>:");
scanf("%d",&retry);
}while(retry==0);
prientf("和为%d,平均值为%.2f。\n",sum,(double)sum/count);
return 0;
}
下面我们来讲解一下求和的过程。
1准备
首先进行求和的准备工作。假设变量count存储着读取的整数值的个数,变量sum存储着整数值的和,它们的初始值均为0.
2更新和及个数
在循环体中,首先为变量t读入整数值。之后执行以下赋值。
sum=sum+t;这里可以写成sum+=t;他和sum=sum+t是完全一样的效果,但是这种写法让代码看上去更简单,并且程序运行的时候不也不用那么麻烦,西面我们就直接用这种写法。
count+=1;
这样一来,count的值就会加1,从而变为1.
接着,因为变量retry中读入的值为0,所以会再次执行循环体。
只要retry中读入的值为0,上述处理就会一直循环进行。另外,每进行一次循环,变量count的值就加1,其中储存读入的数值个数。
复合赋值运算符
上述2中使用的+=称为复合赋值运算符。这是一个同时进行加法运算+和赋值=的运算符。
sum=sum+t和sum+=t几乎相同。
包括+=在内,复合赋值运算符一共有10个。
后置递增迅运算符和后置递减运算符
上述代码中使用的++是后置递增运算符。使用该运算符的表达式a++,能够使操作数的值仅加1。这种只增加1 的情况,我们称之为递增。
后置递增运算符 | a++ | 使a的值增加1 |
后置递减运算符 | a-- | 使a的值减少1 |
如上表所示,使操作数的值减1(递减)的--运算符是后置递减运算符。
由于复合赋值运算符和后置递增运算符,后置递减运算符在一般的数学计算中不会使用,因此可能会觉得比较难。但熟悉之后,其实是很简单的。使用复合赋值运算符和后置递增运算符,后置递减运算符,能够使程序更简洁,更易读。
while语句
与上一节介绍的do语句不同,在循环体执行前对循环的继续条件进行的判断是while语句。
首先我们来写一串代码来看看while语句的执行过程。
//从输入的整数开始倒数到0
#include <stdio.h>
int main()
{
int num;
printf("请输入一个整数:");
scanf("%d",&num);
while(num>=0)
{
printf("%d",num);
num--;
}
printf("\n");
return 0;
}
这里为了实现递减而使用了while语句。
我们以num的值为5为例。
首先对控制表达式num>=0的值进行判断,结果为1,不为0,所以循环体中的语句会被执行。先通过printf("%d",num);语句在屏幕上显示出5。接下来执行no--;语句,由于后置递减运算符的作用,num的值递减为4.
这样循环体就结束了,程序会再次会到控制表达式。
然后再对循环是否继续执行进行判断。由于表达式num>=0仍然成立,因此循环体会被执行。于是屏幕上会显示出4,并且num的值会递减为3。
像这样,通过循环的反复执行,num的值会不断递减,并在屏幕上显示相应的数字。
当num的值为0的时候,在屏幕上显示出0,接下来通过后置递减运算符使num的值递减为-1.在这之后判断循环是否继续执行的控制表达式num>=0就不再成立了,循环结束。
需要注意的是,虽然最后显示在屏幕上的num的值是0,但其实while语句结束的时候它 的值已经变成了-1。
数据递增
这次我们来编写一段跟之前的程序相反的程序,显示出从0开始递增到输入的整数的哥哥整数。程序代码如下图所示。
//递增显示从0到输入的正整数为止的各个整数
#include <stdio.h>
int main()
{
int i,num;
printf("请输入一个整数:");
scanf("%d",&num);
i=0;
while(i<=num)
{
printf("%d",i++);
}
printf("\n");
return 0;
}
该程序与之前实现递减的程序最大的不同就是引入了一个新的变量i。i的值按照0,1,2···的方式递增。
限定次数的循环操作
输入一个下整数后,并排显示出该整数个*,具体的程序代码如下图所示。
//输入一个整数,连续显示出该整数个*
#include <stdio.h>
int main()
{
int num;
printf("正整数:");
scanf("%d",&num);
while(num-->0)
{
putchar('*');
}
putchar('\n');
return 0;
}
让我们以num的值等于15为例来考虑一下。首先,对while语句的控制表达式num-->0进行判断。--是后置递减运算符,所以会对递减前的num的值是否大于0进行判断。因此该控制表达式成立。之后,num的值递减,变为14。
先这样,每当程序的流程经过控制表达式,num的值都会递减。当它的值递减为0时,表达式num-->0的值第一次为0,while语句也就结束了。另外,由于在判断的时候变量num的值会再次递减,因此while语句结束的时候num的值为-1。
字符常量和putchar函数
在while语句执行的过程中,“putchar('*');”被执行;while语句结束之后,putchar('*');”。像'*'和'\n'这样,用单引号“”括起来的字符称为字符常量。字符常量是int型。
为了显示单一的字符,本代码中使用了putchar函数。()中的实参,就是需要显示的字符。本代码中的参数是'*'和'\n'。后者会换行。
注意:do语句的循环体至少会执行一次,而while语句的循环体则可能一次也不会执行。另外,在判断循环是否继续执行的时间方面,do语句和while语句也完全不同。
1.do语句······先循环后判断:执行循环体之后的判断。
2.while语句······先判断后循环:执行循环体之前进行判断。
▶下面要讲的for语句,也属于先判断后循环的类型。
逆向显示整数值
我们来考虑一下下面这个问题。
输入一个非负整数,并进行逆向显示。
也就是说,当输入1234的时候,显示出的结果是4321。当输入非正整数的时候,提示再次输入。我们来看看下面这串代码。
//逆向显示正整数
#include <stdio.h>
int main()
{
int num;
do{
printf("请输入一个正整数:");
scanf("%d",&num);
if(num<=0)
puts("\a请不要输入非正整数。");
}while(num<=0)
printf("该数逆向显示的结果是:");
while(num>0)
{
printf("%d",num%10);
num/=10;
}
puts("。");
return 0;
}
第一个do语句的作用是将输入的值限定为正值。当循环结束的时候,num的值肯定为正,即比0大。
while语句的作用是将输入的整数逆向显示。假设num的值为1234,则最终结果就会显示4321。
首先,先求出num%10的余数,也就是整数的最后一位数字,结果为4.然后执行以下语句。
num/=10。
由此可见,表达式num/=10的作用就是首先取出变量num的最后一位数字,然后将其他位的数字右移一位。
因为num的值123大于0,所以会再次执行循环体。接下来显示123除以10的余数,然后用123除以10,变为12。
只要num大于0,同样的处理就会循环执行,这样就完成了逆向显示的整个过程。
当num的值为0的时候,控制表达式num>0就不成立,while语句也就执行结束了。
以上是利用复合赋值运算符的第二个代码。复合赋值运算符有以下优点。
复合赋值运算符的优点
▶能够简洁地表示要进行的运算
比起“将num除以10的商赋值给num”,“将num除以10”更加简洁,而且这种表达式也易于人们接受。
▶只需写一遍左边的变量名
在变量名较长的情况下,或者在后面学习的使用数组和结构体的复杂的表达式中,使用复合赋值运算符能够减少输入错误,而且程序也更加易读。
▶左边的判断仅进行一次
使用复合赋值运算符最大的好处就是左边的判断仅进行一次。在以后的学习中,该优势会更加明显。
for语句
比起使用while语句,使用for语句实现循环会使程序更加简洁,易读。下面就来学习for语句。
for语句
下面我们使用for语句对我们之前写的代码进行一下修改。
//递增显示从0到输入的正整数为止的各个整数
#include <stdio.h>
int main()
{
int i,num;
printf("请输入一个正整数:");
scanf("%d",&num);
for(i=0;i<=num;i++)
{
printf("%d",i);
}
printf("\n");
return 0;
}
程序变得更加简洁了。for语句的结构图如图所示。for语句后面的括号中由三部分构成,分别用分号隔开。
用语言表述的话,就像下面这样。
1.作为“预处理”,判断并执行A部分。
2.如果作为“继续条件”的B部分控制表达式不为0,则执行语句(循环体)。
3.执行语句后,判断并执行作为“收尾处理”或“下一个循环的准备处理”的C部分,返回到2。
关于for语句中的个表达式,有几点需要注意的地方。
1.预处理
表达式A仅在循环执行之前执行一次。当程序不需要预处理的时候,该表达式可以省略。
2.控制表达式
表达式B是用来判定循环操作是否继续执行的表达式。如果该表达式成立,则执行循环体。
当省略表达式B的时候,通常认为控制表达式的值始终不为0。因此,除非使用break语句,否则该循环将成为永远执行的无限循环。
3.收尾处理
表达式C作为“收尾处理”或“下个循环的准备处理”,会在循环体执行后被判断,执行。如果没有需要执行的内容,则表达式可以省略。
使用for语句实现固定次数的循环
//输入一个整数,连续显示出整数个*
#include <stdio.h>
int main()
{
int i,num;
printf("正整数:");
scanf("%d",&num);
for(i=1;i<=num;i++)
{
putchar('*');
}
return 0;
}
在上文使用了while与觉得代码程序中,变量num的值发生了变化。在循环的过程中,num的值一直在递减。在while语句结束的时候,num的值变为了-1。
偶数的枚举
下面我们来编写一段程序,实现输入一个整数的值,显示该整数值一下的正偶数。
//显示输入的整数值一下的偶数
#include <stdio.h>
int main()
{
int i,num;
printf("整数值:");
scanf("%d",&num);
for(i=2;i<=n;i+=2)
{
printf("%d",i);
}
return 0;
}
for语句的i+=2部分中使用了复合赋值运算符+=,其作用是将右操作数的值加左操作数的值。
因为是将变量i加2,所以每次循环时i的值都会加2。
约数的枚举
下面我们来写一段程序,实现输入一个整数值,显示该整数值的所有约数。
//显示输入的整数值的所有约数
#include <stdio.h>
int main()
{
int i,num;
printf("整数值:");
scanf("%d",&num);
for(i=1;i<=num;i++)
{
if(num%i==0)
printf("%d",i);
}
return 0;
}
for语句中,变量i的值是从1到num递增的。
如果num除以i的余数为0,则判断i是num的约数,并显示它的值。
循环语句
本节学习的do语句,while语句,for语句,都是循环执行程序流程的语句。像这样的语句都称为循环语句。
多重循环
将循环语句的循环体作为循环语句,就可以进行二重,三重循环。这样的循环称为多重循环。下面我们来了解一下多重循环。
二重循环
之前我们见到的程序中的循环,结构都比较简单。实际上,在一个循环中还可以嵌套另一个循环。根据所嵌套的循环的多少,有二重循环,三重循环等。他们统称为多重循环。
使用二重循环显示九九乘法表的代码如下图所示。
//显示九九乘法表
#include <stdio.h>
int main()
{
int i,j;
for(i=1;i<=9;i++)
{
for(j=1;j<=i;j++)
{
printf("%d*%d=%d\t",i,j,i*j);
}
printf("\n");
}
return 0;
}
外则的for语句的作用是使变量i的值从1到9递增。其循环分别对应乘法表的第1行,第2行·······,即纵方向的循环。
各行中执行的内则的for语句的作用是使变量j 的值从1到9递增,这是各行中的横方向的循环。
显示图形
下面我们来显示长方形。
//画一个长方形
#include <stdio.h>
int main()
{
int i,j;
int h,w;
putf("让我们来画一个长方形");
printf("高:"); scanf("%d",&h);
printf("宽:"); scanf("%d",&w);
for(i=1;i<=h;i++)
{
for(j=1;j<=w;j++)
{
putchar('*');
}
printf("\n");
}
return 0;
}
共计h行,每行都显示出w个*,这样就形成了一个长方形。
总结
1.do语句,while语句和for语句统称为循环语句。无论哪种循环语句,只要控制表达式的判断结果不为0,都要执行循环体。另外,循环语句的循环体也可以是循环语句。这种结构的循环语句是多重循环。
2.先循环后判断可以通过do语句来实现。循环体至少执行一次。即使是单一语句,也可以使之称为程序块,这样程序会更易读。
3.先判断后循环可以通过while语句和for语句来实现。循环体有可能一次也不执行。使用单一变量控制的固定类型的循环,可以通过for语句简单地实现。
4.循环语句中的break语句会中断该循环语句的执行。
5.表达式后带有分号的语句称为表达式语句。省略表达式,只有分号的表达式语句,称为空语句。
6.复合赋值运算符是既进行运算又进行赋值的运算符。与用两个运算符分别进行运算和赋值相比,使用复合赋值运算符可以使程序更简洁,而且对左操作数的判断仅需进行一次即可。
7.C语言程序的书写格式很自由。通过加入适当的缩进,可以使程序更易读。