第六章循环结构程序设计
6.1 概述(goto循环语句)
循环结构主要用于解决那些需要重复执行的操作;例如:求若干数之和、迭代求根、排序、查找等。
设计循环结构时,要从重复性的操作过程中寻找规律,包括重复执行的代码段和重复执行的条件。
-
常见的循环结构语句:while语句、do…while语句、for语句、goto语句(一般不提倡使用)
-
使用goto语句与if语句一起也可以构成循环结构;goto语句也称为无条件转移语句
-
goto语句一般格式如下:
goto 语句标号; . . . 标号:语句 . . .
-
goto语句的语义是改变程序流向,转去执行语句标号所标识的语句
例:用goto语句构造循环计算1到100的整数和
#include <stdio.h>
void main()
{
int i=1,sum=0;
loop:sum=sum+i;
i++;
if(i<=100)
goto loop;
printf("The sum of 1 to 100 is:%d\n",sum);
}
6.2 while循环语句
由while语句构成的循环称为当型循环,当满足循环条件,执行循环体语句;
-
while语句的一般形式:
while(表达式) 循环语句; /*表达式为循环条件*/
-
while语句特点是先判断表达式,再执行循环体语句
例:统计从键盘输入一行字符的个数
#include <stdio.h>
void main()
{
int n=0;
printf("输入一个字符串:\n");
while(getchar()!='\n') /*只要从键盘输入的字符不是换行符就继续执行循环*/
n++;
printf("%d",n);
}
- 在C语言中,按下enter键时,产生’\r’和’\n’两个字符,标准输入函数接收的是’\n’
-
while语句中的表达式可以是任意合法的表达式,一般是关系表达式或逻辑表达式,只要表达式的值为真(非0)就继续执行循环
-
循环体如果包括一条以上的语句,就必须用花括号{}括起来,组成复合语句
-
选择循环条件必须避免死循环,循环条件必须要能从真变成假,循环体语句可以为空
6.3 do…while循环语句
do…while循环称为直到型循环;先执行循环体语句,再判断表达式,直到while中表达式为假,跳出循环
-
do…while循环一般形式为:
do 循环体语句; while(表达式); /*句末有分号!*/
-
do…while语句的执行过程为先执行一次循环体语句,再判别表达式的值,表达式值为真,则继续循环,直到表达式值为假,跳出循环
例:求整数i,它满足1+2+…+(i+1)<100且1+2+…+i>=100
#include <stdio.h>
void main()
{
int i=0,sum=0;
do
{ i++;
sum=sum+i;
}while(sum<100);
printf("The integer is:%d\n",i);
}
- while和do…while语句很相似,但do…while语句是先执行循环体语句再判断,至少执行一次循环体;而while语句是先判断再选择是否执行循环体语句
例:任意输入一个正整数,将该数各位颠倒顺序输出,如输入1234,输出4321
分析:可对输入的正整数取余来求没位的数字,第一次取余得到个位数字,然后除10,再对10取余得到原正整数的十位数字
- while循环
#include <stdio.h>
void main()
{
int a,b;
printf("输入一个正整数:");
scanf("%d",&a);
while(a!=0)
{
b=a%10;
printf("%d",b);
a=a/10;
}
}
- do…while循环
#include <stdio.h>
void main()
{
int a,b;
printf("输入一个正整数:");
scanf("%d",&a);
do
{
b=a%10;
printf("%d",b);
a=a/10;
}while(a!=0);
}
- 若题目要求输入一个非负整数,使用while循环输入0时无输出,则需要在while循环前添加判断输入为0时的情况
6.4 for循环语句
for循环不仅适用于已知循环次数的情况,也适用于未知循环次数的情况
-
for循环的一般形式为:
for(表达式1;表达式2;表达式3) 循环体语句;
- 表达式1通常用于在进入循环前给某些变量赋值,一般是赋值表达式,整个循环只执行一次,可以放到for循环前面
- 表达式2通常是用来控制循环是否执行的循环条件,一般为关系表达式或逻辑表达式;缺少表达式2系统默认用1代替,这样就陷入死循环
- 表达式3用来修改循环重复时循环控制变量的值,一般是赋值表达式;可以放到for循环内部做循环体语句
- 这三个表达式可以是任意合法的表达式
- 循环体语句若由多条语句组成,必须用花括号括起来
-
for循环的执行流程:
- 计算表达式1的值,没有表达式1则直接进入表达式2
- 计算表达式2的值,若值为真则执行循环体语句1次,为假直接跳出for循环,执行后继语句
- 执行循环体语句
- 计算表达式3的值,然后转回第二步执行表达式2,若无表达式3则直接转回第二步执行表达式2
-
整个for循环过程,表达式1只执行1次,表达式2和3则可能执行多次,循环体可能多次执行,可能一次都不执行
-
for循环中的三个表达式都可以省略,但分号不能省略
例:将所有可显示字符与其ASCII码对照表在屏幕上输出
ASCII码从32(空格)开始到126(’~’)都是可显示字符
#include <stdio.h>
void main()
{
char c;
for(c=32;c<=126;c++)
printf("%c %d\n",c,c);
}
6.5 break和continue语句
break和continue语句都是控制程序的流程转向的跳转语句
6.5.1 break语句
- break语句除了能用在switch语句中还能用在循环语句中跳出本层循环,去执行后继语句
- break语句在循环语句中使用时,一般与if语句配合使用,提前结束循环的目的
- break语句只能在循环语句和switch语句中使用,但break出现在循环体中的switch语句内时,它只是跳出switch语句,并不能终止循环
例:计算r=1到r=10时的圆面积,当面积大于100时终止
#include <stdio.h>
#define PI 3.1415926
void main()
{
int r;
float area;
for(r=1;r<=10;r++)
{
area=PI*r*r;
if(area>100)
break;
printf("r=%d area is: %.2f\n",r,area);
}
}
6.5.2 continue语句
-
continue语句只能用在循环体内,一般形式为:continue;
-
continue语句语义是结束本次循环,不再执行循环体中continue语句之后的语句,转入下次循环条件的判断和执行
-
continue语句一般也要与if语句配合使用,达到结束本次循环的目的
-
在while和do…while语句中,continue语句使得流程直接跳到循环控制条件的判断部分;在for语句中,遇到continue后,跳过循环体中余下的部分,而去对for语句中的表达式3求值
例:输出100以内能被7整除的数
#include <stdio.h>
void main()
{
int a;
for(a=1;a<=100;a++)
{
if(a%7!=0)
continue;
printf("%d ",a);
}
}
不适用continue语句也可以:
#include <stdio.h>
void main()
{
int a;
for(a=1;a<=100;a++)
{
if(a%7==0)
printf("%d ",a);
}
}
6.6 循环的嵌套
循环嵌套指在一个循环的循环体内完整的包含另一个或几个循环结构
- while、do…while、for循环可以互相嵌套
- 嵌套不能交叉,需完整的包含
- 内外循环的循环控制变量不能重名
- 同类或不同类的循环都可以多层嵌套
- 注意内层循环的初值设定以及内层循环体的执行次数和范围
例:演示嵌套循环的执行过程
#include <stdio.h>
void main()
{
int i,j;
for(i=0;i<3;i++)
{
printf("i=%d",i);
for(j=0;j<4;j++)
printf("j=%-4d",j);
printf("\n");
}
}
6.7 循环结构程序设计举例
6.7.1 累加、连乘算法
例:在8×8的棋盘64个格子里,第一个格子放一个豆子,第二个放两个豆子,第三个放4粒依次累计,放满64个格子,设计算法求共放多少豆子,合多少立方米?1立方米豆子约1.42e8粒。
分析:第一个格子放1个,第二个放2个,第三个放4个,以此类推第i个格子放2(i-1)个豆子,则豆子总数便是20+21+22+23+…263
#include <stdio.h>
void main()
{
double sum,t; /*t为累乘器,初值通常为1;sum为累加器,初值有时为0、有时为累加的第一个数;i为计数器, 初值为1,即为2^1的指数*/
int i;
for(t=1,sum=1,i=1;<=63;++)
{
t=t*2;
sum=sum+t;
}
printf("豆子总数为:%e\n",sum);
printf("折合体积为:%e立方米\n",sum/1.42e8);
}
6.7.2 穷举、枚举算法(是指出各种可能的情况,找出符合问题的解答)
例:100块钱,公鸡5块钱,母鸡3块钱,三个鸡崽1块钱,若买100块买100只鸡,公鸡母鸡鸡崽各几只?
分析:公鸡i,母鸡j,鸡崽k,i+j+k=100;5i+3j+k/3=100;如果100块全买公鸡,能买20只,所以i的范围020;全买母鸡,最多能买33只,剩1块,所以j的范围是033;k的范围可以通过i和j来决定
#include <stdio.h>
void main()
{
int i,j,k;
int m=100/5,n=100/3;
for(i=0;i<=m;i++)
{
for(j=0;j<=n;j++)
{
k=100-i-j;
if(i*5+j*3+k/3 == 100&&k%3 == 0)
printf("i=%d,j=%d,k=%d\n",i,j,k);
}
}
}
6.7.3 递推算法(利用前面已知的数据推后面未知的数据)
例:输出斐波那契数列的前40项,每行输出4项,斐波那契数列为:1,1,2,3,5,8,13…,第一项第二项均为1,后面各项均为前两项之和
分析:通项表达式:f1=1 (n=1)
f2=1 (n=2)
fn=fn-1+fn-2 (n>=3)
#include <stdio.h>
void main()
{
long f1,f2;
int i;
f1=f2=1;
for(i=1;i<=20;i++)
{
printf("%12ld %12ld",f1,f2);
if(i%2==0)
printf("\n");
f1=f1+f2;
f2=f1+f2;
}
}
运行情况:
初始f1=f2=1
①:i=1,i=1<=20;进入循环输出右对齐左侧12空格f1=1、f2=1;i=1,1%2不等于0,不输出换行符;f1=2,f2=3
②:此时i经过i++得到i=2<=20;进入循环输出右对齐左侧12空格f1=2、f2=3;i=2,2%2等于0,输出换行符;f1=5,f2=8
③:此时i经过i++得到i=3<=20;进入循环输出右对齐左侧12空格f1=5、f2=8;i=3,3%2不等于0,不输出换行符;f1=13,f2=21
④:此时i经过i++得到i=4<=20;进入循环输出右对齐左侧12空格f1=13、f2=21;i=4,4%2等于0,输出换行符;f1=34,f2=55
.
.
.
⑤:此时i经过i++得到i=19<=20;进入循环输出右对齐左侧12空格f1=24157817、f2=39088169;i=19,19%2不等于0,不输出换行符;f1=63245986,f2=102334155
⑥:此时i经过i++得到i=20<=20;进入循环输出右对齐左侧12空格f1=63245986、f2=102334155;i=20,20%2等于0,输出换行符;f1=165580141,f2=267914296
⑦:此时i经过i++得到i=21,i<=20为假,跳出循环,结束程序
6.7.4 计算x^y
y为整型变量,且y>=0
#include <stdio.h>
void main()
{
float x,z;
int y;
printf("输入x和y:\n");
scanf("%f,%d",&x,&y);
for(z=1;y>0;y--)
z*=x;
printf("z=%f",z);
}
运行情况:
输入x=4,y=5;
①:z=1,y=5>0;进入循环得到z=z*x为z=1*4
②:z=1*4,此时y经过y--得到y=4>0;进入循环得到z=z*x为z=1*4*4
③:z=1*4*4,此时y经过y--得到y=3>0;进入循环得到z=z*x为z=1*4*4*4
④:z=1*4*4*4,此时y经过y--得到y=2>0;进入循环得到z=z*x为z=1*4*4*4*4
⑤:z=1*4*4*4*4,此时y经过y--得到y=1>0;进入循环得到z=z*x为z=1*4*4*4*4*4
⑥:此时y经过y--得到y=0,跳出循环输出z=1*4*4*4*4*4=4^5
6.7.5 输出3~100之间所有素数
判断素数方法:判断一个整数m是否是素数,只需把m被 2 ~ m-1 之间的每一个整数去除,如果都不能被整除,那么m就是一个素数。
#include <stdio.h>
void main()
{
int i,j;
for(i=3;i<=100;i++)
{
for(j=2;j<=i-1;j++)
if(i%j == 0)
break;
if(j == i)
printf("%3d",i);
}
}
运行情况:
①:i=3<=100;
进入内层循环:
1.j=2<=2;此时i=3,j=2,3%2=1!=0;进入j++,此时j=3
2.j=3>2;结束内层循环
此时j=i=3,输出i=3;进入i++,此时i=4
②:i=4<=100;
进入内层循环:
1.j=2<=3;此时i=4,j=2,4%2=0;进入break;结束内层循环
此时j=2,i=4;不输出i;进入i++,此时i=5
.
.
.
6.7.6 证明一个正整数的立方可以写成一连串连续奇数的和
#include <stdio.h>
void main()
{
long int n,i,k,j,sum;
print("输入n=");
scanf("%ld",&n);
k=n*n*n;
for(i=1;i<k/2;i+=2)
{
for(j=i,sum=0;sum<k;j+=2)
sum+=j;
if(sum==k)
printf("%ld*%ld*%ld=%ld=form%ldto%ld\n",n,n,n,sum,i,j-2);
}
}
运行情况:
输入n=5,则k=125
①:i=1<k/2=62
进入内层循环:
1.j=i=1,sum=0<125;则sum=sum+j=1;进入j+=2得j=3
2.sum=1<125;则sum=sum+j=1+3=4;进入j+=2得j=5
3.sum=4<125;则sum=sum+j=4+5=9;进入j+=2得j=7
4.sum=9<125;则sum=sum+j=9+7=16;进入j+=2得j=9
5.sum=16<125;则sum=sum+j=16+9=25;进入j+=2得j=11
6.sum=25<125;则sum=sum+j=25+11=36;进入j+=2得j=13
7.sum=36<125;则sum=sum+j=36+13=49;进入j+=2得j=15
8.sum=49<125;则sum=sum+j=49+15=64;进入j+=2得j=17
9.sum=64<125;则sum=sum+j=64+17=81;进入j+=2得j=19
10.sum=81<125;则sum=sum+j=81+19=100;进入j+=2得j=21
11.sum=100<125;则sum=sum+j=100+21=121;进入j+=2得j=23
12.sum=121<125;则sum=sum+j=121+23=144;进入j+=2得j=25
13.sum=144>125;则不进入内层循环,进入if语句,sum=144!=k=125;进入i+=2,i=3
②:i=3<k/2=62
进入内层循环:
1.j=i=3,sum=0<125;则sum=sum+j=3;进入j+=2得j=5
2.sum=3<125;则sum=sum+j=3+5=8;进入j+=2得j=7
3.sum=8<125;则sum=sum+j=8+7=15;进入j+=2得j=9
4.sum=15<125;则sum=sum+j=15+9=24;进入j+=2得j=11
5.sum=24<125;则sum=sum+j=24+11=35;进入j+=2得j=13
6.sum=35<125;则sum=sum+j=35+13=48;进入j+=2得j=15
7.sum=48<125;则sum=sum+j=48+15=63;进入j+=2得j=17
8.sum=63<125;则sum=sum+j=63+17=80;进入j+=2得j=19
9.sum=80<125;则sum=sum+j=80+19=99;进入j+=2得j=21
10.sum=99<125;则sum=sum+j=99+21=120;进入j+=2得j=23
11.sum=120<125;则sum=sum+j=120+23=143;进入j+=2得j=25
12.sum=143>125;则不进入内层循环,进入if语句,sum=143!=k=125;进入i+=2,i=5
③:i=5<k/2=62
进入内层循环:
1.j=i=5,sum=0<125;则sum=sum+j=5;进入j+=2得j=7
2.sum=5<125;则sum=sum+j=5+7=12;进入j+=2得j=9
3.sum=12<125;则sum=sum+j=12+9=21;进入j+=2得j=11
4.sum=21<125;则sum=sum+j=21+11=32;进入j+=2得j=13
5.sum=32<125;则sum=sum+j=32+13=45;进入j+=2得j=15
6.sum=45<125;则sum=sum+j=45+15=60;进入j+=2得j=17
7.sum=60<125;则sum=sum+j=60+17=77;进入j+=2得j=19
8.sum=77<125;则sum=sum+j=77+19=96;进入j+=2得j=21
9.sum=96<125;则sum=sum+j=96+21=117;进入j+=2得j=23
10.sum=117<125;则sum=sum+j=117+23=140;进入j+=2得j=25
11.sum=140>125;则不进入内层循环,进入if语句,sum=140!=k=125;进入i+=2,i=7
④:i=7<k/2=62
进入内层循环:
1.j=i=7,sum=0<125;则sum=sum+j=7;进入j+=2得j=9
2.sum=7<125;则sum=sum+j=7+9=16;进入j+=2得j=11
3.sum=16<125;则sum=sum+j=16+11=27;进入j+=2得j=13
4.sum=27<125;则sum=sum+j=27+13=40;进入j+=2得j=15
5.sum=40<125;则sum=sum+j=40+15=55;进入j+=2得j=17
6.sum=55<125;则sum=sum+j=55+17=72;进入j+=2得j=19
7.sum=72<125;则sum=sum+j=72+19=91;进入j+=2得j=21
8.sum=91<125;则sum=sum+j=91+21=112;进入j+=2得j=23
9.sum=112<125;则sum=sum+j=112+23=135;进入j+=2得j=25
10.sum=135>125;则不进入内层循环,进入if语句,sum=135!=k=125;进入i+=2,i=9
⑤:i=9<k/2=62
进入内层循环:
1.j=i=9,sum=0<125;则sum=sum+j=9;进入j+=2得j=11
2.sum=9<125;则sum=sum+j=9+11=20;进入j+=2得j=13
3.sum=20<125;则sum=sum+j=20+13=33;进入j+=2得j=15
4.sum=33<125;则sum=sum+j=33+15=48;进入j+=2得j=17
5.sum=48<125;则sum=sum+j=48+17=65;进入j+=2得j=19
6.sum=65<125;则sum=sum+j=65+19=84;进入j+=2得j=21
7.sum=84<125;则sum=sum+j=84+21=105;进入j+=2得j=23
8.sum=105<125;则sum=sum+j=105+23=128;进入j+=2得j=25
9.sum=128>125;则不进入内层循环,进入if语句,sum=128!=k=125;进入i+=2,i=11
⑥:i=11<k/2=62
进入内层循环:
1.j=i=11,sum=0<125;则sum=sum+j=11;进入j+=2得j=13
2.sum=11<125;则sum=sum+j=11+13=24;进入j+=2得j=15
3.sum=24<125;则sum=sum+j=24+15=39;进入j+=2得j=17
4.sum=39<125;则sum=sum+j=39+17=56;进入j+=2得j=19
5.sum=56<125;则sum=sum+j=56+19=75;进入j+=2得j=21
6.sum=75<125;则sum=sum+j=75+21=96;进入j+=2得j=23
7.sum=96<125;则sum=sum+j=96+23=119;进入j+=2得j=25
8.sum=119<125;则sum=sum+j=119+25=144;进入j+=2得j=27
10.sum=144>125;则不进入内层循环,进入if语句,sum=144!=k=125;进入i+=2,i=13
.
.
.
6.7.7 按顺序读入10名学生4门课程的成绩,计算出每位学生的平均分并输出
#include <stdio.h>
void main()
{
int n,k,score,sum;
float ave;
for(n=1;n<=10;n++)
{
sum=0;
for(k=1;k<=4;k++)
{
scanf("%d",&score);
sum+=score;
}
ave=sum/4.0;
printf("NO.%d:%f\n",n,ave);
}
}
6.7.8 三位数,各位数字的立方和等于该数,称为水仙花数,打印出所有水仙花数
#include <stdio.h>
void main()
{
int i,j,k,sum;
for(i=1;i<=9;i++)
for(j=0;j<=9;j++)
for(k=0;k<=9;k++)
{
sum=100*i+10*j+k;
if(sum==i*i*i+j*j*j+k*k*k)
printf("%d ",sum);
}
}
6.7.9 计算并输出n以内最大的10个能被11或19整除的自然数之和。若n值为300,则输出2646
#include <stdio.h>
void main()
{
int sum=0,mix=1,n;
scanf("%d",&n);
while((n>=2)&&(mix<=10))
{
if((n%11==0)||(n%19==0))
{
sum=sum+n;
mix++;
}
n--;
}
printf("%d\n",sum);
}
6.7.10 统计一个无符号整数中各位数字值为0的个数,并求出各位上的最大数字值
例:10080,数字值为0的有3个,各位上数字最大的为8
#include <stdio.h>
void main()
{
unsigned m;
int n=0,max=0,t;
scanf("%d",&m);
do
{
t=m%10;
if(t==0)
n++;
if(max<t)
max=t;
m=m/10;
}while(m);
printf("\n结果是:最大的数字是%d 0有%d个\n",max,n);
}
6.7.11 分式累加和
求1-1/2+1/3-1/4+…+1/99-1/100
#include <math.h>
void main()
{
int s; /*s为分子,且需要来决定各项正负*/
float n,t,sum; /*n为分母,需要累加;t为各项的具体数值;sum为总和*/
t=1;
sum=0;
n=1;
s=1.0;
while(n<=100)
{
sum=sum+t;
n=n+1;
s=-s;
t=s/n;
}
printf("sum=%10.6f\n",sum);
}
6.7.12 1~10的阶乘
求1~10的阶乘,并分别显示在屏幕上
#include <stdio.h>
void main()
{
int i;
long int n=1;
for(i=1;i<=10;i++)
{
n=n*i;
printf("%d ",n);
}
}
6.7.13 由n个*组成的等腰三角形
#include <stdio.h>
void main()
{
int n,i,j;
scanf("%d",&n);
for(i=0;i<=n;i++)
{
for(j=1;j<=n+i-1;j++)
if(j<=n-i)
printf(" ");
else
printf("*")
printf("\n");
}
}
运行情况:
输入7;则n=7
①:i=0<=7;
进入内层循环:
1.j=1<=7+0-1=6;j=1<7-0=7,输出空格
6.7.14 找出1000以内的完数
一个数恰好等于它的因子之和,称为完数;完数6等于1+2+3,
#include <stdio.h>
void main()
{
int m,s,i; /*s为因子和;m为验证是否为完数的数;i为因子*/
for(m=2;m<1000;m++)
{
s=0;
for(i=1;i<m;i++)
if((m%i)==0)
s=s+i;
if(s==m)
{
printf("%d its factors are ",m);
for(i=1;i<m;i++)
if((m%i)==0)
printf("%d ",i);
printf("\n");
}
}
}
6.7.15 打靶
8发打了53环,全部命中10环、7环、5环上,问各打中多少环
#include <stdio.h>
void main()
{
int h10,h7,h5;
for(h10=1;h10<=4;h10++)
for(h7=1;h7<=6;h7++)
for(h5=1;h5<=8;h5++)
if(h10+h7+h5==8&h10*10+h7*7+h5*5==53)
printf("h10=%d,h7=%d,h5=%d",h10,h7,h5);
}
6.7.16猴子吃桃问题
猴子第一天摘下一堆桃子,吃了一半,没吃带劲,又多吃了一个;第二天又把昨天剩下的桃子吃了一半,又没吃带劲,又多吃了一个;往后每天都吃了上一天剩下的多一个;到第10天再吃时,就剩一个了;问第一天摘了多少桃?
分析:第九天吃了第八天剩下的桃一半加1个,然后还剩下一个桃
逆向思维,倒推
#include <stdio.h>
void main()
{
int day,x1,x2; /*day为第几天;x2初始为第九天吃完给第十天剩的桃;x1为第八天吃完给第九天剩的桃*/
day=9;
x2=1;
while(day>0)
{
x1=(x2+1)*2;
x2=x1;
day--;
}
printf("第一天摘得桃为%d个\n",x1);
}
方法二
#include <stdio.h>
void main()
{
}
6.7.17 用牛顿迭代法求方程2x3-4x2+3x-6=0在1.5附近的根
6.7.18 输入两个正整数m和n,求其最大公约数和最小公倍数
利用辗转相除,直到b为0为止
#include <stdio.h>
void main()
{
int p,r,n,m,temp;
printf("输入两个正整数:");
scanf("%d,%d",&n,&m);
if(n<m)
{
temp=n;
n=m;
m=temp;
}
p=n*m;
while(m!=0)
{
r=n%m;
n=m;
m=r;
}
printf("最大公约数是:");
printf("最小公倍数是:");
}