C语言中逐行读取文件并将每行单词插入二维链表的问题
动态读取文件行并构建二维链表的解决方案
核心思路
通过动态分配内存读取整行内容,再在内存中拆分每行的单词,既保留行边界,又无需提前限制行长度,完美适配未知行/单词数量的场景。
步骤实现
1. 实现动态行读取函数
手动实现一个可自动扩容的行读取函数,替代固定长度的fgets:
#include <stdio.h> #include <stdlib.h> #include <string.h> char* dynamic_getline(FILE* file) { size_t buf_size = 128; // 初始缓冲区大小,可按需调整 char* buf = malloc(buf_size); if (!buf) return NULL; size_t pos = 0; int c; // 逐字符读取直到换行或文件结束 while ((c = fgetc(file)) != EOF && c != '\n') { // 缓冲区不足时扩容 if (pos >= buf_size - 1) { buf_size *= 2; char* new_buf = realloc(buf, buf_size); if (!new_buf) { free(buf); return NULL; } buf = new_buf; } buf[pos++] = c; } buf[pos] = '\0'; // 处理EOF且无内容的情况 if (c == EOF && pos == 0) { free(buf); return NULL; } return buf; }
2. 拆分每行单词并插入链表
拿到动态读取的行字符串后,用strtok拆分单词(或手动遍历拆分),再插入到当前行的链表中:
// 辅助函数:向当前行链表插入单词 void insert_word(struct Node** line_head, const char* word) { struct Node* new_node = malloc(sizeof(struct Node)); if (!new_node) return; strncpy(new_node->word, word, sizeof(new_node->word) - 1); new_node->word[sizeof(new_node->word) - 1] = '\0'; // 确保字符串终止 new_node->words = NULL; new_node->next = NULL; if (*line_head == NULL) { *line_head = new_node; } else { struct Node* temp = *line_head; while (temp->words != NULL) { temp = temp->words; } temp->words = new_node; } } // 主处理逻辑 void parse_file(FILE* file, struct Node** list_head) { struct Node* current_line = NULL; char* line; while ((line = dynamic_getline(file)) != NULL) { // 创建新行的头节点 struct Node* new_line = malloc(sizeof(struct Node)); if (!new_line) { free(line); break; } new_line->words = NULL; new_line->next = NULL; // 拆分当前行的单词 char* token = strtok(line, " \t"); // 按空格、制表符拆分,可添加其他分隔符 while (token != NULL) { insert_word(&new_line, token); token = strtok(NULL, " \t"); } // 将新行加入二维链表 if (*list_head == NULL) { *list_head = new_line; } else { struct Node* temp = *list_head; while (temp->next != NULL) { temp = temp->next; } temp->next = new_line; } free(line); // 释放行内存 } }
关键说明
- 放弃
fscanf:它会跳过所有空白字符(包括换行),无法区分行边界,不符合按行处理的需求。 - 替代
fgets:固定缓冲区容易导致超长行被截断,手动实现的动态读取可自动扩容,适配任意长度的行。 - 内存管理:所有动态分配的内存(行缓冲区、链表节点)都要记得在使用完后释放,避免内存泄漏。
内容的提问来源于stack exchange,提问作者zogac
相关产品推荐
相关产品推荐

