4.1 用格雷戈里公式求$\pi$的近似值(while语句)
4.2 统计一个整数的位数(do-while语句)
4.3 判断素数(break和continue语句)
4.4 求1!+2!+...+n!(循环嵌套)
4.5 循环结构程序设计
例4-1. 使用格雷戈里公式求$\pi$的近似值
要求精确到最后一项的绝对值小于给定精度eps $$ \frac{\pi}{4}=1-\frac{1}{3}+\frac{1}{5}-\frac{1}{7}+\ldots $$
循环结束条件: |item|<eps
循环条件: |item|>=eps --> fabs(item)>=eps
参照
flag=1;
denominator=1;
item=1;
sum=0;
for(i=1;i<=n;i++) /* 替换为while(fabs(item)>=eps) */
{
sum=sum+item;
flag=-flag;
denominator=denominator+2;
item=flag*1.0/denominator;
}
#include<stdio.h>
#include<math.h>
int main()
{
int denominator, flag;
double item, pi;
flag=1; denominator=1; item=1.0; pi=0;
while(fabs(item)>=eps)
{
pi=pi+item;
flag=-flag;
denominator=denominator+2;
item=flag*1.0/denominator;
}
pi=pi+item;
pi=pi*4;
printf("pi=%.4f\n", pi);
return 0;
}
从第1项到倒数第2项,fabs(item)>eps,最后一项fabs(item)<eps
while(条件)
循环体语句; /* 一条语句或者多条复合语句 */
注意区分循环体和循环条件
for(表达式1; 表达式2; 表达式3)
循环体语句
表达式1;
while(表达式2){
for的循环体语句;
表达式3;
}
for循环
sum=0;
for(i=1;i<=10;i++)
{
sum=sum+i;
}
while循环
sum=0;
i=1; /* 循环变量赋初值 */
while(i<=10) /* 循环条件 */
{
sum=sum+i;
i++; /* 循环变量改变值 */
}
比较:
total=0;
count=0;
for(i=1;i<=n;i++)
{
scanf("%lf", &score);
total=total+score;
if(score<60)
{
count++;
}
}
如何确定循环条件?
确定循环条遥
从for循环到while循环
total=0;
count=0;
for(i=1;i<=n;i++)
{
scanf("%lf", &score);
total=total+score;
if(score<60)
{
count++;
}
}
num=0;
total=0;
count=0;
scanf("%lf", &score);
while(score>=0)
{
total=total+score;
num++;
if(score<60)
{
count++;
}
scanf("%lf", &score);
}
#include<stdio.h>
int main()
{
int count, num;
double score, total;
num=0; total=0; count=0;
printf("Enter score:\n");
scanf("%lf", &score); /* 输入第1个数 */
while(score>=0) /* 输入负数,循环结束 */
{
total=total+score;
num++;
if(total<60)
{
count++;
}
scanf("%lf", &score);
}
if(num!=0)
{
printf("Average: %.2f\n", total/num);
printf("Number of failures is %d\n", count);
}else
{
printf("Average is 0\n");
}
return 0;
}
sum=0
for(i=1;i
<=n;i++)
sum=sum+i;
item=1.0;
while(fabs(item)>=eps){
......
item=flag*1.0/denominator;
}
scanf("%lf", &score);
while(score>=0){
......
scanf("%lf", &score);
}
例4-3. 统计一个整数的位数
从键盘读入一个整数,统计该数的位数
分析:以
| digit=number%10 | number=number/10 | |
|---|---|---|
| number=495 | 495%10=5 | 495/10=49 |
| number=49 | 49%10=9 | 49/10=4 |
| number=4 | 4%10=4 | 4/10=0 |
| number=0结束 | ||
| 循环结束条件 | 循环条件 | 循环体 |
|---|---|---|
| number==0 | number!=0 | digit=number%10; number=number/10; count++; |
do-while循环
count=0;
do{
digit=number%10;
number=number/10;
count++;
}while(number!=0);
while循环
count=0;
while(number!=0)
{
digit=number%10;
number=number/10;
count++;
}
思考: 两种循环的区别是什么?
while循环
do-while循环
#include<stdio.h>
int main()
{
int count, number;
printf("Enter a number:");
scanf("%d", &number);
if(number<0)
{
number=-number;
}
count=0;
do{
number=number/10;
count++;
}while(number!=0);
printf("It contains %d digits.\n");
return 0;
}
#include<stdio.h>
int main()
{
int count, number, t_number;
printf("Enter a number:");
scanf("%d", &number);
t_number=number;
if(t_number<0) /* 保护输入的数number */
{
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;
}
do{
循环体语句;
}while(表达式);
确定
| 12345%10=5 | 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结束 |
循环不变式:
digit=number%10;
number=number/10;
循环结束条件:
number==0;
#include<stdio.h>
int main()
{
int number;
printf("Enter a number:");
scanf("%d", &number);
do{
printf("%d ", number%10);
number=number/10;
}while(number!=0);
return 0;
}
例4-5. 判断素数
输入一个正整数m,判断它是否为素数。素数指的是只能被1和自身整除的正整数,1不是素数,2是素数
判断素数的依据:除了1和m,不能被其它数整除
设i取值范围在[2, m-1]之间,有
| m | %2 | %3 | %4 | %5 | %(m-1) | |
|---|---|---|---|---|---|---|
| m不是素数-->|| | =0 | =0 | =0 | =0 | ... | =0 |
| m是素数-->&& | !=0 | !=0 | !=0 | !=0 | ... | !=0 |
m不可能被大于m/2的整数整除
i的取值可能有
[2,m-1], [2, m/2], [2, $\sqrt{m}$], [2, $\sqrt{m}+1$]
limit=sqrt(m)+1; /* 考虑浮点数运算误差 */
for(i=2; i<=limit; i++)
{
if(m%i==0)
break;
}
if(i>m/2)
printf("yes\n");
else
printf("no\n");
#include<stdio.h>
#include<math.h>
int main()
{
int m, limit, i;
printf("Enter a number:");
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");
}
return 0;
}
while(expa){
语句1;
if(expb)
break;
语句2;
}
当循环有多个出口时
for(i=2; i<=limit; i++)
if(m%i==0) break;
if(i>limit) print("yes\n");
else printf("no\n");
for(i=2; i<=limit; i++)
if(m%i==0) break;
if(i>limit) print("yes\n");
else printf("no\n");
Enter a number: 9
for(i=2; i<=limit; i++)
if(m%i==0){
printf("no\n");
break;
}
printf("yes\n");
Enter a number: 9
yes
for(i=2; i<=limit; i++)
{
if(m%i==0) printf("no\n");
else printf("yes\n");
}
Enter a number: 9
no
yes
while(expa)
{
语句1;
if(expb)
continue;
语句2;
}
跳过continue后面的语句,继续下一次循环
下述代码的输出结果是什么?
#include<stdio.h>
int main()
{
char c;
int i;
for(i=0; i<10; i++)
{
c=getchar();
if(c=='\n')
continue;
putchar(c);
}
}
输入: abc<Enter>efgh<Enter>123<Enter>
输出的字符:
输出100~200之间所有能被3整除的数
for(i=100; i<=200; i++)
{
if(i%3==0)
printf("%d ", i);
}
for(i=100; i<=200; i++)
{
if(i%3!=0)
continue;
printf("%d ", i);
}
i=100;
while(i<=200)
{
if(i%3!=0)
continue;
printf("%d ", i);
i++;
}
这样对吗?
#include<stdio.h>
int main()
{
int count=0, flag, mynumber, yournumber;
mynumber=38; /* 计算机指定被猜的数 */
flag=0; /* flag为0表示没猜中,1表示猜中 */
while(count<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
{
print("Too small\n");
}
}
if(flag==0) /* 超过7次还没猜中,提示游戏结束 */
printf("Game Over!\n");
return 0;
}
#include<stdio.h>
#include<math.h>
int main()
{
int m, limit, i, flag;
printf("Enter a number:");
scanf("%d", &m);
if(m<=1)
flag=0;
else if(m==2)
flag=1;
else
{
flag=1;
limit=sqrt(m)+1;
for(i=2; i<=limit; i++)
{
if(m%i==0)
{
flag=0;
break;
}
}
if(flag==1)
printf("yes\n");
else
printf("no\n");
}
return 0;
}
#include<stdio.h>
#include<time.h>
int main()
{
int count=0, flag=0, mynumber, yournumber;
srand(time(0));
mynumber=rand()%100+1; /* 随机产生一个1~100之间的被猜数 */
while(count<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
{
print("Too small\n");
}
}
if(flag==0) /* 超过7次还没猜中,提示游戏结束 */
printf("Game Over!\n");
return 0;
}
例4-7. 使用函数求阶乘和
输入一个正整数n(n≤16),计算1!+2!+3!+...+n!。要求定义和调用函数fact(n)计算n的阶乘,如果n是非负数,则该函数返回n的阶乘,否则返回0
#include<stdio.h>
double fact(int n);
int main()
{
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)
{
int i;
double result;
if(n<0)
return 0;
result=1;
for(i=1; i<=n; i++)
result=result*i;
return result;
}
求阶乘的循环:
item=1;
for(i=1; i<=n; i++)
item=item*i;
循环求阶乘加和
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;
}
求1!+2!+3!+...+n!
sum=0;
for(i=1; i<=n; i++)
{
item=1;
for(j=1; j<=i; j++)
{
item=item*j;
}
sum=sum+item;
}
sum=0;
item=1;
for(i=1; i<=n; i++)
{
for(j=1; j<=i; j++)
{
item=item*j;
}
sum=sum+item;
}
求1!+1!2!+...+1!2!...n!
sum=0;
for(i=1; i<=n; i++)
{
item=1;
for(j=1; j<=i; j++)
{
item=item*j;
}
sum=sum+item;
}
内外层循环变量的名字不能相同,分别用
以下代码片段运行结果是什么?内层循环总共执行了多少次?
for(i=1; i<=100; i++)
{
for(j=1; j<=i; j++)
{
printf("%d %d\n", i, j);
}
}
| i=1 | j=1 | 1 1 | No.1 |
| i=2 | j=1 | 2 1 | No.2 |
| j=2 | 2 2 | No.3 | |
| ............ | |||
| i=100 | j=1 | 100 1 | No.4951 |
| j=2 | 100 2 | No.4952 | |
| ...... | ...... | ...... | |
| j=100 | 100 100 | No.5050 | |
sum=0;
for(i=1; i
<=n; i++){
sum=sum+fact(i);
}
item=1.0;
while(fabs(item)>=0.0001){
item=flag*1.0/denominator;
......
}
scanf("%lf", &score);
while(score>=0){
......
scanf("%lf", &score);
}
例4-8. 求最值问题
输入一批学生的成绩,找出最高分
#include<stdio.h>
int main()
{
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(mark>max)
max=mark;
}
printf("max=%d\n", max);
return 0;
}
以"-1"作为成绩输入的结束
#include<stdio.h>
int main()
{
int mark, max;
printf("Enter marks:");
scanf("%d", &mark); /* 读入第一个成绩 */
max=mark; /* 假设第一个成绩是最高分 */
while(mark>=0)
{
if(mark>max)
max=mark;
scanf("%d", &mark);
}
printf("max=%d\n", max);
return 0;
}
#include<stdio.h>
int main()
{
int mark, max;
max=-1; /* 给max赋一个小初值 */
printf("Enter marks:", n);
do{
scanf("%d", &mark);
if(mark>max)
max=mark;
}while(mark>=0);
printf("max=%d\n", max);
return 0;
}
例4-9. 斐波那契问题
输入正整数n(1≤n≤46),输出斐波那契(Fibonacci)数列的前n项:1, 1, 2, 3, 5, 8, 13, ..., 每行输出5个。Fibonacci数列就是满足任一项数字是前两项的和(最开始的两项均定义为1)的数列
x1=x2=1;
x=x1+x2;
x1=x2;
x2=x;
#include<stdio.h>
int main()
{
int i, n, x1, x2, x; /* 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;
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;
}
例4-10. 素数问题
输入2个正整数m和n(1≤m≤n≤500),输出m到n之间的全部素数,每行输出10个。素数就是只能被1和自身整除的正整数,1不是素数,2是素数
for(k=m; k<=n; k++)
if(k是素数)
printf("%d", k);
判断k是否为素数
if(k<=1)
flag=0;
else if(k==2)
flag=1;
else{
flag=1;
limit=sqrt(k)+1;
for(i=2; i<=limit; i++){
if(k%i==0){
flag=0;
break;
}
}
}
if(flag==1)
printf("%d", k);
#include<stdio.h>
#include<math.h>
int main()
{
int count, i, k, flag, limit, m, n;
printf("Enter m, n");
scanf("%d%d", &m, &n);
count=0;
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;
limit=sqrt(k)+1;
for(i=2; i<limit; i++){
if(k%i==0){
flag=1;
break;
}
}
}
if(flag==1){
printf("%d", k);
count++;
if(count%10==0)
printf("\n");
}
}
}
return 0;
}
例4-11. 搬砖问题
某工地需要搬运砖块,书籍男人一人搬3块,女人一人搬2块,小孩两人搬一块。如果想用n人正好搬n块砖,问有哪些搬法?
#include<stdio.h>
int main()
{
int children, men, women, cnt, n;
printf("Enter n:");
scanf("%d", &n);
cnt=0;
for(men=0; men<=n; men++){
for(women=0; women<=n; women++){
for(children=0; children<=n; children++){
if(men+women+children==n && men*3+women*2+children*0.5==n){
printf("men=%d, women=%d, children=%d", men, women, children);
cnt++;
}
}
}
}
if(cnt==0){
printf("None\n");
}
return 0;
}
#include<stdio.h>
int main()
{
int children, men, women, cnt, n;
int men_limit, women_limit;
printf("Enter n:");
scanf("%d", &n);
cnt=0;
men_limit=n/3;
women_limit=n/2;
for(men=0; men<=men_limit; men++){
for(women=0; women<=women_limit; women++){
children=n-men-women;
if(men+women+children==n && men*3+women*2+children*0.5==n){
printf("men=%d, women=%d, children=%d", men, women, children);
cnt++;
}
}
}
if(cnt==0){
printf("None\n");
}
return 0;
}
例4-12. 找零钱问题
有足够数量的5分、2分和1分硬币,现在要用这些硬币来支付一笔小于1元的零钱money,问至少要用多少个硬币?输入零钱,输出硬币的总数量和相应面额的硬币数量
硬币总数最小,优先考虑使用面值大的硬币
采用三重循环嵌套,按照5分、2分和1分的顺序,从上限(money/币值)到下限(0)
#include<stdio.h>
int main()
{
int flag, money, n1, n2, n5; /* n1, n2, n5分别表示5分、2分和1分硬币的数量 */
flag=1; /* 表示是否中止嵌套循环 */
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("n5: %d, n2: %d, n1: %d\n, total: %d", n5, n2, n1, n1+n2+n5);
flag=0;
}
}
}
}
return 0;
}