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

C语言queue_poll函数错误排查:无法取出队列尾元素

问题排查与修复

核心问题分析

你的代码存在三个关键问题,导致queue_poll无法正常工作:

1. queue_poll破坏队列结构,产生野指针

当前实现直接free最后一个节点,但未修改倒数第二个节点的next指针为NULL,导致悬空指针;更严重的是,当队列只有头节点时,你直接free了作为队列入口的queue指针(比如FCFS_queue),使其变为野指针,后续操作完全失效。

2. queue_add是头插法,与"取最后一个元素"的预期错位

queue_add的逻辑是把新元素插入到队列头部:每次将新对象放到头节点的object字段,原头节点的内容被移到新创建的节点并挂到next上。添加A-F后,队列结构为:

FCFS_queue -> object = F
FCFS_queue -> next -> object = E
...
最后一个节点 -> object = A,next = NULL

此时queue_poll取出的是最早添加的A,而非你可能预期的最后添加的F。

3. queue_poll循环逻辑错误

你的循环只能找到最后一个节点,但无法处理头节点本身存储元素的情况,也没有维护队列的链接关系。


修复方案

根据你的需求,分两种场景给出修复代码:

场景1:取出队尾元素(最早添加的元素,如A)

保留头插法的队列结构,修改queue_poll找到倒数第二个节点,维护队列链接,且不释放作为入口的头节点:

void *queue_poll(queue_object *queue) {
    if (queue == NULL || (queue->next == NULL && queue->object == NULL)) {
        return NULL;
    }

    // 头节点直接存储元素,无后续节点
    if (queue->next == NULL) {
        void *object = queue->object;
        queue->object = NULL;
        return object;
    }

    // 找到倒数第二个节点
    queue_object *prev = queue;
    while (prev->next->next != NULL) {
        prev = prev->next;
    }

    queue_object *last_node = prev->next;
    void *object = last_node->object;
    free(last_node);
    prev->next = NULL; // 断开悬空指针
    return object;
}

场景2:取出队头元素(最后添加的元素,如F)

如果你的实际需求是栈式的"后进先出",修改queue_poll直接取头节点元素,并调整队列结构:

void *queue_poll(queue_object *queue) {
    if (queue == NULL || queue->object == NULL) {
        return NULL;
    }

    void *object = queue->object;
    queue_object *tmp = queue->next;
    if (tmp != NULL) {
        queue->object = tmp->object;
        queue->next = tmp->next;
        free(tmp);
    } else {
        queue->object = NULL;
    }
    return object;
}

额外优化:改为标准FIFO队列(可选)

如果要实现标准的先进先出队列,修改queue_add为尾插法,确保新元素添加到队尾:

int queue_add(void *new_object, queue_object *queue) {
    if (queue == NULL || new_object == NULL) {
        return 1;
    }

    // 头节点为空,直接存入
    if (queue->object == NULL) {
        queue->object = new_object;
        return 0;
    }

    queue_object *object = new_queue();
    if (object == NULL) {
        return 1;
    }
    object->object = new_object;

    // 找到队尾节点
    queue_object *tail = queue;
    while (tail->next != NULL) {
        tail = tail->next;
    }
    tail->next = object;
    return 0;
}

此时queue_poll取出队头元素(最早添加的A),符合队列的FIFO特性。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.22 21:25:59