这段C语言链表代码打印异常,求排查及内存分配问题解析
嘿,我帮你找到了代码里的几个关键问题,这就是你打印结果不符合预期的核心原因,咱们一步步拆解修复:
1. 最致命的坑:结构体内存分配大小完全错了
你定义了typedef struct node* node;,这意味着node是个指针类型。但在mklist和listins_beg里,你写了:
*mklist里:*n=(node)malloc(sizeof(node*)); listins_beg里:a=(node)malloc(sizeof(node));
sizeof(node)和sizeof(node*)都是指针的大小(通常4或8字节),但你的struct node实际需要的是整个结构体的内存(包含int、两个100字节的char数组和指针,远大于指针大小)。这直接导致内存分配不足,后续写入name和number时会越界,破坏内存里的其他数据——这就是你打印出奇怪内容的根源!
修复方案:要么分配struct node的大小,要么调整typedef避免混淆(更推荐后者):
// 换个更清晰的typedef:把结构体本身typedef成node,指针用node* typedef struct node node; struct node{ int times; char name[100]; char number[100]; node* next; };
这样malloc(sizeof(node))就会分配整个结构体的正确大小了。
2. 打印链表的逻辑漏了节点
你的printlist有两个问题:
- 空链表判断错了:你初始创建的是一个带"null"的哨兵节点,所以空链表应该是
n->next == NULL(没插入任何节点时),而不是x->next == NULL(此时x就是那个哨兵节点)。 do-while循环会漏掉最后一个节点:循环条件是x->next != NULL,导致最后一个节点(包括哨兵节点)不会被打印。
修复后的printlist(我顺便改成了不带哨兵节点的逻辑,更简洁):
void printlist(node n){ if(n == NULL){ printf("EMPTY LIST"); return; } node x = n; while(x != NULL){ printf("%s - %s\n", x->name, x->number); x = x->next; } }
3. 内存释放函数直接踩了野指针的坑
freelist里的x根本没初始化就直接用x->next,这是未定义行为,轻则打印垃圾,重则程序崩溃。而且循环逻辑也不对,没法正确释放所有节点。
修复后的freelist:
void freelist(node* n){ node current = *n; node next_node; while(current != NULL){ next_node = current->next; free(current); current = next_node; } *n = NULL; // 释放后把头置为NULL,避免野指针 }
完整修正后的代码
我还加了strncpy代替strcpy,避免输入字符串过长导致数组越界,更安全:
#include <stdio.h> #include <stdlib.h> #include <string.h> typedef struct node node; struct node{ int times; char name[100]; char number[100]; node* next; }; // 初始化空链表,不用哨兵节点更简洁 void mklist(node* n){ *n = NULL; } void listins_beg(node* n, char name[], char num[], int tim){ node a = (node)malloc(sizeof(node)); if(a == NULL){ perror("malloc failed"); // 打印分配失败的原因,方便调试 exit(1); } a->times = tim; // 用strncpy保证不越界,手动加结束符 strncpy(a->name, name, sizeof(a->name)-1); a->name[sizeof(a->name)-1] = '\0'; strncpy(a->number, num, sizeof(a->number)-1); a->number[sizeof(a->number)-1] = '\0'; a->next = *n; *n = a; } void printlist(node n){ if(n == NULL){ printf("EMPTY LIST"); return; } node x = n; while(x != NULL){ printf("%s - %s\n", x->name, x->number); x = x->next; } } void freelist(node* n){ node current = *n; node next_node; while(current != NULL){ next_node = current->next; free(current); current = next_node; } *n = NULL; } int main(void){ node n; mklist(&n); listins_beg(&n, "Hermanouhuhuuteu", "4523-2248", 300); listins_beg(&n, "Luhu", "4523-4887", 299); listins_beg(&n, "Lulamolute", "4523-4687", 512); printlist(n); freelist(&n); return 0; }
额外小建议
- 别把指针typedef成单一名称(比如
typedef struct node* node),真的很容易搞混指针和结构体本身,踩内存分配的坑。 - 永远用
strncpy/snprintf这类带长度限制的字符串函数代替strcpy,避免越界。 - 内存分配后一定要检查是否成功,用
perror打印错误信息,调试起来省好多事。
内容的提问来源于stack exchange,提问作者Rafael Santos
相关产品推荐
相关产品推荐

