在程序设计中,如果需要重复执行某些操作,就要用到循环结构。所以在使用循环结构编程时,
要明确:
哪些操作需要反复执行? | 这些操作在什么情况下重复执行? |
---|---|
循环体 | 循环条件 |
明确后就可以选用C语言中的for,while和do-while来实现循环。
首先来看看while语句。
while语句
除了for语句,while语句也用于实现循环,且它的适用面更广,一般形式为:
♾️ c 代码: while ( 表达式)
循环体语句; //一条语句
首先判断表达式的真假,如果值为真,循环执行,直到表达式的值为假,循环终止并继续执行while的下一条语句。
for,while都是在循环前先判断条件
把 for 语句改写成 while 语句
♾️ c 代码: for (表达式1; 表达式2; 表达式3)
循环体语句
修改为while语句:
♾️ c 代码:表达式1;
while (表达式2) {
for的循环体语句;
表达式3;
}
注意:修改的前提是for的循环体语句中没有使用continue语句。
for循环和while循环的区别:
for是计数循环;
while是无法计数时使用。
实例1:求平均成绩
从键盘输入一批学生的成绩,计算平均成绩,并统计不及格学生的人数。
代码如下:
# include <stdio.h>
int main (void)
{
int count, num; double score, total;
num = 0; total = 0; count=0;
printf ("Enter scores: \n");
scanf ("%lf", &score); /* 输入第1个数*/
while (score >= 0) { /* 输入负数,循环结束 */
total = total + score; //累加成绩
num++;
if (score < 60) {
count++;
}
scanf ("%lf", &score); //读入一个新数据,为下次循环做准备
}
if (num != 0) {
printf("Average is %.2f\n", total/num);
printf("Number of failures is %d\n", count);
} else {
printf("Average is 0\n");
}
return 0;
}
运行结果:
♾️ c 代码:Enter scores: 67 88 73 54 82 -1
Average is 72.80
Number of failures is 1
实例2:统计一个整数的位数
从键盘读入一个整数,统计该数的位数。
以12345为例:
12345/10=1234;
1234/10=123;
123/10=12;
12/10=1;
1/10=0.
计算了5次,当输出为0时输出结果,所以12345是一个五位数。
由于需要处理的数据有待输入,故无法事先确定循环次数。故引用do-while循环。
代码如下:
♾️ c 代码:int main (void)
{
int count, number, t_number;
printf ("Enter a number: ");
scanf ("%d", &number) ;
t_number = number;//保护输入数据
if (t_number < 0){
t_number = - t_number;
}
count = 0;
do {
t_number = t_number / 10;
count ++;
} while (t_number != 0);
printf ("It contains %d digits.\n", count);
return 0;
}
运行结果:
♾️ c 代码:Enter a number: 12534
It contains 5 digits.
do-while语句
特点:先执行循环体,后判断循环条件。无论循环条件的值如何,
至少会执行一次循环体
一般形式为:
♾️ c 代码:do {
循环体语句
} while (表达式)
实例3:将一个整数逆序输出
分离方法:
对10求余,从低位开始分离。
设n=12345,从低位开始分离:
12345%10=5;继续求余,但需先将n的值改变为1234:12345/10=1234.
重复上述操作:
1234%10=4
1234/10=123;
123%10=3
123/10=12;
12%10=2
12/10=1;
1%10=1
1/10=0
当n最后等于0时,处理过程结束。
由上述操作可得:
- 需重复处理的操作:
n%10,分离一位,
n/10,为下一次分离做准备; - 循环条件:
n!=0.
代码如下:
♾️ c 代码:scanf ( "%d", &number );
do{ //输入0,循环也要执行一次
digit = number %10; //分离一位,
number = number / 10; //为下一次分离做准备;
printf ( "%d ", digit );
} while ( number != 0 ) //n==0时跳出循环
输出结果:
♾️ c 代码:12345
5 4 3 2 1
实例4:判断素数
输入一个正整数m,判断它是否为素数。素数就是只能被1和自身整除的正整数,1不是素数,2是素数。
判断一个数m是否为素数,需要检查该数是否能被1和自身以外的其他数整除,即判断m是否能被2到m-1之间的整数整除。用求余运算来判断整除余数为0,表示能被整除,否则就不能被整除。
代码如下:
♾️ c 代码:int i, limit, m;
scanf ("%d", &m);
if(m <= 1){
printf ("No!\n");
}else if(m == 2){
printf ("Yes!\n");
}else{
limit = sqrt(m) + 1; /* 考虑浮点数运算误差 */
for (i = 2; i <= limit; i++){
if (m % i == 0){
break;
}
}
}
if (i > limit)
printf ("Yes!\n");
else
printf ("No!\n");
}
运行结果:
♾️ c 代码:2
Yes
break语句和continue语句
我们通过一个表格来区别这两种语句。
break | continue |
---|---|
强制循环结束 | 跳过后面语句继续下一次循环 |
不再执行循环体中位于其后的其他语句 | 跳过循环体中continue后的语句,继续下一次循环 |
和if语句配合使用,满足条件时才跳出循环 | |
可用于中止循环和switch语句 | 只能用于循环 |
实例5:猜数游戏
代码如下:
♾️ c 代码:int count = 0, flag, mynumber, yournumber;
mynumber = 38; /* 计算机指定被猜的数 */
flag = 0; /* flag: 为0表示没猜中,为1表示猜中了*/
while (count < 7){ /* 最多能猜7次 */
printf ("Enter your number: ");
scanf ("%d", &yournumber);
count++;
if ( yournumber == mynumber ) { /* 若相等,显示猜中 */
printf ("Lucky You!\n");
flag = 1;
break; /* 已猜中,终止循环 */
}else if ( yournumber > mynumber ) printf("Too big\n");
else printf("Too small\n");
}
if ( flag == 0 ) /* 超过7次还没猜中,提示游戏结束 */
printf ("Game Over!\n");
运行结果:
♾️ c 代码:38
Lucky You!
实例6:求阶乘和1! + 2! + … + n!
代码如下:
♾️ c 代码:# include <stdio.h>
double fact (int n);
int main (void)
{
int i, n;
double sum;
printf("Enter n: ");
scanf("%d", &n);
sum = 0;
for ( i = 1; i <= n; i++ ){
sum = sum + fact (i);
}
printf ("sum = %.0f\n", sum);
return 0;
}
double fact (int n) // 定义求n!的函数
{
int i;
double result;
if(n < 0) return 0;
result = 1;
for ( i = 1; i <= n; i++){
result = result * i ;
}
return result ;
}
运行结果:
♾️ c 代码:Enter n: 15
Sum = 1401602636313
嵌套循环
♾️ c 代码:sum = 0;
for ( i = 1; i <= n; i++ ) {
item = 1; /* 每次求阶乘都从1开始 */
for (j = 1; j <= i; j++){ /* 内层循环算出 item = i! */
item = item * j;
}
sum = sum + item;
}
上述循环即为嵌套循环,在for循环中嵌入一个for循环。
- 外层循环变量 i 的每个值,内层循环变量 j 变化一个轮次;
- 内外层循环变量的名字不能相同,分别用 i 和 j。
循环结构程序设计
注意区分循环结构和分支结构。
循环结构的实现要点:
归纳出哪些操作需要反复执行?——循环体
这些操作在什么情况下重复执行? ——循环条件循环次数=外循环次数*内循环次数
实例7:求最值
输入一批学生的成绩,求最高分。
先输入一个成绩,假设它为最高分,然后在循环中读入下一个成绩,并与最高分比较,如果大于最高分,就设它为新的最高分,继续循环,直到所有的成绩都处理完毕。
一般有以下两种途径:
for语句:
♾️ c 代码:
代码如下:#include <stdio.h> int main(void) { int i, mark, max, n; printf("Enter n: "); scanf ("%d", &n); printf("Enter %d marks: ", n); scanf ("%d", &mark); /* 读入第一个成绩 */ max = mark; /* 假设第一个成绩是最高分 */ for (i = 1; i < n; i++ ){ scanf ("%d", &mark); if (max < mark){ max = mark; } } printf("Max = %d\n", max); return 0; }
while语句
♾️ c 代码:
代码如下:#include <stdio.h> int main(void) { int mark, max; printf(“Enter marks:"); scanf ("%d", &mark); /* 读入第一个成绩 */ max = mark; /* 假设第一个成绩最高分 */ while (mark >= 0){ if(max < mark){ max = mark ; } scanf ("%d", &mark ); }; printf("Max = %d\n", max); return 0; }
实例8:斐波那契(Fibonacci)数列问题
输出斐波那契(Fibonacci)数列的前n项(1<=n<=46) ,每行输出5个。
任一项数字是前两项的和,最开始两项均为1。
1, 1, 2, 3, 5, 8, 13, ……即任意项数字是前两项的和的数列。
代码如下:
♾️ c 代码: int i,n,x1,x2,x;
printf("Enter n: ");
scanf ("%d", &n);
if(n < 1 || n > 46){
printf("Invalid.\n");
}else if (n == 1){
printf ("%10d", 1); /* 输出第1项 */
}else{
x1 = 1;
x2 = 1; /* 头两项都是1 */
printf ("%10d%10d", x1, x2); /* 先输出头两项 */
for (i = 3; i <= n; i++) { /* 循环输出后n-2项 */
x = x1 + x2; /* 计算新项 */
printf("%10d", x);
if(i % 5 == 0){
printf("\n");
}
x1 = x2;
x2 = x;
}
}
return 0;
运行结果:
♾️ c 代码:Enter n: 10
1 1 2 3 5
8 13 21 34 55
本题采用迭代的方法计算斐波那契数列,迭代法也称辗转法,是一个不断从变量的旧值递推新值的过程,跟迭代法相对应的是直接法(或者称为一次解法),即一次性解决问题。
实例9:素数问题
输入2个正整数m和n(1<=m<=n<=500),输出m到n之间的全部素数,每行输出10个。
素数就是只能被1和自身整除的正整数,1不是素数,2是素数。
采用二重循环嵌套:
for (k = m; k <= n; k++)
if (k是素数) printf( "%d", k);
代码如下:
♾️ c 代码: printf("Enter m n: ");
scanf ("%d%d", &m, &n);
if(m < 1 || n > 500 || m > n)
printf("Invalid.\n");
else{
for(k = m; k <= n; k++){
if (k <= 1) flag = 0;
else if (k == 2) flag = 1;
else{
flag = 1; /* 先假设k是素数 */
limit = sqrt(k) + 1;
for(i = 2; i <= limit; i++){
if(k % i == 0){ /* 若k能被某个i整除,则k不是素数 */
flag = 0; /* 置flag为 0 */
break; /* 提前结束循环 */
}
}
}
if (flag == 1){ /* 如果k是素数 */
printf("%6d", k); /* 输出k */
count++; /* 累加已经输出的素数个数 */
if(count % 10 == 0) printf("\n");
}
}
}
return 0;
实例10:搬砖问题(三重嵌套)
某地需要搬运砖块,已知男人一人搬3块,女人一人搬2块,小孩两人搬一块。
问用n人正好搬n块砖,有多少种搬法?
代码如下:
limit_m = n/3; limit_w = n/2;
for(men = 0; men <= limit_m; men++){
for(women = 0; women <= limit_w; women++){
child = n - men - women;
if((men*3 + women*2 + child*0.5 == n)){
printf("men=%d, women=%d, children=%d\n", men, women, child);
}
}
}
实例11:找零钱问题
有足够数量的5分、2分和1分的硬币,现在要用这些硬币来支付一笔小于1元的零钱money,问至少要用多少个硬币?
输入零钱,输出硬币的总数量和相应面额的硬币数量。
硬币总数最小:优先考虑使用面值大的硬币
采用三重循环嵌套
按照5分、2分和1分的顺序,从上限(money/币值)到下限(0)
代码如下:
♾️ c 代码:flag = 1; /* flag表示是否中止嵌套循环 */
printf("Enter money: "); scanf("%d", &money);
for (n5 = money/5; (n5 >= 0) && (flag == 1); n5--){
for (n2 = (money-n5*5)/2; (n2 >= 0) && (flag == 1); n2--){
for (n1 = money-n5*5-n2*2; (n1 >=0) && (flag == 1); n1--){
if ((n5*5 + n2*2 + n1) == money) {
printf("fen5:%d, fen2:%d, fen1:%d, total:%d\n", n5, n2, n1, n1+n2+n5);
/* 置flag为 0,则三重循环的条件都不满足,中止嵌套循环 */
flag = 0;
}
}
}
}