{算法竞赛入门经典}第二章 文件操作 重定向及fopen版本

 

 

例题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才能实现正常换行. 重定向版本没有这个问题,应该是因为重定向

        版并不算严格意义上的文件操作(没有定义文件指针及没有用文件操作函数). 

 

 

 

你可能感兴趣的:({算法竞赛入门经典}第二章 文件操作 重定向及fopen版本)