调试C语言链表代码时为何出现Write Access Violation错误?
C语言链表Write Access Violation错误修复
调试以下C语言链表代码时触发Write Access Violation错误,调试器显示异常出现在listAdd函数中标记的两行代码处。尝试用malloc为结构体分配内存实现链表,但程序运行失败。
原始代码:
#include <stdio.h> struct Lnode { int value; struct Lnode* next; }; struct List { struct Lnode* head; struct Lnode* tail; }; void listAdd(struct List* x, int val) { struct Lnode* y; y = (struct Lnode*)malloc(sizeof(struct Lnode)); // write access violation y->value = val; // write access violation if (x->head == NULL) { x->head = y; x->tail = y; } else { struct Lnode *currentNode; currentNode = x->head->next; while (currentNode) { if (currentNode->next == NULL) { currentNode->next = y; x->tail = y; break; } currentNode = currentNode->next; } } } struct Lnode* listFind(struct List* x, int value) { if (x->head->value == value) { return x->head; } else if (x->tail->value == value) { return x->tail; } else { struct Lnode* currentNode = x->head->next; while (currentNode) { if (currentNode->value == value) { return currentNode; } currentNode = currentNode->next; } } return NULL; } int main() { struct List* myList = (struct List*)malloc(sizeof(struct List)); listAdd(myList, 10); listAdd(myList, 20); printf("%d", listFind(myList, 10)->value); printf("%d", listFind(myList, 20)->value); return 0; }
错误原因分析
- 链表结构体未初始化:
main中用malloc分配struct List后,head和tail是未初始化的垃圾值,并非NULL。第一次调用listAdd时,x->head == NULL判断不成立,进入else分支后访问野指针x->head的next成员,触发内存访问错误,进而引发后续异常。 - listAdd逻辑缺陷:else分支从
x->head->next开始遍历,当链表只有一个节点时,x->head->next为NULL,循环不会执行,新节点无法被添加到链表。 - 未检查malloc返回值:如果
malloc分配内存失败返回NULL,访问y->value会直接触发Write Access Violation。 - listFind空指针访问:链表为空时,直接访问
x->head->value会触发内存访问错误。
修复后的代码
#include <stdio.h> #include <stdlib.h> struct Lnode { int value; struct Lnode* next; }; struct List { struct Lnode* head; struct Lnode* tail; }; // 初始化链表,将head和tail置为NULL void listInit(struct List* x) { x->head = NULL; x->tail = NULL; } void listAdd(struct List* x, int val) { struct Lnode* y = malloc(sizeof(struct Lnode)); // 检查内存分配是否成功 if (!y) { fprintf(stderr, "内存分配失败\n"); return; } y->value = val; y->next = NULL; // 初始化新节点的next指针 if (!x->head) { x->head = y; x->tail = y; } else { // 直接通过tail指针添加新节点,无需遍历 x->tail->next = y; x->tail = y; } } struct Lnode* listFind(struct List* x, int value) { // 先判断链表是否为空 if (!x->head) return NULL; struct Lnode* current = x->head; while (current) { if (current->value == value) { return current; } current = current->next; } return NULL; } int main() { struct List* myList = malloc(sizeof(struct List)); if (!myList) { fprintf(stderr, "链表结构体内存分配失败\n"); return 1; } // 初始化链表 listInit(myList); listAdd(myList, 10); listAdd(myList, 20); struct Lnode* node10 = listFind(myList, 10); if (node10) printf("%d\n", node10->value); struct Lnode* node20 = listFind(myList, 20); if (node20) printf("%d\n", node20->value); // 释放链表内存,避免内存泄漏 struct Lnode* temp; while (myList->head) { temp = myList->head; myList->head = myList->head->next; free(temp); } free(myList); return 0; }
关键修复点
- 新增
listInit函数初始化链表的head和tail为NULL,彻底避免野指针问题。 - 重构
listAdd的添加逻辑,直接利用tail指针添加新节点,既高效又避免遍历逻辑的缺陷。 - 检查所有
malloc的返回值,处理内存分配失败的情况。 - 修复
listFind函数,先判断链表是否为空,再从头遍历整个链表,逻辑更简洁可靠。 - 添加内存释放代码,避免程序退出后残留内存泄漏。
内容的提问来源于stack exchange,提问作者McorpusC
相关产品推荐
相关产品推荐

