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

调试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;
}

错误原因分析

  1. 链表结构体未初始化:main中用malloc分配struct List后,head和tail是未初始化的垃圾值,并非NULL。第一次调用listAdd时,x->head == NULL判断不成立,进入else分支后访问野指针x->head的next成员,触发内存访问错误,进而引发后续异常。
  2. listAdd逻辑缺陷:else分支从x->head->next开始遍历,当链表只有一个节点时,x->head->next为NULL,循环不会执行,新节点无法被添加到链表。
  3. 未检查malloc返回值:如果malloc分配内存失败返回NULL,访问y->value会直接触发Write Access Violation。
  4. 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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.14 21:44:52