在线编译器可运行但VS报错:fprintf触发访问违规问题排查
问题描述
这是一份生成学生资格评定表并写入文件的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

