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

C语言操作txt文件跳行读取触发0xC0000005错误解决方法

问题现象

程序首次运行时可正常进入新账号注册流程、写入用户数据,二次运行已存有用户数据的test.txt时,直接触发错误码-1073741819 (0xC0000005)崩溃,无法输出预期的用户欢迎内容。

原问题代码:

int main() {
    FILE *fp;
    fp = fopen("test.txt", "a+");
    char test = 'T', check3rd, optreg = 'T';
    int x;
    char namalengkap[50], gender[50];
    int umur, tb, bb;
    fprintf(fp, "Username : testa\nPassword : 12345\n");
    rewind(fp);
    fscanf(fp, "%*[^\n]\n%*[^\n]\n");
    fscanf(fp, "%c", check3rd);
    if (check3rd == '\0') {
        printf("Akun baru terdeteksi,Silahkan isi data anda terlebih dahulu\n");
        while (optreg !='Y' && optreg !='y') {
            fflush(stdin);
            printf("Nama Lengkap  : ");
            fgets(namalengkap, 50, stdin);
            strtok(namalengkap, "\n");
            printf("Jenis Kelamin : ");
            fgets(gender, 50, stdin);
            strtok(gender, "\n");
            printf("Umur          : ");
            scanf("%d", &umur);
            fflush(stdin);
            printf("Tinggi Badan  : ");
            scanf("%d", &tb);
            fflush(stdin);
            printf("Berat Badan   : ");
            scanf("%d", &bb);
            fflush(stdin);
            printf("Apa anda sudah yakin dengan data ini?\n");
        chkch:
            printf("(Y/T)");
            scanf(" %c", &optreg);
            if (optreg != 'Y' && optreg !='y' && optreg != 'T' && optreg != 't') {
                puts("input salah\n");
                goto chkch;
            }
            rewind(fp);
            fprintf(fp, "\nNama : %s\nJenis Kelamin: %s\nUmur : %d\nTinggi Badan : %d\nBerat Badan : %d",
                    namalengkap, gender, umur, tb, bb);
        }
    } else {
        printf("Selamat datang %s!\n", namalengkap);
    }
    return 0;
}
根因分析

代码存在多处可直接触发崩溃和逻辑错误的问题:

  • 直接导致内存访问崩溃的核心错误:fscanf(fp, "%c", check3rd); 未传入check3rd的内存地址。%c格式符要求参数为char*类型,代码直接传入char类型变量值,fscanf会把读取到的字符值当作内存地址执行写入操作,触发非法内存访问,对应0xC0000005访问违例错误。
  • 空行判断逻辑完全错误:跳过前两行后,若第三行为空,文件指针实际已经到达文件末尾,fscanf读取会直接失败;即使第三行是空行,首字符也是换行符\n而非字符串结束符\0,原判断条件永远无法匹配预期场景。
  • 未初始化内存访问:走到非新账号的else分支时,namalengkap是栈上未初始化的字符数组,存储的是随机垃圾值,代码从未从文件中读取已存储的用户姓名,直接用%s打印该数组会访问随机内存,同样会触发崩溃。
  • 重复写入逻辑bug:每次打开文件都无脑执行fprintf(fp, "Username : testa\nPassword : 12345\n");,程序每运行一次就会在文件末尾追加一组账号密码,多次运行后文件内容会完全混乱。
  • 依赖未定义行为:fflush(stdin)不属于C标准规定的合法用法,标准仅支持对输出流执行fflush操作,输入流fflush的效果随编译器变化,会导致输入逻辑不可控。
修复方案

按以下规则修正代码即可解决问题:

  1. 所有格式化输入函数读取普通变量时,必须传入变量地址(数组名自动退化为指针,不需要额外取地址)。
  2. 打开文件后先判断文件是否为空,仅首次创建文件时写入初始账号密码行,避免重复写入。
  3. 修正空行判断逻辑:跳过前两行后检查fscanf返回值,若读取失败(到达EOF)或读到的首字符为\n,判定为新账号需要注册。
  4. 移除所有fflush(stdin),输入后残留的换行符用逐字符读取的方式清空缓冲区,不依赖未定义行为。
  5. 非新账号场景下,先从文件中解析出已存储的用户姓名字段,再执行欢迎语打印,禁止访问未初始化的内存。

修正后的可运行代码:

#include <stdio.h>
#include <string.h>

// 清空输入缓冲区残留字符,替代未定义的fflush(stdin)
void clear_stdin() {
    int c;
    while ((c = getchar()) != '\n' && c != EOF);
}

int main() {
    FILE *fp;
    fp = fopen("test.txt", "a+");
    if (fp == NULL) {
        perror("Gagal membuka file");
        return 1;
    }

    char check3rd, optreg = 'T';
    char namalengkap[50], gender[50];
    int umur, tb, bb;

    // 判断文件是否为空,仅空文件首次写入初始账号密码
    fseek(fp, 0, SEEK_END);
    long fsize = ftell(fp);
    if (fsize == 0) {
        fprintf(fp, "Username : testa\nPassword : 12345\n");
    }
    rewind(fp);

    // 跳过文件前两行
    fscanf(fp, "%*[^\n]\n%*[^\n]\n");
    // 传入check3rd地址,修正fscanf参数错误
    int ret = fscanf(fp, "%c", &check3rd);

    // 新账号判断:读失败到EOF/读到换行符,说明第三行为空
    if (ret == EOF || check3rd == '\n') {
        printf("Akun baru terdeteksi,Silahkan isi data anda terlebih dahulu\n");
        while (optreg !='Y' && optreg !='y') {
            printf("Nama Lengkap  : ");
            fgets(namalengkap, 50, stdin);
            strtok(namalengkap, "\n");
            printf("Jenis Kelamin : ");
            fgets(gender, 50, stdin);
            strtok(gender, "\n");
            printf("Umur          : ");
            scanf("%d", &umur);
            clear_stdin();
            printf("Tinggi Badan  : ");
            scanf("%d", &tb);
            clear_stdin();
            printf("Berat Badan   : ");
            scanf("%d", &bb);
            clear_stdin();
            printf("Apa anda sudah yakin dengan data ini?\n");
        chkch:
            printf("(Y/T)");
            scanf(" %c", &optreg);
            clear_stdin();
            if (optreg != 'Y' && optreg !='y' && optreg != 'T' && optreg != 't') {
                puts("input salah\n");
                goto chkch;
            }
            // a+模式下写操作自动追加到文件末尾,无需rewind
            fprintf(fp, "\nNama : %s\nJenis Kelamin: %s\nUmur : %d\nTinggi Badan : %d\nBerat Badan : %d",
                    namalengkap, gender, umur, tb, bb);
            fflush(fp); // 确保写入内容落盘
        }
    } else {
        // 回退之前读取的1个字符,解析文件中存储的姓名
        fseek(fp, -1, SEEK_CUR);
        fscanf(fp, "%*[^:]: %49[^\n]", namalengkap);
        printf("Selamat datang %s!\n", namalengkap);
    }

    fclose(fp);
    return 0;
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.30 21:12:19