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

LeetCode合并有序链表代码出现地址对齐运行时错误求助(问题21)

LeetCode第21题:合并两个有序链表运行时错误排查与修复

我在LeetCode上运行合并两个有序链表的代码时触发运行时错误:

Runtime Error
Line 10: Char 19: runtime error: member access within misaligned address 0xbebebebebebebebe for type 'struct ListNode', which requires 8 byte alignment [solution.c]
0xbebebebebebebebe: note: pointer points here

这段代码在NetBeans和在线C编译器上能正常编译运行,但LeetCode的C编译器校验更严格,错误出在Push函数第19行,以下是问题排查与修复方案:

原代码

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>

struct ListNode {
    int val;
    struct ListNode *next;
};

void push(int data, struct ListNode* head){
    struct ListNode* newNode = (struct ListNode*)malloc(sizeof(struct ListNode));
    newNode->val = data;
    
    if(head->val == 0){
        head->val = newNode->val;
    }else{
        struct ListNode* curr = head;
        while(curr->next != NULL){
            curr = curr->next;
        }
        curr->next = newNode;
    }
}
 
struct ListNode* mergeTwoLists(struct ListNode* list1, struct ListNode* list2){
    struct ListNode* mergedList = (struct ListNode*)malloc(sizeof(struct ListNode));
    
    struct ListNode* i = list1;
    struct ListNode* j = list2;
    
    while(i != NULL && j != NULL){
        if(i->val < j->val){
            push(i->val, mergedList);
            i = i->next;
        }else{
            push(j->val, mergedList);
            j = j->next;
        }
    }
    
    while(i != NULL){
        push(i->val, mergedList);
        i = i->next;
    }
    
    while(j != NULL){
        push(j->val, mergedList);
        j = j->next;
    }

    return mergedList;
}

void displayList(struct ListNode *curr){
    while(curr != NULL){
        printf("%d", curr->val);
        curr = curr->next;
    }
}

int main()
{
    struct ListNode* List1 = (struct ListNode*)malloc(sizeof(struct ListNode));
    struct ListNode* List2 = (struct ListNode*)malloc(sizeof(struct ListNode));
    
    struct ListNode* newNode0 = (struct ListNode*)malloc(sizeof(struct ListNode));
    newNode0->val = 1;
    List1 = newNode0;
    
    struct ListNode* newNode1 = (struct ListNode*)malloc(sizeof(struct ListNode));
    newNode1->val = 2;
    List1->next = newNode1;
    
    struct ListNode* newNode2 = (struct ListNode*)malloc(sizeof(struct ListNode));
    newNode2->val = 4;
    List1->next->next = newNode2;
    
    struct ListNode* newNode00 = (struct ListNode*)malloc(sizeof(struct ListNode));
    newNode00->val = 1;
    List2 = newNode00;
    
    struct ListNode* newNode10 = (struct ListNode*)malloc(sizeof(struct ListNode));
    newNode10->val = 3;
    List2->next = newNode10;
    
    struct ListNode* newNode20 = (struct ListNode*)malloc(sizeof(struct ListNode));
    newNode20->val = 4;
    List2->next->next = newNode20;
    
    struct ListNode *mergeL = mergeTwoLists(List1, List2);
    
    displayList(mergeL);

    return 0;
}

错误原因分析

  1. 未初始化malloc内存:mergeTwoLists中分配的mergedList仅申请了内存,未初始化val和next字段,head->val是随机垃圾值,if(head->val == 0)的判断完全不可靠。
  2. Push函数逻辑缺陷:修改head->val时未释放newNode造成内存泄漏;当输入链表为空时,mergedList的next是未初始化的垃圾值,访问时触发内存对齐错误(0xbebebebebebebebe是未初始化/已释放内存的标记)。
  3. 主函数内存泄漏:初始分配的List1/List2内存被覆盖,导致内存丢失(非LeetCode触发错误的直接原因)。

修复后的代码

改用哑节点(dummy node)简化边界处理,同时保证内存正确初始化:

#include <stdio.h>
#include <stdlib.h>

struct ListNode {
    int val;
    struct ListNode *next;
};

// 辅助函数:在链表尾部添加节点
void push(int data, struct ListNode* tail){
    struct ListNode* newNode = (struct ListNode*)malloc(sizeof(struct ListNode));
    newNode->val = data;
    newNode->next = NULL;
    tail->next = newNode;
}

struct ListNode* mergeTwoLists(struct ListNode* list1, struct ListNode* list2){
    // 哑节点:统一处理空链表与非空链表的边界情况
    struct ListNode* dummy = (struct ListNode*)malloc(sizeof(struct ListNode));
    dummy->next = NULL;
    struct ListNode* tail = dummy; // 尾指针,跟踪合并链表的最后一个节点

    struct ListNode* i = list1;
    struct ListNode* j = list2;

    while(i != NULL && j != NULL){
        if(i->val < j->val){
            push(i->val, tail);
            tail = tail->next;
            i = i->next;
        }else{
            push(j->val, tail);
            tail = tail->next;
            j = j->next;
        }
    }

    // 直接拼接剩余节点,无需逐个创建新节点
    if(i != NULL){
        tail->next = i;
    }
    if(j != NULL){
        tail->next = j;
    }

    struct ListNode* result = dummy->next;
    free(dummy); // 释放哑节点内存
    return result;
}

void displayList(struct ListNode *curr){
    while(curr != NULL){
        printf("%d ", curr->val);
        curr = curr->next;
    }
}

int main()
{
    // 构建list1: 1->2->4
    struct ListNode* newNode0 = (struct ListNode*)malloc(sizeof(struct ListNode));
    newNode0->val = 1;
    struct ListNode* newNode1 = (struct ListNode*)malloc(sizeof(struct ListNode));
    newNode1->val = 2;
    struct ListNode* newNode2 = (struct ListNode*)malloc(sizeof(struct ListNode));
    newNode2->val = 4;
    newNode0->next = newNode1;
    newNode1->next = newNode2;
    newNode2->next = NULL;
    struct ListNode* List1 = newNode0;

    // 构建list2:1->3->4
    struct ListNode* newNode00 = (struct ListNode*)malloc(sizeof(struct ListNode));
    newNode00->val = 1;
    struct ListNode* newNode10 = (struct ListNode*)malloc(sizeof(struct ListNode));
    newNode10->val = 3;
    struct ListNode* newNode20 = (struct ListNode*)malloc(sizeof(struct ListNode));
    newNode20->val = 4;
    newNode00->next = newNode10;
    newNode10->next = newNode20;
    newNode20->next = NULL;
    struct ListNode* List2 = newNode00;

    struct ListNode *mergeL = mergeTwoLists(List1, List2);

    displayList(mergeL);

    // 实际使用中需释放链表内存,此处为简化省略
    return 0;
}

关键修复点

  • 哑节点初始化:保证链表起始内存完全初始化,避免未定义行为。
  • 尾指针跟踪:无需每次遍历找链表尾部,提升效率同时避免错误。
  • 直接拼接剩余节点:减少内存分配次数,避免重复操作的潜在错误。
  • 内存泄漏修复:释放哑节点内存,主函数移除无用的内存分配。

内容的提问来源于stack exchange,提问作者chree

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.09 01:40:30