(一)改错题
序列求和:输入一个正实数eps,计算序列部分和 1 - 1/4 + 1/7 - 1/10 + ... ,精确到最后一项的绝对值小于eps(保留6位小数)。
输入输出样例:
Input eps:1E-4
s = 0.835699
源程序(有错误的程序)
#include<stdio.h>
int main()
{
int flag,n;
double eps,item,s;
printf("Input eps: ");
scanf("%f",&eps);
flag = 1;
s = 0;
n = 1;
do{
item = 1/ n;
s = s + flag * item;
flag = -flag;
n = n + 3;
}while( item < eps)
printf( "s = %f\n",s);
return 0;
}
错误信息1:
错误原因1:do...while语句中while需要在后面加分号
改正方法1:在while后面加上分号
错误信息2:
错误原因2:n为整型变量,所以输出为0或1
改正方法2:将1改为1.0,强制转换
错误信息3:
错误原因3:while中应为循环开始的语句,而题中给出的为循环结束的语句
改正方法3:将item < eps改为item >= eps
错误信息4:
错误原因4:题中定义的eps为double格式
改正方法4:将%f改为%lf
改正后与输出样例相符
给出改正后的代码
#include<stdio.h>
int main()
{
int flag,n;
double eps,item,s;
printf("Input eps: ");
scanf("%lf",&eps);
flag = 1;
s = 0;
n = 1;
do{
item = 1.0 / n;
s = s + flag * item;
flag = -flag;
n = n + 3;
}while( item >= eps);
printf( "s = %f\n",s);
return 0;
}
(二)学习总结
1.语句while(1)和for(;;)是什么意思?,如何保证这种循环能正常执行?
答:while(1)表示无限循环,当括号里的数字为1时,表示为真,执行循环语句,当括号里的数字为0时,表示为假,跳出循环。
for(;;)表示已知循环次数时用for语句,表达式1是赋初值,表达式2是判断循环条件,表达式3是步长。先执行表达式1,再进行表达式2,接着执行循环体,然后执行表达式3,再进行表达式2,再执行循环体,然后再回到表达式3,直到表达式2不成立,跳出循环。所以for(;;)也为无限循环。若程序中没有停止标志,则一直执行下去,在程序中加入break,则停止循环。
2.一般情况下,设计循环结构时,使用for、while、do while三种语句都可以,并且三种语句可以相互转换,但是,在某些特定情况下,我们应该优先选择某种语句来快速实现循环设计。如果有如下情况:
(1)循环次数已知
(2)循环次数未知,但循环条件在进入循环时明确
(3)循环次数未知,且循环条件在进入循环时未知,需要在循环体中明确
针对上面三种情况,分别采用什么循环语句实现比较好?对每种情况,用我们完成的两次循环结构作业中的题目加以说明。
当循环次数已知时,用for语句循环,先判断后执行;当循环次数未知,但给出了循环条件结束时的条件时,用while语句循环,也是先判断后执行;当循环体至少执行一次时,用do...while语句循环,先执行后判断。
for语句:以PTA循环结构(一)第一题为例,题目为:计算序列 1 + 1/3 + 1/5 + ... 的前N项之和。
这道题用for比较方便,题中明确给出了循环次数,给次数赋初值,明确了循环条件和步长,就可以得出答案。
while语句:以PTA循环结构(二)第七题为例,题目为:对方不想和你说话,并向你扔了一串数…… 而你必须从这一串数字中找到“250”这个高大上的感人数字。
这道题就是典型的用while语句,不知道循环多少次,但知道循环结束的条件,当输入的数字第一次遇到250时,循环结束。
do...while语句:以PTA循环结构(二)第六题为例,题目为:掉入陷阱的数字。
这道题的要求就是当这一次的输出的结果和上一次的输出结果相同时输出,所以需要先循环一次,再进行判断,直到输出。所以用do...while是合适的。
3.有如下问题:输入一批学生成绩,以-1作为结束,计算学生的平均成绩。
要求分别用for语句、while语句、do while语句三种循环语句实现,并说明你认为哪种形式更合适?
(1)for语句程序:
#include <stdio.h>
int main(void)
{
int grade = 0,sum = 0,i = 0;
double average = 0.0;
for(;;)
{
scanf("%d",&grade);
if(grade != -1)
{
sum = sum + grade;
i++;
}
else
{
break;
}
}
average = sum/i;
printf("%f",average);
return 0;
}
(2)while语句程序:
#include <stdio.h>
int main(void)
{
int grade = 0,sum = 0,i;
double average = 0.0;
i = 1;
while(grade != -1)
{
scanf("%d",&grade);
sum = sum + grade;
i++;
}
average = (sum+1)/(double)(i-1);
printf("%f",average);
return 0;
}
(3)do...while语句程序:
#include <stdio.h>
int main(void)
{
int grade = 0,i = 0,sum = 0;
double average = 0.0;
do
{
scanf("%d",&grade);
sum = sum + grade;
i++;
}
while(grade != -1);
average = (sum+1)/(double)(i-1);
printf("%f",average);
return 0;
}
我觉得for语句循环比较简单易懂,并且方便,while语句和do...while语句很相似,不同的地方是判断循环进行的条件位置不同。但while语句比较简洁,不需要循环重复很多遍。while语句在题目输入-1时,会将-1也算进去,需要特别说明。综上,我觉得for语句更加合适。
4.运行下面程序,输入1到10,结果分别是什么?为什么?
(1)
#include<stdio.h>
int main()
{
int n,s,i;
s = 0;
for(i = 1; i <= 10; i++)
{
scanf("%d",&n);
if(n % 2 == 0)
break;
s = s + n;
}
printf("s = %d\n",s);
return 0;
}
结果如下:
(2)
#include<stdio.h>
int main()
{
int n,s,i;
s = 0;
for(i = 1; i <= 10; i++)
{
scanf("%d",&n);
if(n % 2 == 0)
continue;
s = s + n;
}
printf("s = %d\n",s);
return 0;
}
结果如下:
两个程序唯一的不同就是第一个用break控制循环语句,第二个用continue控制循环语句。break控制就是跳出循环体,执行循环外的语句,而第一个程序在输入2时就已经跳出循环了,所以答案为s=1;continue控制是结束本次循环,跳出本次未执行的循环语句,再执行下一次循环语句,直到结束。这个语句求的是1-10的奇数和,所以答案为s=25。
(三)实验总结
本次实验总结,完成循环结构(2)中的1、2、3题。
第一题:求给定精度的简单交错序列部分和
(1)题目:计算序列部分和 1 - 1/4 + 1/7 - 1/10 + ... 直到最后一项的绝对值不大于给定精度eps
(2)流程图:
(3)源代码:
#include <stdio.h>
#include <math.h>
int main()
{
double eps,item,S = 0;
int denominator = 1,flag = 1;
item = 1.0;
scanf("%lf",&eps);
if(eps >= item)
{
S = 1.0;
}
while(fabs(item) > eps)
{
item = flag *1.0 / denominator;
S = S + item;
flag = -flag;
denominator = denominator + 3;
}
printf("sum = %.6f",S);
return 0;
}
(4)实验分析:
问题1:结果最后输出为0.000000
原因1:item定义为double类型,flag*1为0
解决方法1:将1改为1.0
问题2:这个程序用while语句是错误的
原因2:这个程序必须执行一次才能循环
解决方法2:将while语句改为do...while语句
(5)本题PTA提交列表
第二题:猜数字游戏
(1)题目:令游戏机随机产生一个100以内的正整数,用户输入一个数对其进行猜测,需要你编写程序自动对其与随机产生的被猜数进行比较,并提示大了(“Too big”),还是小了(“Too small”),相等表示猜到了。如果猜到,则结束程序。程序还要求统计猜的次数,如果1次猜出该数,提示“Bingo!”;如果3次以内猜到该数,则提示“Lucky You!”;如果超过3次但是在N(>3)次以内(包括第N次)猜到该数,则提示“Good Guess!”;如果超过N次都没有猜到,则提示“Game Over”,并结束程序。如果在到达N次之前,用户输入了一个负数,也输出“Game Over”,并结束程序。
(2)流程图:
(3)源代码:
#include <stdio.h>
int main()
{
int num,N,i,a;
i = 1;
scanf("%d %d",&num,&N);
do
{
scanf("%d",&a);
if(a < 0)
{
printf("Game Over");
break;
}
else if(a == num && i <= N)
{
if(i == 1)
{
printf("Bingo!");
break;
}
else if(i <= 3)
{
printf("Lucky You!");
break;
}
else if(i > 3 && i <= N)
{
printf("Good Guess!");
break;
}
}
else if(i > N)
{
printf("Game Over");
break;
}
else if(a > num)
{
printf("Too big\n");
}
else if(a < num)
{
printf("Too small\n");
}
i++;
}
while(num != a);
return 0;
}
(4)实验分析:
问题1:当输入的数字大于次数时,结束程序,输出结果
原因1:没有在输入的数字和次数相等时结束
解决方法1:将i>N改为i>=N
问题2:当输入负数时仍可输出
原因2:没有在if语句后面加break
解决方法2:在第13行加上break
(5)本题PTA提交列表
第三题:求奇数和
(1)题目:本题要求计算给定的一系列正整数中奇数的和。
(2)流程图:
(3)源代码:
#include<stdio.h>
int main(void)
{
int n = 0,sum = 0;
do
{
scanf("%d",&n);
if(n % 2 == 1)
{
sum = sum+n;
}
else
{
}
}
while(n > 0);
printf("%d",sum);
return 0;
}
(4)实验分析:
问题1:一开始用的while语句,但是不能很好理解
原因1:本题更应该用do...while语句
解决方法1:把循环改为do...while无限循环
(5)本题PTA提交列表
(四)博客互评
幕曦:改错题步骤清楚,并且实验分析简洁清楚,非常细致,还附上了改错完成后的源代码,这一点值得我学习
(http://www.cnblogs.com/yjy751522356/p/7838296.html)
侯冠达:改错题我感觉有一个你没有改出来,就是保留六位小数那里,但是实验总结和学习总结你完成的很好,思路很清晰,需要向你学习。
(http://www.cnblogs.com/HGD980425/p/7837319.html)
lucky you:改错题条理清楚,过程简洁明了,但是在实验分析中的源代码部分,最后是用markdown格式,具体如何操作,老师已经在群里说过了,群文件里有,希望改正。
(http://www.cnblogs.com/LYFRRS/p/7854183.html)
风离你在:本次博客园作业完成迅速,思路也很清晰,格式很规范。
(http://www.cnblogs.com/GX201701-/p/7828562.html)