C语言rb+模式下读操作后无法写入的原因探究
问题:二进制读写模式下fputs写入失败的原因分析
我以rb+模式打开文件,通过两次fputs写入两个字符串;用fseek将文件指针移至文件开头3字节处,调用fgets读取4个字符后,尝试用fputs写入第三个字符串却失败。但取消注释被注释的fputs("hello", fp)代码后就能正常写入,请问这是什么原因?
代码示例
#include <stdio.h> int main(int argc, char *argv[]) { FILE *fp; if( argc != 2) { printf("NOT ENOUGH ARGUMENTS"); return 1; } fp = fopen(argv[1], "rb+"); if(fp == NULL) { fp = fopen(argv[1], "wb+"); if( fp == NULL ) { printf("\nUNABLE TO CREATE FILE"); return 2; } else { printf("\nFILE CREATED SUCCESSFULLY"); } } else { printf("\nFILE OPENED SUCCESSFULLY"); } char str[100]; fseek(fp, 0, SEEK_END); fputs("123456789", fp); fputs("ABCDEFGH", fp); fseek(fp, 3, SEEK_SET); //fputs("hello", fp); fgets(str, 4, fp); printf("\n%s\n",str); fputs("why", fp); fseek(fp, 0, SEEK_END); printf("\nTHE SIZE OF FILE IS : %ld", ftell(fp)); fclose(fp); return 0; }
原因分析
核心规则:更新流的读写切换要求
C标准对更新流(即可读可写的流,如rb+/wb+模式打开的文件)的操作有明确约束:
- 从读操作切换到写操作时,必须先调用一个定位函数(
fseek、fsetpos、rewind),或者调用fflush刷新输出缓冲区,否则行为未定义。 - 从写操作切换到读操作时,如果未到达文件末尾,必须先调用一个定位函数。
原代码失败的直接原因
你的代码流程中,fgets(读操作)执行完成后,直接调用fputs(写操作),没有执行任何定位或刷新操作,违反了「读转写必须先切换状态」的规则,导致写入行为未定义(表现为写入失败)。
取消注释后成功的本质
取消注释fputs("hello", fp)后,流程变为:fseek定位 → fputs("hello")(写)→ fgets(读)→ fputs("why")(写)。
这里的fgets属于「写转读」操作,理论上也需要定位函数切换,但在部分系统的流实现中,fgets会直接从当前文件指针位置读取,且读取完成后,流的缓冲区状态被间接重置,使得后续的写操作能够执行。但这属于依赖具体实现的行为,并非标准规定的合规操作。
合规的解决方法
不需要依赖额外的fputs,只需在fgets之后、fputs之前添加一个合法的状态切换操作即可:
fgets(str, 4, fp); printf("\n%s\n",str); // 方法1:执行空定位操作,满足读转写的规则 fseek(fp, ftell(fp), SEEK_SET); // 方法2:刷新输出缓冲区 // fflush(fp); fputs("why", fp);
内容的提问来源于stack exchange,提问作者vijai shankar
相关产品推荐
相关产品推荐

