C语言自定义递归链表存储内容输出乱码问题求解
问题根因
你代码的核心错误出在next_source的拷贝逻辑:
- 当你创建
head节点传入next_source=tail时,你调用了new_list(NULL, next_source, next_source->next)生成后继节点,此时由于string_source为空、list_source非空,新生成的head->next节点类型被判定为LIST,联合体内存储的是指向克隆后tail节点的指针,而非直接将tail克隆为STRING类型的后继节点。 - 你直接访问
head->next->STRING时,实际读取的是联合体中存储的LIST指针的内存内容,属于非法访问,自然输出乱码。单独打印tail->STRING正常,是因为tail本身是类型正确的STRING节点。
此外你的代码还有隐含风险:ctype的判断没有兜底分支,如果两个源参数同时非空会触发未定义行为。
优化方案
你需要把「创建单个节点」和「克隆整条链表」的逻辑拆分,避免语义混淆:
- 新增
clone_list函数专门负责递归克隆整条链表(包含所有同级next节点) new_list仅负责创建单个节点,后继节点的克隆直接调用clone_list实现
修改后参考代码
#include <assert.h> typedef enum ListType ListType; typedef struct List List; enum ListType { STRING, LIST }; struct List { union { char* STRING; List* LIST; }; ListType type; List* next; }; // 新增:克隆整条链表的辅助函数 List* clone_list(List* src) { if (src == NULL) return NULL; List* temp = calloc(1, sizeof(List)); temp->type = src->type; if (src->type == STRING) { int n = strlen(src->STRING) + 1; temp->STRING = calloc(1, n); strcpy(temp->STRING, src->STRING); } else { temp->LIST = clone_list(src->LIST); } // 递归克隆后继节点 temp->next = clone_list(src->next); return temp; } // 修改后的new_list,仅负责创建单个节点 List* new_list(char* string_source, List* list_source, List* next_source) { if(string_source == NULL && list_source == NULL) return NULL; // 加断言避免非法入参 assert((string_source == NULL) != (list_source == NULL)); List* temp = calloc(1, sizeof(List)); if(string_source != NULL) { temp->type = STRING; int n = strlen(string_source) + 1; temp->STRING = calloc(1, n); strcpy(temp->STRING, string_source); } else { temp->type = LIST; // 克隆传入的子链表 temp->LIST = clone_list(list_source); } // 后继直接克隆整条传入的next链表 temp->next = clone_list(next_source); return temp; }
修改后你的测试用例可以正常输出预期结果,同时也能支持嵌套链表的克隆需求。
内容的提问来源于stack exchange,提问作者user16830968
相关产品推荐
相关产品推荐

