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

同一文件混合调用fgetc、ungetc与fputc时出错的原因排查

混合使用fputc()与ungetc()引发文件操作错误的原因

问题重现

测试代码

#include <stdio.h>

int main(int argc, char *argv[])
{
    FILE *fp;
    int c;

    fp = fopen("filetest.txt", "r+");

    int fno = fileno(fp);


    /* 读取并打印第一个字符'1' */
    if((c = fgetc(fp)) == EOF){
        printf("fgetc(): error\n");
    }else{
        printf("%c\n", c);
    }

    /* 读取第二个字符'2' */
    if((c = fgetc(fp)) == EOF){
        printf("fgetc(): error\n");
    }

    /* 在第三个位置写入字符'X' */
    if((fputc('X', fp)) == EOF){
        printf("fputc(): error\n");
    }


    /* -- 问题代码段 --- */
    /* 把字符'2'退回输入流 */
    if (ungetc(c, fp) == EOF){
        printf("ungetc(): error\n");
    }

    /* 再次读取并打印'2' */
    if((c = fgetc(fp)) == EOF){
        printf("fgetc(): error\n");
    }else{
        printf("%c\n", c);
    }
    /* -- 问题代码段结束 --- */


    /* 读取第四个字符'4' */
    if((c = fgetc(fp)) == EOF){
        printf("fgetc(): error\n");
    }else{
        printf("%c\n", c);
    }

    if (fclose(fp) != 0){
        printf("fclose(): error\n");
    }

}

测试文件内容

filetest.txt初始内容:

12345

预期输出

1
2
4

实际输出

1
2
fgetc(): error
fclose(): error

对比现象

移除标注为“问题代码段”的部分后,输出恢复正常:

1
4

错误原因

核心问题在于标准IO流的读写切换规则:
当以r+(读写模式)打开文件时,从读操作切换到写操作,或者从写操作切换到读操作,必须满足以下条件之一,否则行为是未定义的:

  • 插入fflush()调用刷新输出缓冲区
  • 调用fseek()、fsetpos()或rewind()调整文件位置指针(哪怕只是定位到当前位置)

你的代码执行流程中:

  1. 先执行两次fgetc(读操作),文件指针停在原字符'3'的位置
  2. 调用fputc写入'X',完成写操作,此时流处于写状态
  3. 直接调用ungetc(属于读操作范畴,用于把字符退回输入流供后续读操作获取),没有做任何流同步/定位操作,违反了读写切换规则,触发未定义行为
  4. 后续的fgetc和fclose都会因为流的状态异常而失败

修复方案

在fputc之后、ungetc之前,插入一个流同步操作,比如调用fseek定位到当前位置(不改变指针位置,仅触发流状态切换):

/* 在fputc之后添加 */
fseek(fp, 0, SEEK_CUR);

或者调用fflush刷新输出缓冲区:

fflush(fp);

这样就能合法地从写操作切换回读操作,ungetc和后续的fgetc都能正常工作。


内容的提问来源于stack exchange,提问作者MrIo

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.28 14:10:31