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

C语言程序可打开文件但无法写入数据,请求代码修复

问题分析与修复方案

你的代码存在几个关键问题,导致新文件无法正确存储数据,以下是具体问题和修复方案:

核心问题

  1. 未检查文件打开状态:如果输入的文件不存在或无法读取,fopen返回NULL,后续fgets直接失败,循环不执行,自然没有内容写入新文件。
  2. 未关闭源文件指针:file指针一直未关闭,可能导致资源泄漏,部分系统下也会影响文件缓存正常刷新。
  3. 字段分割越界风险:strtok分割字段时未限制field_index不超过FIELD_COUNT-1,如果一行字段数超过7,会导致fields数组越界,破坏内存。
  4. 换行符未处理:fgets读取的行包含末尾的\n,会被带入最后一个字段(MLA_pages),处理时未去除,可能导致输出格式异常。
  5. 空字段访问风险:如果某个字段为空(比如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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.06 04:20:31