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

链表实现队列时数据丢失与指针异常问题求助——修改节点数据类型后display输出全0

问题分析与修复方案

你的核心问题出在链表节点对数组的内存管理和指针操作错误,不管是传值还是传指针版本,都存在野指针、指针访问优先级错误或者内存赋值无效的问题。下面逐一拆解并给出修复方案:

1. 传值版本的致命错误

在enqueue函数里,你写了:

tmp->data = &value;

这里的value是函数的形参(数组作为函数参数会退化为指针),本质上是局部变量。当enqueue函数执行完毕后,这个局部变量的内存会被系统回收,tmp->data就变成了野指针。后续调用display访问这个指针时,内存内容已经被覆盖,所以输出全是0(或随机垃圾值)。

另外,你试图在dequeue里用free(tmp)释放数组,但实际上你根本没有为数组分配动态内存,这会导致非法内存释放操作。

2. 传指针版本的错误

  • 指针访问优先级错误:在enqueue里打印数组时,*value[i]的写法是错的。因为[]的优先级高于*,value[i]会被先解析为第i个float[20]数组的指针,这显然不是你要的。正确写法应该是(*value)[i],先解引用得到数组,再访问下标。
  • 野指针隐患:你把tmp->data指向了main里的局部数组tmp,后续如果修改main里的tmp,队列里的内容会跟着变化;如果局部数组内存被回收,同样会出现野指针问题。

3. 通用修复思路

链表节点需要独立存储每个数组的数据,而不是指向外部局部变量。这里推荐两种可靠方案:

方案一:节点直接存储数组(简单易维护)

修改节点结构体,直接在节点内定义数组,这样分配节点时会自动包含数组内存,避免额外的内存管理:

修正后的完整代码

#include <time.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h> // 需要memcpy做数组拷贝
#define QUEUE_SIZE 30
typedef float dataArray[20];

struct node {
    dataArray data; // 直接存储数组,无需指针
    struct node *next;
};
typedef struct node node;

struct queue {
    int count;
    node *front;
    node *rear;
};
typedef struct queue queue;

void initialize(queue *q);
int is_empty(queue *q);
void enqueue(queue *q, const dataArray value);
void dequeue(queue *q, dataArray outputArray);
void display(node *head);
float random_float();

void initialize(queue *q) {
    q->count = 0;
    q->front = NULL;
    q->rear = NULL;
}

int is_empty(queue *q) {
    return (q->rear == NULL);
}

void enqueue(queue *q, const dataArray value) {
    // 队列满时先出队一个元素
    if (q->count == QUEUE_SIZE) {
        dataArray tmp;
        dequeue(q, tmp);
    }

    node *tmp_node = malloc(sizeof(node));
    if (!tmp_node) { // 检查内存分配是否成功
        perror("malloc failed");
        exit(EXIT_FAILURE);
    }
    // 拷贝数组内容到节点,确保数据独立
    memcpy(tmp_node->data, value, sizeof(dataArray));
    tmp_node->next = NULL;

    if (!is_empty(q)) {
        q->rear->next = tmp_node;
        q->rear = tmp_node;
    } else {
        q->front = q->rear = tmp_node;
    }
    q->count++;

    // 调试输出
    printf(" contents of tmp-node in enqueue\n");
    for (int i = 0; i < 20; i++) {
        printf("%f\n", tmp_node->data[i]);
    }
}

void dequeue(queue *q, dataArray outputArray) {
    if (is_empty(q)) {
        printf("Queue is empty!\n");
        return;
    }

    node *tmp_node = q->front;
    // 把队列头部的数组拷贝到输出数组
    memcpy(outputArray, tmp_node->data, sizeof(dataArray));

    // 调试输出
    printf("dequeue output before freeing memory\r\n===========\r\n");
    for (int i = 0; i < 20; i++) {
        printf("%f\n", outputArray[i]);
    }

    q->front = q->front->next;
    if (q->front == NULL) { // 队列空了后重置rear
        q->rear = NULL;
    }
    q->count--;
    free(tmp_node); // 释放节点,数组作为节点的一部分自动被释放
}

void display(node *head) {
    if (head == NULL) {
        printf("NULL\r\n");
        return;
    }
    for (int i = 0; i < 20; i++) {
        printf("%f\n", head->data[i]);
    }
    display(head->next);
}

float random_float() {
    // srand只需要初始化一次,放在main里即可
    float a = 50.0;
    return ((float)rand() / (float)(RAND_MAX)) * a;
}

int main() {
    queue *q = malloc(sizeof(queue));
    if (!q) {
        perror("malloc failed");
        exit(EXIT_FAILURE);
    }
    initialize(q);
    srand((unsigned int)time(NULL)); // 仅初始化一次随机种子

    dataArray tmp;
    for (int i = 0; i < 20; i++) {
        tmp[i] = random_float();
    }
    printf("display dataArray before enqueue\r\n===========\r\n");
    for (int i = 0; i < 20; i++) {
        printf("%f\n", tmp[i]);
    }

    enqueue(q, tmp);
    printf("Queue display after enqueue\r\n===========\r\n");
    display(q->front);

    printf("Queue before dequeue\r\n===========\r\n");
    printf("Queue #1 element count: %d\r\n", q->count);

    dataArray queData;
    dequeue(q, queData);
    printf("Queue after dequeue\r\n===========\r\n");
    printf("Queue #1 element count: %d\r\n", q->count);
    for (int i = 0; i < 20; i++) {
        printf("%f\n", queData[i]);
    }

    // 清理队列剩余节点
    while (!is_empty(q)) {
        dataArray dummy;
        dequeue(q, dummy);
    }
    free(q);
    return 0;
}

关键修复点

  • 节点结构体修改:把dataArray *data改成dataArray data,每个节点自带独立的数组空间。
  • 数组拷贝:用memcpy复制数组内容,确保队列中每个元素的数据独立。
  • dequeue函数修正:不再试图修改形参指针(之前的赋值是无效的,因为形参是局部变量),而是直接拷贝数据到输出数组。
  • 随机种子优化:把srand移到main中仅调用一次,避免每次生成相同的随机数。
  • 内存安全:添加内存分配失败检查和空队列处理,避免程序崩溃。

方案二:动态分配数组(适合内存敏感场景)

如果需要灵活控制数组内存,可以让节点指针指向动态分配的数组,但要注意双重内存管理:

// 修改节点结构体
struct node {
    dataArray *data; // 指向动态分配的数组
    struct node *next;
};

// enqueue中分配数组
tmp_node->data = malloc(sizeof(dataArray));
memcpy(tmp_node->data, value, sizeof(dataArray));

// dequeue中释放内存
free(tmp_node->data); // 先释放数组
free(tmp_node); // 再释放节点

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.27 19:17:39