C语言链表实现字符串分割函数遇段错误及内存泄漏问题排查
链表实现字符串分割函数的问题排查方案
段错误(指针地址异常)的核心诱因
- 野指针/空指针解引用:链表头、尾指针未初始化为
NULL就直接操作,或是分割字符串时未检查终止符'\0'就盲目移动指针,导致越界访问无效内存;还有可能是节点的next指针被错误赋值,形成无效引用链。 - 内存分配失败未处理:创建链表节点或子字符串时,调用
malloc/calloc后未检查返回值是否为NULL,后续对空指针的直接操作会触发段错误。 - 子串内存写入越界:计算子串长度时出错,导致
strncpy等函数写入超出已分配内存的区域,破坏链表节点结构或其他内存空间。
内存泄漏的关键原因
- 链表节点与子串未联动释放:只释放链表节点本身,却忘记释放节点中存储的子字符串内存;或是提供的销毁函数只处理了节点,遗漏了子串。
- 异常分支内存未回收:分割过程中中途失败(比如某节点内存分配失败),但之前已分配的节点或子串内存没有被清理就直接返回,导致内存泄漏。
- 无效内存分配:处理连续分隔符(如
"a,,b")时,错误生成空串节点且未标记,后续无法追踪释放;或是分配了子串内存却未绑定到节点,导致内存块成为“孤儿”。
针对性排查与修复步骤
规范链表节点创建逻辑
确保节点和子串的内存分配都做合法性检查,且初始化完整:typedef struct Node { char *data; struct Node *next; } Node; Node* create_node(const char *substr, size_t len) { Node *node = malloc(sizeof(Node)); if (!node) return NULL; // 为子串分配内存,预留终止符位置 node->data = malloc(len + 1); if (!node->data) { free(node); // 子串分配失败,必须先释放节点 return NULL; } strncpy(node->data, substr, len); node->data[len] = '\0'; node->next = NULL; return node; }修正链表尾插逻辑
尾插时必须区分空链表和非空链表的情况,避免空指针解引用:void append_node(Node **head, Node **tail, Node *new_node) { if (!*head) { *head = new_node; *tail = new_node; } else { (*tail)->next = new_node; *tail = new_node; } }完善分割逻辑的边界处理
遍历原字符串时必须以'\0'为终止条件,同时处理连续分隔符的场景(根据需求决定是否生成空串):Node* split_string(const char *str, char delim) { Node *head = NULL, *tail = NULL; const char *start = str; while (*str) { if (*str == delim) { size_t len = str - start; if (len > 0) { // 避免连续分隔符生成空节点 Node *node = create_node(start, len); if (!node) { free_split_list(head); // 分配失败,回收已创建的节点 return NULL; } append_node(&head, &tail, node); } start = str + 1; } str++; } // 处理最后一段子串 size_t len = str - start; if (len > 0) { Node *node = create_node(start, len); if (!node) { free_split_list(head); return NULL; } append_node(&head, &tail, node); } return head; }补充完整的内存回收函数
递归或迭代释放所有节点及子串内存:void free_split_list(Node *head) { Node *temp; while (head) { temp = head; head = head->next; free(temp->data); free(temp); } }
内容的提问来源于stack exchange,提问作者VirtualCode
相关产品推荐
相关产品推荐

