输入输出重定向与fopen函数——C语言进阶

简介: 正片开始👀大多数情况下,我们所熟知的输入输出都是标准I/O(标准输入输出),也就是我们在写代码时会直接从键盘读取,从屏幕输出。但是当我们涉及到数据统计或者多组未定义内容输入时,我们的程序就会出现一些小问题

正片开始👀

大多数情况下,我们所熟知的输入输出都是标准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函数👏

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 的使用难点在于以下几点:


对空白符的处理(空格、制表符、换行符);

*的用法;

[] 以及 [^] 的用法;

EOF 的处理;

上述问题,网上的文章都语焉不详,具体内容参见 fscanf详谈

当我们想把fopen的程序改成标准输入输出,只需赋值"fin = stdin;fout = stdout",不用再调用fopen和fclose。

相关文章
|
1月前
|
存储 C语言 开发者
【C语言】字符串操作函数详解
这些字符串操作函数在C语言中提供了强大的功能,帮助开发者有效地处理字符串数据。通过对每个函数的详细讲解、示例代码和表格说明,可以更好地理解如何使用这些函数进行各种字符串操作。如果在实际编程中遇到特定的字符串处理需求,可以参考这些函数和示例,灵活运用。
62 10
|
1月前
|
存储 程序员 C语言
【C语言】文件操作函数详解
C语言提供了一组标准库函数来处理文件操作,这些函数定义在 `<stdio.h>` 头文件中。文件操作包括文件的打开、读写、关闭以及文件属性的查询等。以下是常用文件操作函数的详细讲解,包括函数原型、参数说明、返回值说明、示例代码和表格汇总。
51 9
|
1月前
|
存储 Unix Serverless
【C语言】常用函数汇总表
本文总结了C语言中常用的函数,涵盖输入/输出、字符串操作、内存管理、数学运算、时间处理、文件操作及布尔类型等多个方面。每类函数均以表格形式列出其功能和使用示例,便于快速查阅和学习。通过综合示例代码,展示了这些函数的实际应用,帮助读者更好地理解和掌握C语言的基本功能和标准库函数的使用方法。感谢阅读,希望对你有所帮助!
40 8
|
1月前
|
C语言 开发者
【C语言】数学函数详解
在C语言中,数学函数是由标准库 `math.h` 提供的。使用这些函数时,需要包含 `#include <math.h>` 头文件。以下是一些常用的数学函数的详细讲解,包括函数原型、参数说明、返回值说明以及示例代码和表格汇总。
50 6
|
1月前
|
存储 C语言
【C语言】输入/输出函数详解
在C语言中,输入/输出操作是通过标准库函数来实现的。这些函数分为两类:标准输入输出函数和文件输入输出函数。
242 6
|
1月前
|
存储 缓存 算法
【C语言】内存管理函数详细讲解
在C语言编程中,内存管理是至关重要的。动态内存分配函数允许程序在运行时请求和释放内存,这对于处理不确定大小的数据结构至关重要。以下是C语言内存管理函数的详细讲解,包括每个函数的功能、标准格式、示例代码、代码解释及其输出。
63 6
|
1月前
|
C语言 开发者
【C语言】断言函数 -《深入解析C语言调试利器 !》
断言(assert)是一种调试工具,用于在程序运行时检查某些条件是否成立。如果条件不成立,断言会触发错误,并通常会终止程序的执行。断言有助于在开发和测试阶段捕捉逻辑错误。
41 5
|
2月前
|
存储 人工智能 算法
数据结构实验之C 语言的函数数组指针结构体知识
本实验旨在复习C语言中的函数、数组、指针、结构体与共用体等核心概念,并通过具体编程任务加深理解。任务包括输出100以内所有素数、逆序排列一维数组、查找二维数组中的鞍点、利用指针输出二维数组元素,以及使用结构体和共用体处理教师与学生信息。每个任务不仅强化了基本语法的应用,还涉及到了算法逻辑的设计与优化。实验结果显示,学生能够有效掌握并运用这些知识完成指定任务。
60 4
|
2月前
|
C语言
c语言调用的函数的声明
被调用的函数的声明: 一个函数调用另一个函数需具备的条件: 首先被调用的函数必须是已经存在的函数,即头文件中存在或已经定义过; 如果使用库函数,一般应该在本文件开头用#include命令将调用有关库函数时在所需要用到的信息“包含”到本文件中。.h文件是头文件所用的后缀。 如果使用用户自己定义的函数,而且该函数与使用它的函数在同一个文件中,一般还应该在主调函数中对被调用的函数做声明。 如果被调用的函数定义出现在主调函数之前可以不必声明。 如果已在所有函数定义之前,在函数的外部已做了函数声明,则在各个主调函数中不必多所调用的函数在做声明
39 6
|
2月前
|
存储 算法 程序员
C语言:库函数
C语言的库函数是预定义的函数,用于执行常见的编程任务,如输入输出、字符串处理、数学运算等。使用库函数可以简化编程工作,提高开发效率。C标准库提供了丰富的函数,满足各种需求。