例题2-4 数据统计
输入一些整数,求出它们的最小值,最大值和平均值(保留3位小数).
输入保证这些数都是不超过1000的整数.
#include<stdio.h> #define INF 1000000 int main() { int x,n,sum,min,max; min = INF; max = -INF; sum = 0; n = 0; while(scanf("%d",&x) == 1) { if(x >= max) max = x; if(x <= min) min = x; sum += x; n ++; } printf("%d %d %.3lf/n",min,max,(double)sum / n); return 0; }
分析:
1. 首先遇到的问题是:如何在没给出输入确定个数的变量的输入问题.即不知道变量的个数,
就无法定义变量的确定名称.
其实,就算知道了变量的个数,但是这个数量是很大的话,利用scanf来控制输入也是不方
便的(当然,可以采取数组的形式).因此必须采用一种更加方便的方法.
就是 while(scanf("%d",&x)) 这种语句.由于scanf返回值是int型,只要有输入返回就是
成功的变量个数(不等于0).就不断循环.当然,如果输入完毕,可以人为结束:在windows下
先按enter确定输入完毕,再按组合键Ctrl + Z,再按enter键确认.在linux下,按组合键
Ctrl + D;
2. 接下来的问题就是max和min的初值问题:一开始要设置max与min为什么值才能与待输入的
数据正确地比较呢?
一种比较直观的方法是把max设为一个很小的值,把min设为一个很大的值.但是,这样做有
一定的风险,因为你不能确定接下来输入的数据到底有多大,或者有多小(本题中做了约束
是1000).比如你设min初值是1000.但是接下来输入的数据都是比1000大的数据,那么最小
值结果就是错误的.
另一种比较稳妥的方法是将max与min都赋予第一个输入的数据的值,这样,无论如何都不会
出现上面描述的那种情况了.但是程序要稍长一点.
/*重定向版*/ #define LOCAL #include<stdio.h> #define INF 1000000 int main() { #ifdef LOCAL freopen("data.in","r",stdin); freopen("data.out","w",stdout); #endif int x,n,sum,min,max; min = INF; max = -INF; sum = 0; n = 0; while(scanf("%d",&x) == 1) { if(x >= max) max = x; if(x <= min) min = x; //printf("x = %d, min = %d, max = %d/n",x,min,max); sum += x; n ++; } printf("%d %d %.3lf/n",min,max,(double)sum / n); return 0; }
分析: 这份代码是有比赛代码的严谨格式.
1. 重定向部分被写在了#ifdef和#endif中.含义是:只有定义了符号LOCAL,才能
编译两条freopen语句.
2. 输出中间结果的printf语句写在了注释中,既方便调试,又方便提交---只需控
制注释符就行了.
/*fopen版*/ #include<stdio.h> #define INF 10000000 int main() { FILE *fin, *fout; fin = fopen("data.in","rb"); fout = fopen("data.out","wb"); int x, n = 0, min = INF, max = -INF, s = 0; while(fscanf(fin,"%d",&x) == 1) { s += x; if(x < min) min = x; if(x > max) max = x; n++; } //fprintf(fout,"%d %d %.3lf",min,max,(double)s/n); fprintf(fout,"%d %d %.3lf/r/n",min,max,(double)s/n); fprintf(fout,"%d %d %.3lf/r/n",min,max,(double)s/n); // printf("%d %d %.3lf/n",min,max,(double)s/n); fclose(fin); fclose(fout); return 0; }
分析:
fopen版本要先定义FILE *文件指针,将FILE *定义的fin和fout赋值为fopen
打开的文件.将scanf和printf分别改为fscanf与fprintf.最后记得用fclose
关闭fin和fout.
这样看来,fopen版本似乎比重定向版本的语句和修改的部分都要多.那么fopen
版本和重定向版本各有什么优劣呢?
1.从代码形式上看来,重定向方法写起来简单,自然.fopen写法稍显繁琐.但是,
实际上都是很固定的语句.
2.从灵活性上看,重定向方法只要运用,就全部是用文件读写,不能再进行常规的
标准输入输出(即scanf和printf).而fopen版本显得更加灵活,支持同时文件
读写和标准输入输出读写,只要分别用fscanf,fprintf和scanf,printf就能共
存.灵活性更强.
3. 从代码特点上看,重定向方法需要注意#ifdef与#endif符号定义(也可以在编译
选项中实现),从而从文件读写转换为标准输入输出读写比较方便.
而fopen则需要注意要定义FILE *文件指针,利用fopen打开文件.同时,特别需
要注意的是使用完毕后要使用fclose关闭文件指针.从文件读写改为标准输入输
出需赋值fin = stdin; fout = stdout; 同时将注释掉fopen和fclose.修改稍显
复杂.
另:
在使用fprintf进行文件输出时,在输出格式控制时,若用换行符"/n"则会在文本
中打印出实心正方形符号.因为/n虽然在DOS下可以表示换行,但是在文件操作中
需要使用/r/n才能实现正常换行. 重定向版本没有这个问题,应该是因为重定向
版并不算严格意义上的文件操作(没有定义文件指针及没有用文件操作函数).