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

在线编译器可运行但VS报错:fprintf触发访问违规问题排查

C语言fprintf触发0xC0000005访问违规错误(Visual Studio环境)

问题描述

这是一份生成学生资格评定表并写入文件的C语言作业代码,已遵循学校方法指南,参考过相关错误案例但未解决问题。代码在在线编译器中可正常运行,但在Visual Studio中,第一个fprintf语句触发0xC0000005访问违规错误(写入地址0x0000000000000039时出错)。文件与程序处于同一目录,已尝试修改文件路径、fprintf内容等操作,仍无法解决问题。

代码示例

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


struct qinf { //structure of students
    char name[15];
    int year;
    int rate;
    float qual;
} qarr[10];

int main(void) {
    int n; 
    int i, j, m;
    float funk;
    struct qinf x;
    SetConsoleCP(1251);
    SetConsoleOutputCP(1251);

    for (n = 0; n < 10; n++) {
        printf("%d: Enter second name, year of birth, rate and qualification rate for work >> ", n + 1);
        scanf("%s", qarr[n].name);
        if (!strcmp(qarr[n].name, "***")) break;
        scanf_s("%d", &qarr[n].year);
        scanf_s("%d", &qarr[n].rate);
        scanf_s("%f", &funk); qarr[n].qual = funk;
    }
    
    FILE *fin;
    if (fin = fopen("test.txt", "w") != NULL) {

        fprintf(fin, "\n|-------------------------------------------------------------------------------------------|\n");
        fprintf(fin, "|                            Ведомость о присвоении квалификации                            |\n");
        fprintf(fin, "|-------------------------------------------------------------------------------------------|\n");
        fprintf(fin, "|       Фамилия      | Год рождения | Оценка рез-тов экзамена | Присвоен ур-нь квалификации |\n");
        fprintf(fin, "|-------------------------------------------------------------------------------------------|\n");

        for (i = 0; i < n; i++) {
            fprintf(fin, "| %18s | %12d | %23d | %27.2f |\n", qarr[i].name, qarr[i].year, qarr[i].rate, qarr[i].qual);
        }

        fprintf(fin, "|-------------------------------------------------------------------------------------------|\n");


        for (i = 0; i < n - 1; i++) {
            m = i;
            for (j = i + 1; j < n; j++) {
                if (strcmp(qarr[m].name, qarr[j].name) > 0) m = j;
                if (m > i) {
                    strcpy(x.name, qarr[i].name); x.year = qarr[i].year;
                    x.rate = qarr[i].rate; x.qual = qarr[i].qual;
                    strcpy(qarr[i].name, qarr[m].name); qarr[i].year = qarr[m].year;
                    qarr[i].rate = qarr[m].rate; qarr[i].qual = qarr[m].qual;
                    strcpy(qarr[m].name, x.name); qarr[m].year = x.year;
                    qarr[m].rate = x.rate; qarr[m].qual = x.qual;
                }

            }
        }

        fprintf(fin, "\n|-------------------------------------------------------------------------------------------|\n");
        fprintf(fin, "|                            Ведомость о присвоении квалификации                            |\n");
        fprintf(fin, "|-------------------------------------------------------------------------------------------|\n");
        fprintf(fin, "|       Фамилия      | Год рождения | Оценка рез-тов экзамена | Присвоен ур-нь квалификации |\n");
        fprintf(fin, "|-------------------------------------------------------------------------------------------|\n");

        for (i = 0; i < n; i++) {
            fprintf(fin, "| %18s | %12d | %23d | %27.2f |\n", qarr[i].name, qarr[i].year, qarr[i].rate, qarr[i].qual);
        }

        fprintf(fin, "|-------------------------------------------------------------------------------------------|\n");
        fclose(fin);
    }
    else printf("\n\nОшибка открытия файла");

    return 0;
}

错误信息(翻译后)

在0x00007FFDD833FAAD (ntdll.dll) 处发生未经处理的异常: 0xC0000005: 写入位置0x0000000000000039时发生访问违规。

解决方案

1. 修复文件指针赋值的运算符优先级错误

这是导致访问违规的核心原因:
原代码中if (fin = fopen("test.txt", "w") != NULL) 由于运算符优先级,会先执行fopen(...) != NULL,得到布尔值(成功时为1,失败时为0),再将该值赋值给fin。此时fin不是有效的文件指针,而是整数1(对应内存地址0x39,即错误信息中的写入地址),调用fprintf时自然触发访问违规。

修正代码:给赋值表达式添加括号,确保先完成指针赋值再判断是否为空:

FILE *fin;
if ((fin = fopen("test.txt", "w")) != NULL) {
    // 后续写入逻辑
}

2. 统一输入函数(可选)

代码混合使用了scanf和scanf_s,建议统一使用scanf_s以符合Visual Studio的安全要求,避免潜在的输入缓冲区溢出问题:
将scanf("%s", qarr[n].name); 修改为:

scanf_s("%s", qarr[n].name, (unsigned)_countof(qarr[n].name));

3. 修正排序逻辑错误

原排序代码中,交换操作放在内层循环的if (m > i)判断里,会导致每次找到更小的字符串就立即交换,这不符合选择排序的逻辑(应该在内层循环结束后找到最小值的索引,再执行一次交换)。修正后的排序代码:

for (i = 0; i < n - 1; i++) {
    m = i;
    for (j = i + 1; j < n; j++) {
        if (strcmp(qarr[m].name, qarr[j].name) > 0) {
            m = j;
        }
    }
    // 内层循环结束后再执行交换
    if (m != i) {
        strcpy(x.name, qarr[i].name); x.year = qarr[i].year;
        x.rate = qarr[i].rate; x.qual = qarr[i].qual;
        strcpy(qarr[i].name, qarr[m].name); qarr[i].year = qarr[m].year;
        qarr[i].rate = qarr[m].rate; qarr[i].qual = qarr[m].qual;
        strcpy(qarr[m].name, x.name); qarr[m].year = x.year;
        qarr[m].rate = x.rate; qarr[m].qual = x.qual;
    }
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.03 06:41:03