C语言程序可打开文件但无法写入数据,请求代码修复
问题分析与修复方案
你的代码存在几个关键问题,导致新文件无法正确存储数据,以下是具体问题和修复方案:
核心问题
- 未检查文件打开状态:如果输入的文件不存在或无法读取,
fopen返回NULL,后续fgets直接失败,循环不执行,自然没有内容写入新文件。 - 未关闭源文件指针:
file指针一直未关闭,可能导致资源泄漏,部分系统下也会影响文件缓存正常刷新。 - 字段分割越界风险:
strtok分割字段时未限制field_index不超过FIELD_COUNT-1,如果一行字段数超过7,会导致fields数组越界,破坏内存。 - 换行符未处理:
fgets读取的行包含末尾的\n,会被带入最后一个字段(MLA_pages),处理时未去除,可能导致输出格式异常。 - 空字段访问风险:如果某个字段为空(比如
MLA_names是空字符串),MLA_names[0]会访问数组越界,引发未定义行为。
修复后的代码
#include <stdio.h> #include <string.h> #define FILENAME_SIZE 1024 #define BUFFER_SIZE 256 #define FIELD_COUNT 7 // 去除字符串首尾空格、换行符、回车符 void trim(char *str) { if (!str || *str == '\0') return; // 去除开头空白字符 char *start = str; while (*start == ' ') start++; memmove(str, start, strlen(start) + 1); // 去除结尾空白字符 char *end = str + strlen(str) - 1; while (end >= str && (*end == ' ' || *end == '\n' || *end == '\r')) { *end = '\0'; end--; } } int main() { FILE *file = NULL; FILE *newfile = NULL; char filename[FILENAME_SIZE]; printf("File: "); scanf("%s", filename); // 检查源文件是否打开成功 file = fopen(filename, "r"); if (!file) { printf("无法打开源文件\n"); return 1; } // 检查新文件是否创建成功 newfile = fopen("updatedReferences.txt", "w"); if (!newfile) { printf("无法创建新文件\n"); fclose(file); return 1; } char line[BUFFER_SIZE]; while (fgets(line, BUFFER_SIZE, file)) { char *fields[FIELD_COUNT] = {NULL}; char *token = strtok(line, ","); int field_index = 0; // 限制字段数量,避免数组越界 while (token && field_index < FIELD_COUNT) { fields[field_index++] = token; token = strtok(NULL, ","); } // 为字段设置默认空字符串,避免访问空指针 char *MLA_surname = (field_index > 0) ? fields[0] : ""; char *MLA_names = (field_index > 1) ? fields[1] : ""; char *MLA_title = (field_index > 2) ? fields[2] : ""; char *MLA_journal = (field_index > 3) ? fields[3] : ""; char *MLA_issue_number = (field_index > 4) ? fields[4] : ""; char *MLA_year = (field_index > 5) ? fields[5] : ""; char *MLA_pages = (field_index > 6) ? fields[6] : ""; // 处理所有字段的首尾空白 trim(MLA_surname); trim(MLA_names); trim(MLA_title); trim(MLA_journal); trim(MLA_issue_number); trim(MLA_year); trim(MLA_pages); char reference[BUFFER_SIZE] = {0}; int current_len = 0; // 安全拼接字符串,避免缓冲区溢出 current_len += snprintf(reference + current_len, BUFFER_SIZE - current_len, "%s", MLA_surname); if (current_len >= BUFFER_SIZE) break; if (*MLA_names != '\0') { current_len += snprintf(reference + current_len, BUFFER_SIZE - current_len, ", %c.", MLA_names[0]); if (current_len >= BUFFER_SIZE) break; } if (*MLA_year != '\0') { current_len += snprintf(reference + current_len, BUFFER_SIZE - current_len, " (%s)", MLA_year); if (current_len >= BUFFER_SIZE) break; } if (*MLA_title != '\0') { current_len += snprintf(reference + current_len, BUFFER_SIZE - current_len, ". %s", MLA_title); if (current_len >= BUFFER_SIZE) break; } if (*MLA_journal != '\0') { current_len += snprintf(reference + current_len, BUFFER_SIZE - current_len, ". %s", MLA_journal); if (current_len >= BUFFER_SIZE) break; } if (*MLA_issue_number != '\0') { current_len += snprintf(reference + current_len, BUFFER_SIZE - current_len, " %s", MLA_issue_number); if (current_len >= BUFFER_SIZE) break; } if (*MLA_pages != '\0') { current_len += snprintf(reference + current_len, BUFFER_SIZE - current_len, ", %s.", MLA_pages); if (current_len >= BUFFER_SIZE) break; } fprintf(newfile, "%s\n", reference); } // 关闭所有文件指针,确保缓存写入磁盘 if (newfile) fclose(newfile); if (file) fclose(file); return 0; }
关键修复说明
- 文件打开校验:无论源文件还是新文件,打开后立即检查状态,失败则提示并退出,避免后续无效操作。
- 封装trim函数:将重复的首尾空白处理逻辑封装,同时兼容换行符、回车符,代码更简洁易维护。
- 字段越界防护:限制
field_index不超过数组长度,为空字段设置默认值,避免空指针访问。 - 安全字符串拼接:用
snprintf逐步拼接,每次检查剩余缓冲区大小,彻底避免溢出风险。 - 关闭所有文件:确保所有打开的文件都被关闭,强制刷新缓存到磁盘,保证数据写入成功。
内容的提问来源于stack exchange,提问作者user19344428
相关产品推荐
相关产品推荐

