代码之家  ›  专栏  ›  技术社区  ›  Alex Wicks

c队列链表-打印队列更改指针的值?

  •  1
  • Alex Wicks  · 技术社区  · 7 年前

    我在C中创建了一个链表队列。我的结构如下:

    typedef struct Node{
        int *data;
        struct Node *next;
    } node;
    
    typedef struct Queue{
        node *front, *rear;
    } queue;
    

    在main()函数中,我获取一个用户输入,确定队列的长度,创建一个该长度的数组,并获取数组中每个元素的用户输入。然后调用一个名为runQueue()的函数。

    void runQueue(int array[], int len){
        queue *q = (queue *)malloc(sizeof(queue));
        q->front = q->rear = NULL;
        for(int i = len - 1; i >= 0; i--){ //len-1, user doesn't input 0-based index
            enQueue(q, array[i]);
        }
        printQueue(q);
        enQueue(q,4);
        printQueue(q);
        queueMenu(q);
    }
    

    在这个函数中,我在循环中调用函数enQueue(),将所有节点从数组排入队列。然后我调用printQueue()。

    void enQueue(queue *q, int data){
        node *tmp = (node *) malloc(sizeof(node));
        tmp->data = data;
        tmp->next = NULL;
    
        if (q->rear == NULL){
            q->front = q->rear = tmp;
            return;
        }
    
        q->rear->next = tmp;
        q->rear = tmp;
    }
    
    void printQueue(queue *q){
        int iterator = 0;
        queue *tmp = (queue *)malloc(sizeof(queue));
        tmp = q;
        while(tmp->front->next != tmp->rear->next && tmp->front != NULL){
            iterator += 1;
            //printf("in loop, i = %d\n",iterator);
            printf("Queue node %d: data val %d ptr %p front ptr %p\n", iterator, tmp->front->data, tmp->front, tmp->front->next);
            tmp->front = tmp->front->next;
        }
        printf("Queue node %d: data val %d ptr %p front ptr %p\n", iterator+1, tmp->front->data, tmp->front, tmp->front->next);
        free(tmp);
    }
    

    问题是这样的:我可以运行它,而排队函数似乎工作得很好。第一次调用printQueue()时,该函数将打印正确的结果。然而,在打印队列后,前后指针的值会发生变化,打印尝试在队列上执行更多操作当然会导致segfault,因为它尝试访问的内存区域与它应该访问的内存区域不同。指针的值是如何改变的?在更改指针值之前,我已经将队列复制到一个临时队列,那么为什么实际队列的指针在更改呢?

    编辑: 作为如何将数组输入队列的示例-

    int array[3] = {4,3,2};
    runQueue(array,3);
    

    然后在runQueue()中,for循环通过数组递减,并为数组中的每个元素调用enQueue()。在这种情况下,先调用排队(q,2),然后调用排队(q,3),然后再调用排队(q,4)。

    void printQueue(queue *q){
        int iterator = 0;
        node *tmp = (node *)malloc(sizeof(node));
        tmp = q->front;
        while(tmp != NULL){
            iterator += 1;
            printf("Queue node %d: data val %d ptr %p front ptr %p\n", iterator, tmp->data, tmp, tmp->next);
            tmp = tmp->next;
        }
        printf("Queue node %d: data val %d ptr %p front ptr %p\n", iterator+1, tmp->data, tmp, tmp->next);
        free(tmp);
    }
    

    进行此更改后,指针是正确的,但在退出该函数之前,我仍然会遇到segfault。

    我试着免费发表评论(tmp),但我还是遇到了问题。但是我发现了问题!不知怎的,我在循环外有一个printf(),我没有注意到:

    printf("Queue node %d: data val %d ptr %p front ptr %p\n", iterator+1, tmp->data, tmp, tmp->next);
    

    2 回复  |  直到 7 年前
        1
  •  0
  •   Thomas Blanquet    7 年前

    “打印队列”中存在一些问题:

    首先,你为什么要分配 tmp 用malloc,然后给它 q 的价值? malloc分配内存并返回该内存的地址,但使用 q ,你失去了这段记忆。

    然后 tmp公司 包含的地址 q

    tmp->front = tmp->front->next;
    

    您可以更改队列的前端节点。

    你应该这样做 node *tmp = q->front; tmp->front . 不同之处在于,您不会更改队列中前端节点的地址,而是更改指向其前端节点的tmp变量。

    tmp != NULL 作为条件,在循环之后,您不必为最后一个节点执行特殊情况。

    编辑

    我忘记了一些事情 free(tmp) ,在您的帖子中,它的值与q相同,您可以释放队列结构,这样您就不能在代码中再使用它了。

        2
  •  0
  •   Alex Wicks    7 年前

    要解决问题。。。

    1. 我将tmp变量从队列结构的引用更改为 队列头节点的引用,并在 队列(tmp=tmp->下一个)

    2. 我删除了line free(tmp),因为它释放了 实际队列因此删除了我队列的一部分!

    3. 我删除了额外的printf(),它位于我创建的循环之外 不小心放在那里了!

    代码现在如下所示:

    void printQueue(queue *q){
        int iterator = 0;
        node *tmp = q->front;
        while(tmp != NULL){
            iterator += 1;
            printf("Queue node %d: data val %d ptr %p front ptr %p\n", iterator, tmp->data, tmp, tmp->next);
            tmp = tmp->next;
        }
    }
    

    非常感谢托马斯·布兰克特。