【问题标题】:c queue linked list - printing queue changes value of pointers?c队列链表 - 打印队列更改指针的值?
【发布时间】:2018-04-30 07:00:43
【问题描述】:

我在 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() 时,该函数将打印正确的结果。但是,在打印队列之后,前后指针的值会发生变化,并且打印尝试在队列上执行任何更多操作当然会导致段错误,因为它试图访问与预期不同的内存区域。指针的值是如何改变的?在更改指针值之前,我已将队列复制到临时队列,那么为什么实际队列的指针会发生变化?

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

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

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

编辑 2: 我尝试了 Thomas Blanquet 的建议,将函数更改为:

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);
}

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

编辑 3: 我尝试注释掉免费(tmp),但我仍然遇到段错误。然而我发现了问题!不知何故,我没有注意到循环外的 printf():

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

现在删除它会停止段错误并且所有指针都是正确的。非常感谢!

【问题讨论】:

  • 你在结构中有int *data;,但是你使用它就像inttmp->data = data;tmp->front->dataprintf%d。您应该至少会看到一些编译器警告。

标签: c pointers struct linked-list queue


【解决方案1】:

你的“printQueue”有一些问题:

首先,为什么要给tmp分配一个malloc,然后给它q的值呢? 您的 malloc 分配内存并返回此内存的地址,但使用 q 更改它,您丢失了此内存。

那么tmp包含q的地址,所以当你这样做时:

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

您更改队列的前端节点。

您应该执行node *tmp = q->front; 之类的操作并使用它来遍历您的链表,就像您已经对tmp->front 所做的一样。不同之处在于您不会更改队列中前端节点的地址,而是指向它的前端节点的 tmp 变量。

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

编辑

我忘记了一些事情,通过执行free(tmp),在您的帖子中,它的值与 q 相同,您释放了队列结构,因此您不能再在代码中使用它。

【讨论】:

  • 谢谢。是的,你是对的,当然是这样……我对 C 语言不是很有经验,我只是假设它是单独的内存位置,但我现在看到它只是在复制指针。但是,我尝试了您的建议,但仍然出现段错误。
  • 更改后可以发布您的 printQueue 吗?
  • 不客气,我建议您在尝试操作时在纸上画出您的链表和指针。通过一个简单的例子一步一步地阅读你的代码来绘制它。它会让你看到你的错误(例如通过修改错误的指针或在你的列表中很远)。
【解决方案2】:

解决问题...

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

  2. 我删除了 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;
    }
}

非常感谢 Thomas Blanquet。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2018-07-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多