简体   繁体   English

为什么在C中执行此队列会导致分段错误?

[英]Why is this queue implementation in C giving segmentation fault?

I have implemented a simple queue in C but its giving segmentation fault when I try to access Q.front after dequeuing (See int main() for example). 我已经在C中实现了一个简单的队列,但是当我尝试出队后访问Q.front时,它给出了分段错误(例如,请参见int main())。

To be more precise, the problem occurs when I - 更确切地说,当我-

  1. Enqueue a single element. 使单个元素入队。
  2. Dequeue it. 出队。
  3. Enqueue one or more elements. 排队一个或多个元素。
  4. Try to access Q.front 尝试访问Q.front

However the program doesn't give segmentation fault or any error when I - 但是,当我-

  1. Enqueue more than one element. 排队多个元素。
  2. Dequeue one time. 出队一次。
  3. Enqueue more elements (optional) 排队更多元素(可选)
  4. Access Q.front successfully. 成功访问Q.front。

So this is my complete program - 这是我完整的程序-

#include <stdio.h>
#include <stdlib.h> //for malloc

struct qnode
{
    int r;
    struct qnode *link;
};

typedef struct qnode qNode;

typedef struct
{
    qNode *front;
    qNode *rear;
    int qsize;
}QUEUE;

QUEUE initializeQueue(void)
{
    QUEUE q;
    q.front = NULL;
    q.rear = NULL;
    q.qsize = 0;
    return q;
}


qNode *createQueueNode(int e)
{
    qNode *temp;
    temp = (qNode *) malloc(sizeof(qNode));
    if(temp == NULL)
    {
        printf("INSUFFICIENT MEMORY\n");
        exit(0);
    }
    temp->r = e;
    temp->link = NULL;
    return temp;
}
QUEUE enqueue(QUEUE q, int e)
{
    if(q.rear == NULL)
    {
        q.rear = createQueueNode(e);
        q.front = q.rear;
        q.qsize++;
    }
    else
    {
        q.rear->link = createQueueNode(e);
        q.rear = q.rear->link;
        q.qsize++;
    }
    return q;
}

QUEUE dequeue(QUEUE q)
{
    qNode *temp;
    if(q.front == NULL)
    {
        printf("queue is empty\n");
        exit(0);
    }
    else
    {
        temp = q.front;
        q.front = q.front->link;
        free(temp);
    }

    q.qsize--;
    return q;
}



int main(){

    QUEUE Q = initializeQueue();
    Q = enqueue(Q, 2);
    printf("%d\n",Q.front->r);
    Q = dequeue(Q);
    Q = enqueue(Q,4);
    printf("%d\n",Q.front->r); // This line is giving segmentation fault 

    return 0;
}
Program terminated with signal 11, Segmentation fault.
#0  0x0000000000400859 in main () at ./2.c:87
87          printf("%d\n",Q.front->r); // This line is giving segmentation fault 
Missing separate debuginfos, use: debuginfo-install glibc-2.12-1.80.el6.x86_64
(gdb) p Q
$1 = {front = 0x0, rear = 0x1636010, qsize = 1}

front is null and you access it. front为空,您可以访问它。 you just need a debuger like gdb to see what's going wrong with your program. 您只需要gdb之类的调试器,即可查看程序出了什么问题。

dequeue sets q.front to NULL (from q.front->link, which was previously set to NULL in createQueueNode) and leaves a trash pointer (to free()'d memory) in q.rear. 出队将q.front设置为NULL(来自q.front-> link,该链接先前在createQueueNode中设置为NULL),并在q.rear中留下垃圾指针(指向free()的内存)。 Since q.rear is not NULL, the 2nd block in the if statement in enqueue gets executed on the 2nd call to enqueue. 由于q.rear不为NULL,因此enqueue中if语句中的第二个块将在enqueue的第二次调用上执行。 Which writes to free()'d memory (q.rear->link), then dereferences that into q.rear. 它将写入free()的内存(q.rear-> link),然后将其取消引用到q.rear。 I'm surprised it doesn't crash right there, actually, with the write to free()'d memory. 令我惊讶的是,它实际上并没有随着对free()内存的写入而崩溃。 Quick fix would probably be to set q.rear to NULL in dequeue if queue is empty. 如果队列为空,则快速解决方法可能是在出队时将q.rear设置为NULL。 You should also add a sanity check so dequeue won't run on an empty queue. 您还应该添加健全性检查,以使出队不会在空队列上运行。

Also, you've got an interesting way of passing that structure around like a hot potato. 另外,您还有一种有趣的方式来传递该结构,就像土豆一样。 Why not pass it by reference and modify it in place instead of returning it? 为什么不通过引用传递它并对其进行修改而不是返回它呢?

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

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