一文看懂 C 语言 I/O
再会吧,这宝贵的片刻和短暂的时机限制了我在情义上的真挚表示,也不能容我们畅叙衷曲,这本来是亲友重逢所应有的机缘;愿上帝赐给我们美好的未来,好让我们开怀畅谈!再一次告别;勇敢作战吧,祝你胜利!——威廉•莎士比亚《查理三世》
0 说在前面
当你看到这篇文章时,不妨回想一下你当初第一次用 C 语言“Hello World!”时是什么样的心情。那是你第一次成功使用神秘代码完成了和计算机的交流。尽管展示信息的黑框框让你可能不大习惯这样一种沟通方式,但这难道不也有点电影里黑客那感觉了~?
不知不觉半年过去了,你为了数据结构作业绞尽脑汁,敲下最后一个分号,鼠标轻点”编译运行“。黑色高级框框跳出来,尴尬而不失礼貌地对你说:
--------------------------------
Process exited after 4.511 seconds with return value 3221225477
请按任意键继续. . .
你质问:
”你怎么了,为什么要这样对我……呜呜~“
是啊,你认识了这个框框那么久,它早已熟悉你写 bug 的习惯,而你却摸不清它的性情。你是时候应该了解一下它了。
1 标准输入输出
”你好,我叫终端,也叫控制台,英文名是 Terminal,也叫 Console,很高兴成为你的朋友。“
”你不记得我啦?我就是你每次运行程序的时候跳出来跟你聊天的那位。请看——“

“其实我并不是你的程序本体,你的程序躲在电脑里面,是它派我来跟你说话的,”
“当你在键盘上敲敲的时候,我会帮你把你输入的字符显示出来,这样你就知道你输入的对不对了,”
“然后你一行输完,按下回车,我帮你把整行字符串都传给你的程序,你的程序就会对一行字符串进行解析,如果有 scanf 函数的话还会逐个解析出里面的数字、字符等等,”
“当你的程序算完之后,会把输出的信息告诉我,我来显示到屏幕上。”
所谓 I/O,就是 Input/Output,即输入输出。通过终端读入和显示的就是“标准输入输出”,由于终端也是从键盘获取信息,并把信息显示在屏幕上。所以:
- 标准输入也叫键盘输入
- 标准输出也叫屏幕输出
标准输入输出的英文是 Standard Input and Output,缩写就是“stdio”,觉不觉得眼熟hhh~
——“你用的 scanf、gets、getchar 函数都是解析标准输入的,printf、puts、putchar 都是标准输出。现在知道我是干什么的了吧”
——“哦,原来是这样。但是你好丑。”
——“???那我走”
2 输出输出重定向
终端走了——你万念俱灰,把你的代码提交给希冀的评测姬。她说:
得分0.00 最后一次提交时间:2022-03-25 19:29:50
共有测试数据:5
平均占用内存:1.401K 平均CPU时间:0.00578S 平均墙钟时间:0.00576S
测试数据 评判结果
测试数据1 运行错误
测试数据2 运行错误
测试数据3 运行错误
测试数据4 运行错误
测试数据5 运行错误
——“求求你在本地测好再交给我 OK?我每天判那么多代码很累了啦!”
——“emm……我好奇你怎么知道我们的代码对不对的,也是用终端吗?”
——“终端?那不是低级的 PC 才会用的东西?我们服务器不需要这个。I/O 重定向一下就行了”
现在你可以试试这样一个操作,写好一份 C 语言代码,里面有标准输入输出函数,然后添加两行这样的语句:
#include <stdio.h>
// 一些额外的头文件和宏定义
int main() {
freopen("a.in", "r", stdin);
freopen("a.out", "w", stdout); // 额外添加这两句 :)
...
return 0;
}
然后在你的 C 程序的同一文件夹下新建文本文档,命名为 “a.in”(注意这一步之前要确保你的电脑显示了文件后缀[1])。然后在 “a.in” 里面写上你要输入的数据,Ctrl+S 保存。
编译运行你的代码,你会发现程序直接结束,黑框框没有其它输出了。
然后你在代码所在的文件夹里发现了一个名为 “a.out” 的文本文档,里面正是你要的答案。
当然 “a.in” 和 “a.out” 可以改成你喜欢的任何名字,文本文档对后缀不敏感,跟 “.txt” 是一样的。
当然你可以像我一样玩(用编辑器打开输入文件分屏出去,调试的时候不用每次在控制台输入,多是一件美事):

回过头来我们看看这两句是什么意思:
freopen("a.in", "r", stdin);
freopen("a.out", "w", stdout);
/*
* freopen: f 表示 “file (文件)”
* re 表示 “重新”
* open 表示 “打开”
*
* "a.in" / "a.out" 表示重定向的文件名
* "r" / "w" 表示文件的打开模式:"r" 意味着“读”,"w" 意味着写
* stdin / stdout 表示被替换的 I/O 方式
* 分别是标准输入(standard input)和标准输出(standart output)
*/
翻译成人话就是:
- 我要用“只读方式”打开文件 “a.in”,并用其替换标准输入;
- 我要以“只写方式”打开文件 “a.out”,并用其替换标准输出。
- 顺便说一句,只写模式 “w” 下,如果找不到文件,程序会帮你创建一个~
评测姬说:
“现在你懂了?在我拿到你的程序时,会自动帮你加上 freopen 将标准 I/O 重定向为文件 I/O,再在我的 CPU 里跑程序,跑完再对比一下你的输出和标准答案一不一样就行了。”
3 文件 I/O
此时晏老师:“多出点文件 I/O 的题,难死这帮小崽子~”
理论上来说,你会 I/O 重定向之后就可以做所有文件 I/O 的题了,大不了都用 scanf 和 gets 呗。
但是有时候让你既从标准输入读入又从文件读入~文件 I/O 也不能不会是吧。
废话了这么多,终于可以讲讲你们不大清楚的 I/O 函数的用法了:
3.1 文件指针
要熟练使用文件 I/O,要过的第一关就是文件指针,它相当于给你的文件贴一个标签,让后当你需要调用函数的时候要把文件指针作为输入变量传进去,这样才能对你的文件进行操作:
FILE * file_in = fopen("in.txt", "r");
FILE * file_out = fopen("out.txt", "w");
/*
* FILE * 是一个变量类型,代表文件的指针
*
* 后面的 file_in 和 file_out 是你自己起的变量名
*
* fopen("...", "r/w"); 是打开文件的函数,前面的文件名,后面是打开模式读或写
* 表示将一个文件以某种方式打开,返回该文件的指针
*
* 以后你就可以把 file_in 或 file_out 传进其它函数里了
*/
3.2 I/O 函数
3.2.1 输入函数:
scanf("...", ...);
fscanf(file, "...", ...); // file 是前面用 "r" 模式打开的文件指针
在以下两个条件下,这两个函数是我最推荐大家使用的。
- 需要从输入中获取数字(直接 %d 或 %lf)
- 需要逐词对字符串处理(不含空格)
如果题不是要求类似于“读入若干行,行内有空格,对每行输出一个balabala……”这种,真心不建议用 gets 和fgets。因为 gets 很可能会产生莫名其妙的 bug(我曾解释过),fgets 不好记也不好用。
所以比如“单词统计”等等这类题,只要不怕空格,还请选择 scanf/fscanf
printf("...", ...);
fprintf(file, "...", ...);
这俩大家应该挺熟了,后面那个 fprintf 就是把输出目标换成 “w” 模式的文件指针就行了。
介绍两个新朋友:
len = fread(str, sizeof(str[0]), MAX, file);
/*
* 这个函数的作用是从 "r" 模式的 file 文件里把整个文件一股脑读到 str 里
*
* str 是要接受的字符串,尽量开大点,一定要初始化为全 0,这个函数不保证在字符串末尾补 '\0'
* sizeof(str[0]) 实际上就是一个字符的大小,表示读的单位大小
* MAX 读的最大长度,尽量跟 str[] 的容量一样大,要大于所给数据范围
* 如果读到文件末尾还不到 MAX 则返回 str 的长度
* 如果读到 MAX 则返回 MAX
* file 文件指针
*/
fwrite(str, sizeof(str[0]), len, file);
/*
* 这个函数的作用是把 str 一股脑写进 "w" 模式的 file 里
*
* str 是要写的字符串
* sizeof(str[0]) 解释同上
* len 是想写的长度,也就是 str 的长度
* file 想写的文件指针
*/
文件加密一题中,需要读取一整段文本,这种情况下,用这两个函数是最好的选择。
剩下的不太常用我大概说一下。
gets(str); // 读到换行就停止,读进来的字符串不含换行,可能引起神秘 bug
fgets(str, MAX, file); /* 读到换行 / 文件末尾 / 超过 MAX - 1 时停止读入
* 特性:str 中保留读到的换行并自动在末尾添加 '\0' */
上面这俩函数如果想用的话还是建议好好研究一下特性小心一点使用,挺容易出 bug 的。
ch = getchar(); // 从标准输入读入单个字符,毒瘤,别用
// 建议想用的时候用 scanf("%s", str); 读字符串来避免 bug
ch = fgetc(file) // 从文件中读单个字符,注意的一点是:
// 请把 ch 定义成 int 类型,因为它读到文件末尾会返回 EOF
// 而 char 类型不能储存 -1 导致无法识别文件末尾
putchar(ch); // 向标准输出写一个字符,等同于 printf("%c", ch);
fputc(ch, file); // 向文件写一个 ch,等同于 fprintf(file, "%c", ch);
打开“此电脑”,在上面一栏找到“查看”按钮,点进去,找到“文件后缀名”,看是否打勾,如果没有请务必打上。 ︎
一文看懂 C 语言 I/O的更多相关文章
- 一文看懂web服务器、应用服务器、web容器、反向代理服务器区别与联系
我们知道,不同肤色的人外貌差别很大,而双胞胎的辨识很难.有意思的是Web服务器/Web容器/Web应用程序服务器/反向代理有点像四胞胎,在网络上经常一起出现.本文将带读者对这四个相似概念如何区分. 1 ...
- [转帖]一文看懂web服务器、应用服务器、web容器、反向代理服务器区别与联系
一文看懂web服务器.应用服务器.web容器.反向代理服务器区别与联系 https://www.cnblogs.com/vipyoumay/p/7455431.html 我们知道,不同肤色的人外貌差别 ...
- [转帖] 一文看懂:"边缘计算"究竟是什么?为何潜力无限?
一文看懂:"边缘计算"究竟是什么?为何潜力无限? 转载cnbeta 云计算 雾计算 边缘计算... 知名创投调研机构CB Insights撰文详述了边缘计算的发展和应用前景 ...
- 一文看懂大数据的技术生态圈,Hadoop,hive,spark都有了
一文看懂大数据的技术生态圈,Hadoop,hive,spark都有了 转载: 大数据本身是个很宽泛的概念,Hadoop生态圈(或者泛生态圈)基本上都是为了处理超过单机尺度的数据处理而诞生的.你可以把它 ...
- 【转帖】一文看懂docker容器技术架构及其中的各个模块
一文看懂docker容器技术架构及其中的各个模块 原创 波波说运维 2019-09-29 00:01:00 https://www.toutiao.com/a6740234030798602763/ ...
- 一文看懂https如何保证数据传输的安全性的【转载、收藏】
一文看懂https如何保证数据传输的安全性的 一文看懂https如何保证数据传输的安全性的 大家都知道,在客户端与服务器数据传输的过程中,http协议的传输是不安全的,也就是一般情况下http是明 ...
- 一文看懂Stacking!(含Python代码)
一文看懂Stacking!(含Python代码) https://mp.weixin.qq.com/s/faQNTGgBZdZyyZscdhjwUQ
- Nature 为引,一文看懂个体化肿瘤疫苗前世今生
进入2017年,当红辣子鸡PD-1疗法,一路横扫多个适应症.而CAR-T治疗的“小车”在获得FDA专委会推荐后也已经走上高速路,成为免疫治疗又一里程碑事件.PD-1.CAR-T之后,下一个免疫治疗产品 ...
- 转载来自朱小厮博客的 一文看懂Kafka消息格式的演变
转载来自朱小厮博客的 一文看懂Kafka消息格式的演变 ✎摘要 对于一个成熟的消息中间件而言,消息格式不仅关系到功能维度的扩展,还牵涉到性能维度的优化.随着Kafka的迅猛发展,其消息格式也在 ...
随机推荐
- 35、python并发编程之多线程(理论篇)
一 什么是线程 二 线程的创建开销小 三 线程与进程的区别 四 为何要用多线程 五 多线程的应用举例 六 经典的线程模型(了解) 七 POSIX线程(了解) 八 在用户空间实现的线程(了解) 九 在内 ...
- Solution -「SV 2020 Round I」「SRM 551 DIV1」「TC 12141」SweetFruits
\(\mathcal{Description}\) link. 给定 \(n\) 个水果,每个结点可能有甜度 \(v_i\),或不甜(\(v_i=-1\)).现在把这些水果串成一棵无根树.称一 ...
- pytest(10)-常用执行参数说明
pytest单元测试框架中可以使用命令行及代码pytest.main()两种方式执行测试,且可以加入各种参数来组织执行测试.接下来我们来了解常用的执行参数的含义及其用法. pytest中的执行参数根据 ...
- Python 随机(random)模块的不可预测之美
1 . 概念 1.1 真.伪随机数 大部分的计算机语言都会提供 API 生成随机数,此类 API 称为随机数生成器. 计算机可以用随机数模拟现实世界中的各种随机概率问题,没有随机生成器的编程语言不是& ...
- [杂记]LeTeX中使用tikz画图的一些实例
出处:http://www.texample.net/tikz/examples/all/ 上述网站中的实例非常丰富,将代码修改一下再编译就能明白是什么意思,故不再赘述.
- 【windows 操作系统】并发
并发 在操作系统中,是指一个时间段中有几个程序都处于已启动运行到运行完毕之间,且这几个程序都是在同一个处理机上运行.其中两种并发关系分别是同步和互斥 微观角度 所有的并发处理都有排队等候,唤醒,执行等 ...
- 【C# 基础概念】Unicode编码详解
Unicode定义:Unicode(统一码.万国码.单一码)是计算机科学领域里的一项业界标准,包括字符集.编码方案等.Unicode 是为了解决传统的字符编码方案的局限而产生的,它为每种语言中的每个字 ...
- MySQL常用查询命令(连接查询&子查询)
多张表联合起来查询即为连接查询,可分为: 内连接:等值连接.非等值连接.自连接 外连接:右外连接.左外连接 也就是先把多张表通过某种指定条件用join...on...语法连接起来,然后再进行where ...
- mapreduce—shuffle图解
- 解决 Page 'http://localhost:63342/v3/js/math/math.map' requested without authorization页面未授权问题
用webstorm调试页面时,老是弹出对话框说页面未授权,如下图: 解决方法尝试了两种都有效,感觉第一种是正解通用,第二种大家也可以了解一下作为参考 第一种: File--Settings如下图 第二 ...