K&R里面第七章的一个cat程序中遇到的fclose()问题-问答-阿里云开发者社区-阿里云

开发者社区> 问答> 正文

K&R里面第七章的一个cat程序中遇到的fclose()问题

2016-06-13 15:44:54 2114 1

此程序是一个简单版本的cat程序,也就是主要把将几个文件的内容粘到一起输出到stdout中,若在执行程序的 时候没有指定任何文件名,则默认由stdin读取输入。源程序如下:

#include <stdio.h>
 
int main(int argc, char *argv[]) {
    FILE *fp;
    void filecopy(FILE *, FILE *);
     
    if (argc == 1) 
        filecopy(stdin, stdout);
    else
        while (--argc > 0) 
            if ((fp = fopen(*++argv, "r")) == NULL) {
                printf("cat: can't open file %s\n", *argv);
                return 1;
            } else {
                filecopy(fp, stdout);
                fclose(fp);
            }
    return 0;
}
 
 
/* copy the content from input file(stream) to the output file        */
void filecopy(FILE *ifp, FILE *ofp) {
    int c;
 
    while ((c = getc(ifp)) != EOF)
        putc(c, ofp);
}

我的试验文件是两个分别名为mes1和mes2的文件。mes1的内容为“hello”,而mes2的内容为“marry!”,并且两个文件的末端都是没有换行符的,也就是说他们都仅仅只是一行末尾不带换行符的字符串而已。当我在shell执行这个程序时,出现下面的输出:

[garvylo@utopia test]$ ./a.out mes1 mes2
hello
marry!
[garvylo@utopia test]$

也就是说,在mes1和mes2的信息被输出到stdout时都在其尾部被加上了一个换行符,这是为什么呢?

之后,我在源文件中,“ return 0;” 前面加上了" while(1); "语句,目的是想看看程序在没有退出main()之前有没有将stdout的buffer中的内容输出至stdout连接的终端(显示器)。本来,理论上,应该在加了这句“ while(1); ”之后,程序是不会把buffer中积累的数据输送到stdout终端的,因为据我所知,stdout是行缓存的(在本机试验过也确实如此),在其没有写满buffer或遇到换行符之前是不会写到stdout终端的,只有在正常结束main()函数,再由exit()函数调用fclose(),由其调用fflush()函数才会把缓存区的东西输送到stdout终端。所以,这里感觉挺疑惑的。是不是那个" fclose(fp); "的作用呢?

另外,那个“ fclose(fp); ”是不是只是解除外部文件与文件指针fp的连接,释放文件指针和此文件的缓存区呢?它对于stdout应该没有影响吧?因为,我觉得在filecopy()函数中,只是由input file 的buffer读取数据,然后存到一个中间变量c,再把c中的内容存放到stdout终端的buffer中,input file 的buffer 好像与stdout终端的buffer没有什么直接的联系。不知道是否如此?

还有最后一个问题,我在网上搜寻过了却也没有得到答案。就是那个fopen()函数, 当以“ r ”读模式打开某个文件(假设这个文件位于disk上,并且是全缓冲的)时,是不是在为这个文件开辟了缓存区后,立即由文件读取内容填满这个buffer(若文件长度小于buffer长度,则读取完文件的全部内容即可),然后对该文件的读操作其实就是对该buffer的操作。当buffer的内容读完时,再通过系统调用读取该文件的剩余内容填于buffer中,当文件指针被释放后(fclose(fp)),其缓存也会被释放。而对于”调用fflush()函数刷新缓存使buffer中的内容输送到相应的被带开为“写(r)“的文件“这一说,在以” r “打开的文件中是不存在的?一个文件可以同时被打开为”读“和”写“模式吗?如果可以,那么它们申请的应该是两个不同的缓存空间吗?

晚辈还没有学习过操作系统的知识,所以问题问得可能有点浅显,但网上搜寻不出答案,而自己也百思不解,故老烦各位前辈指教一二。

取消 提交回答
全部回答(1)
  • a123456678
    2019-07-17 19:36:13

    老实说,你@我之前,我就看过你这个问题,但是我觉得挺棘手的,因为我自己觉得我也搞不定,所以没敢开腔,但是,被你@了,不站出来似乎有点乌龟了……

    1 “在mes1和mes2的信息被输出到stdout时都在其尾部被加上了一个换行符”,这个确实是不应该的,我在Windows下用vs2010试验过,并没有这样。至于linux为什么这样,我也不知道。

    2 “stdout是行缓存的(在本机试验过也确实如此)”,那你是如何证明这一点的呢?h或许你真的证明了,那我只能说linux的行为对我来说有点费解。

    你觉得fclose()另外一个文件,会强迫stdout输出吗?可是为了实际证明这一点,你把fclose()注释掉,试一下。或许我说的是错的。

    3 “input file 的buffer 好像与stdout终端的buffer没有什么直接的联系”,肯定是这样的,要联系也是程序让他们有联系,否则不乱套了?

    4 文件以"r"模式打开,而且文件是全缓冲,我的理解是缓冲区中的内容不是自动就填充的,而是你使用fread()或其他读的函数,系统会将读取的内容自动放到这个缓冲区,并返回你的读取函数。如果下次读的数据还是这个缓冲去范围内的数据,就直接从这个缓冲去复制,不直接读文件了。但是如果不在范围,还是要实际读取文件的,从而再次更新缓冲区。

    5 根据我知道的资料,fflush()是把缓冲区中的数据刷新到磁盘(真正的写入)。对于以读模式打开的文件,应该不需要同步,因为根本没有也不能修改文件;

    6 文件可以被同时打开为读和写。很多时候都是一个线程写文件,而另一个线程从这个文件读取,这算是线程通讯的一种办法。只要文件指针(读写位置)保持正确就可以了。实际上,在windows下面文件要想这样,必须打开时共享读写,不能独占式访问。但是简单的c库函数做不到这一点,能不能,听天由命了(要看读写这个文件的其他进程是否设置共享)。

    7 “如果可以,那么它们申请的应该是两个不同的缓存空间吗?",我要说的是一个FILE *指针对应一个缓冲区,如果只用一个,那不乱套,你写乱我的,我搞乱你的。多从常识,原理角度考虑问题,常识,原理应该这样,那么程序也应该这样。否则,程序也会出现问题的。

    0 0
相关问答

70

回答

Discuz实现oss云存储

山不周 2015-04-21 11:20:02 66793浏览量 回答数 70

12

回答

在阿里云上安装和运行Node.js全功略

ycwong 2013-09-18 15:17:30 66324浏览量 回答数 12

48

回答

云计算自助服务开篇

阿里云支持与服务 2012-12-18 12:00:13 76615浏览量 回答数 48

30

回答

云计算之路:为什么要选择云计算

cnblogs 2013-03-27 10:22:27 144551浏览量 回答数 30

28

回答

钉钉开放平台“常见问题常见问题常见问题“重要请关注

竹梅 2015-12-03 00:39:14 96124浏览量 回答数 28

295

回答

Linux Bash严重漏洞修复紧急通知(已全部给出最终修复方案)

qilu 2014-09-25 13:26:50 437865浏览量 回答数 295

17

回答

阿里云服务器安装宝塔面板图文教程

张扯淡 2018-12-14 13:34:43 69381浏览量 回答数 17

13

回答

【云服务器分享】如何节省网站流量

dreamdoo 2012-10-15 10:36:09 81567浏览量 回答数 13

97

回答

Redhat/CentOS一键安装web环境全攻略

xiaofanqie 2011-08-11 14:51:38 124828浏览量 回答数 97

78

回答

【2013.9.5修正版图文】新手如何使用阿里云(linux)服务器建站(搬站)

姑苏公子 2013-04-11 00:39:13 108762浏览量 回答数 78
+关注
0
文章
14879
问答
问答排行榜
最热
最新
相关电子书
更多
JS零基础入门教程(上册)
立即下载
性能优化方法论
立即下载
手把手学习日志服务SLS,云启实验室实战指南
立即下载