You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.10 17:01:06