以读写方式打开文件,读写的缓冲区是否相同

今天刷C Primer Plus 上的题目,一些矛盾情况让我对书本产生了深深的怀疑

首先是这样的

img

书本说了在读写模式下会创建两个缓冲区,那么我的理解是读一个缓冲,写一个缓冲,那么问题来了,上题目

img

我打算以r+方式打开文件,然后边读边写,读一个小写字符,然后用fseek定位到当前fp指针的前一位写入大写字符,以是否读到EOF做测试条件循环(这个非常重要,和后来的问题有关)因为我用的是VS2022所以使用了fopen_s,printf_s,参数大致一样

代码如下

#include

#include

#include

#define LEN 100

int main()

{

FILE* fp = NULL;

char file[LEN];//用来存放文件名

file[LEN - 1] = '\0';

char ch;

long now=0L;//文件指针指示器

printf_s("Please enter the file name:\n");

scanf_s("%s", file, (unsigned)_countof(file));//从键盘读入文件名

if (fopen_s(&fp, file, "rb+") != 0)

{

fprintf_s(stderr, "Can't open %s file.", file);

exit(EXIT_FAILURE);

}//打开文件失败失败时退出

while ((ch=getc(fp))!=EOF)//以读到文件结尾为条件,每次从文件读入一个字符

{

if ((now = ftell(fp)) > 0)

//为了防止指针越界,设置now来显示当前位置距离与文件头的字节数

fseek(fp, -1L, SEEK_CUR);

//每读一个字符,fp会指向下一位,所以用fseek使文件指针返回当前位置的前一位

putc(toupper(ch), fp);//在文件指针fp当前的位置输出大写字符

}

if (fp != 0)

fclose(fp);

return 0;

}

按照我的想法,应该是读到文件末尾,然后运行完毕,然而

这是我用来做试验的文本(这是我第一时间想到的最短单词)

img

它进入了一个死循环,这是我在下断点后,运行了几次后的文本

img

可以看见它已经远远超出我原来fuck!的字符数了,文件的结尾标志被删除了,为什么会这样?

我在多次调试之后,使用了fflush来刷新输出缓冲区

增加代码

img

没有了死循环,结果正常

img

我突然想到,读写缓冲区应该是一致的,fflush的功能是把输出缓冲区刷新,从我运行的错误结果来看,显然读到字符u时,字符留在了缓冲区,刚刚说了,这是个死循环,EOF丢失了,如果说读写缓冲区相同,那在写入u后,下一次迭代读字符时,就把缓冲区中之前的u读入了,之后的字符总是u,因为不是直接从磁盘文件中读取字符,而是缓冲区,所以,文件结尾就被舍弃了,一直都是无限u循环

如果我想的没有错的话,那么显然我贴的第一章书本的图就是错的了,难受的是书本的标准答案竟然还运行不了,希望有人告诉读写的机制,是不是读写在同一个缓冲区

首先你既然要putc,那么你打开文件的时候要加w参数,getc每次读到一个字符fp会自动往后移一位,所以你fseek这里用法就是错的,所以你会一直读到U,把fseek那个逻辑去掉,加不加fflush都可以,缓冲区指的是内存中的一块区域fflush作用是把内存里面东西写入到磁盘中去

读写是两个缓冲区,意思就是在你fclose之前读出来的东西和将要写进去的东西都放在内存的两个区域。这样就不会频繁的写磁盘。fclose的时候会把写缓冲区的内容写入磁盘,就好像你开了个word编辑文件一样,缓冲区就像你只编辑了没保存的那个状态,你保存的时候相当于fflush的功能了,或者你关闭word的时候提示你保存,最后一起写到磁盘,道理一样