前面介绍了C语言中的选择结构,根据条件的不同,可以在程序中实现分支的效果。本文就来介绍3种结构中的最后一种,循环结构。
4.1三大循环结构
C语言中实现循环结构的语句有3种,while语句,for语句,do…while语句,下面逐个对其进行讲解。当然,循环结构也可以像选择结构那样,进行嵌套,我们也可以利用循环嵌套去解决一些问题。
4.1.1while循环
while语句是实现循环结构的一种基本语句,其语法格式如下
while (表达式)
语句;
同选择结构一样,while语句也只能控制跟在它后面的一条语句,如果想让其控制多条语句,应该加上花括号。可以辅以下面的图来理解这种结构。
例:在屏幕上打印1-10的数字
#include <stdio.h>
int main()
{
int i=1;
while (i<=10) //当i>10时,循环结束
{
printf("%d ",i);
i++; //每次循环让i自增1
}
return 0;
}
下面我们利用循环,来完成一个和数字位数有关的问题,其中取出数字中的每一位的算法,在以后会经常用到。
例:输⼊⼀个正的整数,逆序打印这个整数的每⼀位
例如:
输⼊:1234,输出:4 3 2 1
输⼊:521,输出:1 2 5
想要实现这个程序,我们首先要解决的问题是,如何把数字的每一位从数字中拆分出来。我们可以利用如下的算法:
1.要想得到n的最低位,可以使⽤n%10的运算,得到的余数就是最低位,如:1234%10得到4
2.要想去掉n的最低位,找出倒数第⼆位,则使⽤ n=n/10 操作就可以去掉最低位的,如:
n=1234/10得到123,123相较于1234就去掉了最低位,123%10就得到倒数第⼆位3。
3.循环1和2两个步骤,在n变成0之前,就能到所有的位。
我们可以通过不断的重复第一步和第二步,拆分出数字,当n=0时,结束循环。下面给出对应的代码
#include <stdio.h>
int main()
{
int n=0;
scanf("%d",&n);
while (n!=0) //当n为0时,结束循环
{
printf("%d ",n%10); //打印出数字的最低位
n=n/10; //通过整除运算,去掉最低位
}
return 0;
}
总结:通过取余运算,可以得到最低位的位数,通过整除运算,可以去掉最低位,应用好这两种运算,即可解决上面的问题。
4.2.2for循环
for语句是我们在写循环结构时,最常用的一种方式,下面给出它的语法格式
//注:如果想让for循环控制多条语句,需要加上花括号
for (表达式1;表达式2;表达式3)
语句;
表达式1用于循环变量的初始化,表达式2用于循环结束条件的判断,表达式3用于循环变量的调整。下面给出流程图,辅以理解
下面我们使用for循环,在屏幕上打印1-10的数字,并和while循环实现的该功能代码进行对比
例:在屏幕上打印1-10的数字
#include <stdio.h>
int main()
{
int n=0;
//i的初始值赋为1,大于10时跳出循环
for (i=1;i<=10;i++)
//每次循环打印i的值,并让i自增1
printf("%d",i);
return 0;
}
将两段代码放在一起对比一下,会发现,两种循环在实现的过程中,都有初始化部分,条件判断部分,和调整部分,不同的是,for循环将这3个部分全部集中在了一起,使整个代码看上去逻辑非常清晰,当代码量变多时,while循环的3个部分会非常分散,而使用for循环,就能更好的维护,充分发挥for循环的优点。
4.3.3do…while循环
在3大循环语句中,do…while语句用的最少,下面给出它的语法格式
//注:如果想让do...while循环控制多条语句,需要在do后面加上花括号
do
语句;
while(表达式);
它与另外两种循环的区别在于,while循环和for循环都是先判断条件是否满足,再执行循环体部分。而do…while循环,无论条件是否满足,都会先执行一次循环体部分,之后判断条件表达式是否满足,来决定是否继续执行循环体部分。下面给出do…while循环的流程图,辅以理解
一般do…while循环使用在循环体至少要被执行一次下的场景,比如下面这个例子
例:输⼊⼀个正整数,计算这个整数是⼏位数
例如:
输⼊:1234 输出:4
输⼊:12 输出:2
#include <stdio.h>
int main()
{
int n=0,cnt=0;
scanf("%d",&n);
do
{
cnt++;
n=n/10;
}while(n!=0);
printf("%d\n",cnt);
return 0;
}
这个功能不一定非要用do…while实现,只是比较合适,因为当n=0时,n是一位数,也要被统计位数,而循环体刚好要被执行一次。
4.2循环中断
在有些场景中,发现某些状况时,我们不得不提前终止循环,这是非常常见的现象。C语言中提供了break和continue两种不同的语句,来应对需要提取终止循环的情况。
4.2.1break语句
break语句的作用是永久停止当前正在执行的循环。当break语句被执行时,直接就会跳出循环,继续执行循环体后面的语句。来看看下面这段代码
#include <stdio.h>
int main()
{
int i=0;
for (i=1;i<=10;i++)
{
printf("%d ",i);
if (i==5)
break;
}
return 0;
}
运行结果:
可以看到,当程序运行到i==5时,在屏幕上打印i之后,执行break语句,直接跳出第一层的循环,之后代码将不再循环,也不再打印。所以break语句的作用就是永久的终止该层循环。当以后,程序满足了某种条件时,我们想要跳出循环,就可以使用break语句来实现这样的效果。
4.2.2continue语句
continue语句的作用是跳过本次循环后面的语句,继续进行下一次循环判断,我们对上面的代码进行细微的改动,来观察continue语句在循环中的作用
#include <stdio.h>
int main()
{
int i=0;
for (i=1;i<=10;i++)
{
if (i==5)
continue;
printf("%d ",i);
}
return 0;
}
运行结果:
看到了吗?当循环执行到i为5时,continue语句的作用是跳过本次循环,后面的打印指令没有被执行,而直接跳到了判断部分,执行下一次循环。需要注意的是,如果循环的调整是continue后边的话,可能会造成死循环,通过对比下面两段代码,可以说明该问题
两段代码对应的运行结果如下:
可以看到,右边的代码陷入了死循环。原因是,我们误把while循环的调整部分放到了continue语句的后面,以至于当i为5时,continue语句直接就跳过了后面的调整部分,所以i的值一直就没有发生变化,导致无法跳出循环。总结一下就是,在使用break语句和continue语句时,应当注意该循环的调整位置有没有被跳过,导致出现bug。
4.3循环的嵌套
有时候,仅靠一层循环可能并不能解决问题,往往要将多层循环放在一起,进行嵌套,才能解决对应问题。下面,我们就看一个例子
例:找出100~200之间的素数,并打印在屏幕上。
注:素数⼜称质数,只能被1和本⾝整除的数字。
想要实现这个功能,我们首先需要一层循环,来遍历100-200的数字,然后在循环内部,对是不是素数进行判断。由于素数只能被1和本身整除,所以对循环内的每一个数都要从2到n-1的每一个数进行取模运算,如果余数都不为0,则该数为素数,如果有一次为0,那么它就不是素数。下面给出源代码
#include <stdio.h>
int main()
{
int i=0,j=0;
for (i=101;i<=200;i++) //外层循环遍历100-200的数
{
int flag=1; //定义flag作为标志
for (j=2;j<i;j++) //内层循环完成对每一位数进行取模运算的操作
if (i%j==0)
{
flag=0; //如果余数为0,则不是素数,将flag改为0并跳出循环
break;
}
if (flag==1) //如果flag一直没有改变,说明都无法整除,即该数为素数
printf("%d ",i);
}
return 0;
}
运行结果:
当然,上述代码还有一些可以优化的地方,比如素数只可能在奇数里出现,所以外层循环的调整部分也可改为i=i+2,这里就不作过多的讨论了,有兴趣的读者可以自行去对该算法进行优化。
4.4goto语句
C语⾔提供了⼀种⾮常特别的语法,就是 goto 语句和跳转标号, goto 语句可以实现在同⼀个函数内跳转到设置好的标号处。看下面这个例子
#include <stdio.h>
int main()
{
printf("好好学习,不摆烂\n");
goto next;
printf("不想学习,想摆烂\n");
next:
printf("所以我们要好好学习\n");
return 0;
}
运行结果:
可以看到,goto语句跳过了“打印:不想学习,想摆烂”这条语句,所以我们一定要好好学习(bushi) 这就是goto语句的作用。不过,goto语句如果使用不当,则会在函数内部到处跳转,打乱程序的执行顺序,比较容易就陷入死循环。因此,建议在程序中尽可能少的使用goto语句。