C语言简单循环链表插入异常:预期输出10 20却得到20 20
问题分析与修正
我帮你排查了代码里的问题,核心是指针使用逻辑混乱,尤其是全局二级指针的滥用和局部变量地址的错误引用,导致循环链表的插入逻辑出错。你的循环链表实现思路本身没问题,但细节处理错了,我们一步步来解决:
原代码的关键错误
全局二级指针
head的误用
你定义了全局的nodePointer* head,并且在insertLast里把局部变量newNode的栈地址赋值给它:head = &newNode。函数执行结束后,栈上的newNode变量会被销毁,这个地址就变成了野指针,后续访问*head时会读取到无效内容,这是导致输出异常的根本原因。链表结构与全局变量的冲突
你的listPointer结构体里已经有了head指针,但又额外定义了全局head,两者互相干扰,让链表的节点引用逻辑彻底混乱。插入逻辑的二级指针冗余
循环链表的头指针用一级指针就足够维护了,你没必要用二级指针(nodePointer*),这反而增加了复杂度,导致指针引用出错。
修正后的代码(基础版)
我们去掉全局变量,用一级指针维护链表头,修复插入逻辑:
#include <stdio.h> #include <stdlib.h> typedef int element; typedef struct node { element data; struct node *link; } *nodePointer; // 链表结构:用一级指针维护头节点,去掉冗余的二级指针 typedef struct list { nodePointer head; int length; } listPointer; listPointer *list = NULL; void createList() { list = (listPointer *)malloc(sizeof(struct list)); list->head = NULL; list->length = 0; } void insertLast(element data) { nodePointer newNode = (nodePointer)malloc(sizeof(struct node)); newNode->data = data; if (list->head == NULL) { // 空链表:新节点既是头也是尾,自环 list->head = newNode; newNode->link = newNode; } else { // 找到尾节点(尾节点的link指向头) nodePointer tail = list->head; while (tail->link != list->head) { tail = tail->link; } // 插入新节点到尾部 tail->link = newNode; newNode->link = list->head; } list->length++; } void display() { if (list->head == NULL) { puts("Empty list"); return; } // 用do-while更适合循环链表,避免单个节点时的重复判断 nodePointer printNode = list->head; do { printf("%d ", printNode->data); printNode = printNode->link; } while (printNode != list->head); puts(""); } int main(void) { createList(); insertLast(10); insertLast(20); display(); // 现在会输出:10 20 return 0; }
优化版(用尾指针实现O(1)插入)
如果希望插入尾部的操作更快(不需要遍历找尾节点),可以给链表结构增加一个尾指针,这样插入操作的时间复杂度是O(1):
#include <stdio.h> #include <stdlib.h> typedef int element; typedef struct node { element data; struct node *link; } *nodePointer; // 增加尾指针,优化插入效率 typedef struct list { nodePointer head; nodePointer tail; int length; } listPointer; listPointer *list = NULL; void createList() { list = (listPointer *)malloc(sizeof(struct list)); list->head = NULL; list->tail = NULL; list->length = 0; } void insertLast(element data) { nodePointer newNode = (nodePointer)malloc(sizeof(struct node)); newNode->data = data; if (list->head == NULL) { // 空链表:头尾都指向新节点,自环 list->head = newNode; list->tail = newNode; newNode->link = newNode; } else { // 直接通过尾指针插入,无需遍历 list->tail->link = newNode; newNode->link = list->head; list->tail = newNode; } list->length++; } void display() { if (list->head == NULL) { puts("Empty list"); return; } nodePointer printNode = list->head; do { printf("%d ", printNode->data); printNode = printNode->link; } while (printNode != list->head); puts(""); } int main(void) { createList(); insertLast(10); insertLast(20); display(); // 输出:10 20 return 0; }
总结
你的循环链表实现思路本身是可行的,问题出在指针的细节处理上——滥用全局变量和二级指针,导致节点引用逻辑混乱。修正后就能得到你预期的输出结果。
内容的提问来源于stack exchange,提问作者Sangeui
相关产品推荐
相关产品推荐

