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

C语言释放指针与关闭文件时触发Segment Fault及Core Dump问题

问题描述

尝试从文件读取数据构建电影链表,在read_file函数末尾释放line指针、关闭文件时出现Segment Fault(段错误)和Core Dump(核心转储),两项操作均引发异常。目前fopen可正常工作,疑惑是否需要额外库。

问题代码
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

struct movie {
    char *title;
    char **languages;
    int year;
    double rating;
    struct movie *next;
};

struct movie *read_file(const char *filename);
struct movie *create_movie(const char *title, const char **languages, int year, double rating);
void append_movie(struct movie *head, struct movie *new_movie);
void free_movie(struct movie *movie);

int main() {
    const char *filename = "movies_sample_1.csv";
    struct movie *head = read_file(filename);

    while (head != NULL) {
        struct movie *temp = head;
        head = head->next;
        free_movie(temp);
    }

    return 0;
}

struct movie *read_file(const char *filename) {
    FILE *file = fopen(filename, "r");
    if (file == NULL) {
        perror("Error opening file");
        exit(1);
    }

    struct movie *head = NULL;
    char *line = NULL;
    size_t len = 0;
    ssize_t nread;

    if ((nread = getline(&line, &len, file)) == -1) {
        perror("Error reading header");
        exit(1);
    }

    while ((nread = getline(&line, &len, file)) != -1) {
        char *title = strtok_r(line, ",", &line);
        char *year_str = strtok_r(NULL, ",", &line);
        char *languages_str = strtok_r(NULL, ",", &line);
        char *rating_str = strtok_r(NULL, ",", &line);


        int year = atoi(year_str);
        double rating = atof(rating_str);

        const char *languages[10];
        int language_count = 0;
        char *language = strtok_r(languages_str, ";[]", &languages_str);

        while (language != NULL) {
            languages[language_count++] = language;
            language = strtok_r(NULL, ";[]", &languages_str);
        }

        languages[language_count] = NULL;

        struct movie *new_movie = create_movie(title, languages, year, rating);

        if (head == NULL) {
            head = new_movie;
        } else {
            append_movie(head, new_movie);
        }
    }

    // if (line != NULL) {
    //     free(line);
    // }

    //fclose(file);
    return head;
}

struct movie *create_movie(const char *title, const char **languages, int year, double rating) {
    struct movie *new_movie = (struct movie *)malloc(sizeof(struct movie));
    if (new_movie == NULL) {
        printf("Memory allocation failed");
        exit(1);
    }

    new_movie->title = strdup(title);
    if (new_movie->title == NULL) {
        printf("Memory allocation failed");
        exit(1);
    }

    new_movie->year = year;
    new_movie->rating = rating;

    int num_languages = 0;
    while (languages[num_languages] != NULL) {
        num_languages++;
    }

    new_movie->languages = (char **)malloc(sizeof(char *) * (num_languages + 1));
    if (new_movie->languages == NULL) {
        printf("Memory allocation failed");
        exit(1);
    }

    for (int i = 0; i < num_languages; i++) {
        new_movie->languages[i] = strdup(languages[i]);
        if (new_movie->languages[i] == NULL) {
            printf("Memory allocation failed");
            exit(1);
        }
    }

    new_movie->languages[num_languages] = NULL;
    new_movie->next = NULL;
    return new_movie;
}

void append_movie(struct movie *head, struct movie *new_movie) {
    struct movie *current = head;
    while (current->next != NULL) {
        current = current->next;
    }
    current->next = new_movie;
}

void free_movie(struct movie *movie) {
    free(movie->title);

    for (int i = 0; movie->languages[i] != NULL; i++) {
        free(movie->languages[i]);
    }

    free(movie->languages);
    free(movie);
}
问题原因与修复方案

核心原因

段错误的根源是**strtok_r修改了line指针的原始指向**:
在循环中执行strtok_r(line, ",", &line)时,第三个参数&line会让strtok_r将line更新为当前分割点之后的内存地址。循环结束后,line已经不再指向getline分配的内存起始位置,此时调用free(line)相当于释放一个非法指针,直接触发段错误。fclose(file)本身无问题,之前的异常是free(line)引发的连锁反应。

修复步骤

  1. 保存getline返回的原始指针:在每次处理行数据时,用临时指针替代原始line指针进行strtok_r操作,避免修改line的起始地址。
  2. 恢复free(line)和fclose(file)的调用。

修改后的read_file函数关键代码:

while ((nread = getline(&line, &len, file)) != -1) {
    // 用临时指针temp_line处理分割,保留原始line指针
    char *temp_line = line;
    char *title = strtok_r(temp_line, ",", &temp_line);
    char *year_str = strtok_r(NULL, ",", &temp_line);
    char *languages_str = strtok_r(NULL, ",", &temp_line);
    char *rating_str = strtok_r(NULL, ",", &temp_line);

    // 后续代码保持不变...
}

// 现在可以安全释放和关闭
if (line != NULL) {
    free(line);
}
fclose(file);
return head;

额外说明

不需要额外库,当前依赖的stdio.h、stdlib.h、string.h已经足够处理文件操作、内存分配和字符串分割。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.09 04:16:42