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; }
错误原因分析
- 未初始化malloc内存:
mergeTwoLists中分配的mergedList仅申请了内存,未初始化val和next字段,head->val是随机垃圾值,if(head->val == 0)的判断完全不可靠。 - Push函数逻辑缺陷:修改
head->val时未释放newNode造成内存泄漏;当输入链表为空时,mergedList的next是未初始化的垃圾值,访问时触发内存对齐错误(0xbebebebebebebebe是未初始化/已释放内存的标记)。 - 主函数内存泄漏:初始分配的
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
相关产品推荐
相关产品推荐

