简体   繁体   English

将元素添加到队列时在C.Segfault中设计队列

[英]Designing a Queue in C. Segfault when adding element to queue

I am having a problem with a queue program I am writing in C. This is a circular queue, so the last item must also point to the first item. 我在用C编写的队列程序遇到问题。这是循环队列,因此最后一项也必须指向第一项。 The problem exists within the addQueue function. 问题存在于addQueue函数中。 First I check whether the head pointer is set to NULL, if it is then I add the first item to the queue. 首先,我检查头指针是否设置为NULL,如果是,则将第一项添加到队列中。 However, head is not equal to NULL, then I add the item to the end of the queue. 但是,head不等于NULL,那么我将项目添加到队列的末尾。 I create an iterate pointer to iterate until it finds the end when: iterate->next == *head; 我创建一个迭代指针来进行迭代,直到以下情况找到结束为止:iterate-> next == * head; The problem I am having is that when I create iterate and set it to *head, it is not operating as it should. 我遇到的问题是,当我创建迭代并将其设置为* head时,它无法正常运行。 Here is my code and the output I have received, I added some prints in the code to show the problem I am having. 这是我的代码和收到的输出,我在代码中添加了一些打印件以显示我遇到的问题。

 #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;*/
         }
 }

Here is the .c file I wrote to test the functions: 这是我编写的用于测试功能的.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;
 }

And the output is: 输出为:

NewItem: 1

Again: 0x7fff2252eb10

HEAD: 1
NewItem: 2

it: 0x7fff2252eb10 head: 0x7fff2252eb10

HEAD: 2
NewItem: 3

it: 0x7fff2252eb10 head: 0x7fff2252eb10

Segmentation fault

I created three items to insert into the queue. 我创建了三个要插入队列的项目。 The first is placed in without issue. 首先放置没有问题。 However I have problems when I insert a second item. 但是,当我插入第二个项目时遇到问题。 The headTemp->data should remain the same no matter what I place into the queue, however it goes from 1 to 2 to 3, which is the data for all items I created. 无论我将什么放入队列中,headTemp-> data都应保持不变,但是它从1到2到3,这是我创建的所有项目的数据。 I'm not really sure what the problem is, and the answer may be staring me in the face. 我不太确定问题是什么,答案可能正盯着我。 But I would really appreciate some help with this. 但我真的很感谢您的帮助。

Cheers! 干杯!

Your addQueue() function is not appropriate. 您的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         }

In this you do newItem() to get newly allocated node, but you again re-assign it to &itemp_p on line 30. This is not good, as you are not using allocated memory, but items variables i1, i2, i3 declared in main() . 在此过程中,您要执行newItem()以获取新分配的节点,但再次在第30 &itemp_p其重新分配给&itemp_p 。这不好,因为您没有使用分配的内存,而是在main()声明了项变量i1, i2, i3main()

Also, in newItem() set next and prev to NULL 另外,在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 }

Thanks for posting paste-able code. 感谢您发布可粘贴的代码。 Right out of the gate, this is wrong: 就在大门外,这是错误的:

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

this is an immediate memory leak. 这是立即的内存泄漏。 Worse the address your replacing it with is a by-value automatic variable. 更糟糕的是,您将其替换为按值自动变量的地址。 Therefore the address is going to be invalid to even evaluate , much less dereference, as soon as this function is finished. 因此,一旦该函数完成,地址将无效,甚至无法评估 ,更不用说取消引用了。

Next, you need to prime your nodes with valid state for all member variables. 接下来,您需要使用所有成员变量的有效状态来初始化节点。 How you do this is up to you, but the simplest way is in the node-creation code. 如何执行此操作取决于您,但是最简单的方法是在节点创建代码中。 To really do this properly, your node creation code should be a "factory" function. 为了真正正确地做到这一点,您的节点创建代码应该是“工厂”功能。 Ie it should take as parameters what is needed to initialize the node. 即,应将初始化节点所需的参数作为参数。 So do this first: 所以先这样做:

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

Once you have that solid, you can modify your addQueue to do this: 获得该实体后,您可以修改addQueue以执行此操作:

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

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

This code is still a ways off from being a deque. 这段代码距离双端队列还很遥远。 You need two pointers to do that, and the best place to keep them is in a separate struct, along with a count to make size-inquiries O(1). 您需要两个指针来执行此操作,并且保留它们的最佳位置是在单独的结构中,并带有进行大小查询的计数O(1)。 Properly done, insertion is O(1) in a full deque, but you'll get there eventually. 如果正确完成,则在完全双端队列中插入O(1),但最终您会到达那里。

Anyway, an updated main appears below for testing everything made it in. Eventually you want a pop-functoin, etc. 无论如何,下面都会显示一个更新的主界面,以测试其中的所有内容。最终,您需要一个弹出功能,等等。

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

Output 输出量

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM