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)引发的连锁反应。
修复步骤
- 保存
getline返回的原始指针:在每次处理行数据时,用临时指针替代原始line指针进行strtok_r操作,避免修改line的起始地址。 - 恢复
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
相关产品推荐
相关产品推荐

