时间:2023-01-18 11:01:15 | 栏目:C代码 | 点击:次
大多数情况下,我们所熟知的输入输出都是标准I/O(标准输入输出),也就是我们在写代码时会直接从键盘读取,从屏幕输出。但是当我们涉及到数据统计或者多组未定义内容输入时,我们的程序就会出现一些小问题
int n = 0; while(scanf("%d",&n)==1)
按照常理来说,这里 scanf
的返回值是成功输入的数的个数,输入一但结束,scanf 函数就无法继续读取 n,返回0,我们测试一下,输入“1,2,3,4,5”看看,好家伙,根本没有结果显示。是代码问题还是运行太慢?其实是还在等待输入,虽然我们可能觉得一个回车就可以搞定,但程序不会。
记得 scanf 的输入格式上对于空格,Tab,Enter键都是一视同仁,那如何才能告诉 程序我们输入结束了呢?在Windows下,输入完毕后先按Enter键,再按Ctrl+Z键,最后再按Enter才能结束输入。在Linux下,只需Ctrl+Z即可结束输入。
也就是说上面的程序不是很方便,每次测试需要手动输入很多数,如果面对多组输入并且需要大量验证的测试,数据也只能保存在命令行中,仍然不够方便。
以上场景我们有个好的方法就是用文件把输入输出的数据放在文件里面,也就是所谓的输入输出重定向,放入事先准备好的数据,就不必每次重复输入了,也可以太多的输出一卷屏跑出来,属实不方便,而且在文件中放好标准的答案,可以很方便的进行比对,无需我们再去逐一的排查。有个不争的事实就是几乎所有算法的输出数据和标准答案都是放在文件里的。
在使用输入输出重定向时,只需在main函数的入口处加入两条语句:
freopen("input.txt","r","stdin"); freopen("output.txt","w","stdout");
其作用很简单,就是使得scanf从文件 input.txt 读入,printf 再从output.txt输出。
我们给出一个代码:
#define Max #include<stdio.h> int main() { #ifdefine Max freopen("input.txt","r","stdin"); freopen("output.txt","w","stdout"); #endif }
#ifdefine Max
,#endif
的特殊之处就是我们只有在Max被定义了情况下才可以编译这两条 freopen 语句。事实上不只scanf 和 printf,所用从键盘键入从屏幕输出的数据都会改用文件,这确实方便,但在很多算法竞赛中禁止访问文件,甚至允许访问文件却禁止使用 freopen 这样的重定向读写文件。这种特殊情况我们又该作何打算呢?没错,那就是 fopen 函数
fopen函数表达式为:
FILE *fopen(char *filename, *type);
这个表达式不细说,只作了解,又是一堆晦涩陌生的名词,有兴趣的可以自行搜索。
我们来看个代码:
FILE *fin,*fout; fin = fopen("test.in","r"); fout = fopen("test.out","w"); fclose(fin); fclose(fout);
这里先声明了变量fin 和 fout,后续如果要输入输出我们需要把printf改为fprintf ,把 scanf 改为 fscanf,最后fclose关闭两个文件。
fopen和 freopen长的差不多,起初我甚至觉得他们就是一个东西,freopen和fopen之间有各自的优劣,重定向的方法写起来简单自然,但不能同时读写文件与标准输入输出;fopen写法稍微繁琐一点,但灵活性更大,就可以反复打开和读写文件。
这里的fscanf,fprintf都是针对数据流的,而什么是数据流?
数据流是一组有序,有起点和终点的字节的数据序列,包括输入流和输出流。就像水管里的水流,在水管的一端一点一点地供水,而在水管的另一端看到的是一股连续不断的水流。数据写入程序可以是一段、一段地向数据流管道中写入数据,这些数据段会按先后顺序形成一个长的数据流。对数据读取程序来说,看不到数据流在写入时的分段情况,每次可以读取其中的任意长度的数据,但只能先读取前面的数据后,再读取后面的数据。不管写入时是将数据分多次写入,还是作为一个整体一次写入,读取时的效果都是完全一样的。
“流是磁盘或其它外围设备中存储的数据的源点或终点。”
而对于fscanf 的使用难点在于以下几点:
上述问题,网上的文章都语焉不详,具体内容参见 fscanf详谈
当我们想把fopen的程序改成标准输入输出,只需赋值"fin = stdin;fout = stdout",不用再调用fopen和fclose。