You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

这段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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.29 06:57:12