【问题标题】:Designing a Queue in C. Segfault when adding element to queue在 C 中设计一个队列。将元素添加到队列时的 Segfault
【发布时间】:2014-02-22 04:40:36
【问题描述】:

我用 C 编写的队列程序有问题。这是一个循环队列,所以最后一项也必须指向第一项。 addQueue 函数中存在问题。首先,我检查头指针是否设置为 NULL,如果是,则将第一项添加到队列中。但是,head 不等于 NULL,然后我将 item 添加到队列的末尾。我创建了一个迭代指针来迭代,直到它找到结束时: 迭代->下一个 == *head; 我遇到的问题是,当我创建迭代并将其设置为 *head 时,它没有按应有的方式运行。这是我的代码和我收到的输出,我在代码中添加了一些打印以显示我遇到的问题。

 #include <stdlib.h>
 #include <stdio.h>


 //define the Q element struct
 typedef struct _item{
        struct _item* next;
         struct _item* prev;
         int data;
} item;

 item * newItem(){

         item * node = malloc(sizeof(item));
         return node;
 }

 void initQueue(item ** head){
         *head = NULL; //Empty queue means head points to NULL
 }

 void addQueue(item ** head, item item_p){
         //create new item
         item * newIt = newItem();
         newIt = &item_p;
         printf("NewItem: %d\n\n", newIt->data);

         //if *head is NULL, make it point to item
         if(*head == NULL)
         {       
                 *head = newIt; //set head to address of item
                 newIt->next = *head;
                 printf("Again: %p\n\n",  *head);
         }
         //else the list is not empty, add item to end of list
         else    
         {       
                 item * iterate = NULL; 
                 iterate = *head;
                 printf("it: %p head: %p\n\n", iterate, *head);
                 /*while (iterate->next != *head)
                 {
                         iterate = iterate->next;
                 }
                 iterate->next = newIt;
                 newIt->next = *head;*/
         }
 }

这是我为测试功能而编写的 .c 文件:

#include "q.h"
#include <stdio.h>

int main ()
 {

 item  i1;
 i1.data = 1;

 item  i2;
 i2.data = 2;

 item  i3;
 i3.data = 3;

 item * headTemp;
 initQueue(&headTemp);

 addQueue(&headTemp, i1);
 printf("HEAD: %d\n", headTemp->data);
 addQueue(&headTemp, i2);
 printf("HEAD: %d\n", headTemp->data);

 addQueue(&headTemp, i3);


 return 0;
 }

输出是:

NewItem: 1

Again: 0x7fff2252eb10

HEAD: 1
NewItem: 2

it: 0x7fff2252eb10 head: 0x7fff2252eb10

HEAD: 2
NewItem: 3

it: 0x7fff2252eb10 head: 0x7fff2252eb10

Segmentation fault

我创建了三个要插入队列的项目。第一个被毫无问题地放入。但是,当我插入第二个项目时,我遇到了问题。无论我将什么放入队列,headTemp->data 都应该保持不变,但是它从 1 到 2 再到 3,这是我创建的所有项目的数据。我不太确定问题出在哪里,答案可能正盯着我看。但我真的很感激这方面的一些帮助。

干杯!

【问题讨论】:

  • 不要将结构体作为参数传递。使用指针。
  • 请,不要给你的行编号。剪切粘贴代码进行测试完全没有价值。如果您必须注意某一行的特定错误,请添加一条注释,说明“这是 LINE ###”。话虽如此,当我很想仅仅根据发帖人的代表少于 1K 并且正确地不是来对问题进行投票时,这对学术界来说是一个可悲的见证> 铸造malloc()(干得好,顺便说一句)。
  • 查看你的代码,看看你是否能找到你的新节点在哪里有nextprev指针,如果没有设置为以前的有效地址,则初始化为NULL。此外,您会立即在前两行的 addQueue 方法中泄漏内存。这不是java。您的代码将一个自动变量推送到您的队列中,一旦您的函数返回,它将无效。
  • 您没有在列表末尾添加元素。
  • @WhozCraig 感谢您提供有关行号的提示。这是我在 stackoverflow 上的第一篇文章,所以我还在努力适应它。

标签: c pointers segmentation-fault queue


【解决方案1】:

感谢您发布可粘贴代码。一出门就错了:

 item * newIt = newItem();
 newIt = &item_p;

这是立即的内存泄漏。更糟糕的是,您替换它的地址是一个按值自动变量。因此,一旦此函数完成,该地址甚至对于评估都是无效的,更不用说取消引用了。

接下来,您需要为 all 成员变量设置有效状态的节点。如何做到这一点取决于您,但最简单的方法是在节点创建代码中。要真正正确地做到这一点,您的节点创建代码应该是“工厂”函数。 IE。它应该将初始化节点所需的参数作为参数。所以先这样做:

item* newItem( int data )
{
    item * node = malloc(sizeof(item));
    if (item == NULL)
    {
        perror("failed to allocate node.");
        exit(EXIT_FAILURE);
    }

    node->data = data;
    node->next = node->prev = NULL;
    return node;
}

一旦你有了这个坚实的,你可以修改你的addQueue来做到这一点:

void addQueue(item** head, int data)
{
    item *prev = NULL;
    while (*head)
    {
        prev = *head;
        head = &prev->next;
    }

    *head = newItem(data);
    (*head)->prev = prev;
}

这段代码距离成为双端队列还有一段距离。您需要两个指针来执行此操作,并且将它们保存在单独的结构中的最佳位置,以及进行大小查询 O(1) 的计数。如果操作正确,在完整的双端队列中插入是 O(1),但您最终会到达那里。

不管怎样,下面会出现一个更新的 main 来测试它的所有内容。最终你想要一个 pop-functoin 等。

int main()
{
    item *q = NULL;

    for (int i=1; i<=20; ++i)
        addQueue(&q, i);

    item *p = q;
    while (p)
    {
        printf("%d ", p->data);
        p = p->next;
    }
    printf("\n");
    return 0;
}

输出

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 

【讨论】:

  • 非常感谢。这帮助很大。
【解决方案2】:

您的addQueue() 功能不合适。

void addQueue(item ** head, item item_p){
28         //create new item
29         item * newIt = newItem();
30         newIt = &item_p;
31         printf("NewItem: %d\n\n", newIt->data);
32         
33         //if *head is NULL, make it point to item
34         if(*head == NULL)
35         {       
36                 *head = newIt; //set head to address of item
37                 newIt->next = *head;
38                 printf("Again: %p\n\n",  *head);
39         }

在此您执行newItem() 以获取新分配的节点,但您在第 30 行再次将其重新分配给&amp;itemp_p。这不好,因为您没有使用分配的内存,而是项目变量i1, i2, i3main() 中声明。

另外,在newItem() 中将nextprev 设置为NULL

17 item * newItem(){
18 
19         item * node = malloc(sizeof(item));
           if(node) { //You can use calloc too.
              node->next = NULL;
              node->prev = NULL;
           }
20         return node;
21 }

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2023-03-10
    • 2018-07-29
    • 1970-01-01
    • 2017-04-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-06-10
    相关资源
    最近更新 更多