指针Dequeue - 指针训练

时间:2016-10-09 18:41:21

标签: c pointers

我正在尝试在C中设置一个双端指针队列。 到目前为止,我已经将推送功能工作和测试。我的问题似乎与两端的弹出条目有关。

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

dequeue* dequeue_create()
{
    return NULL;
}
void dequeue_push_front(dequeue** dq, int data)
{
    dequeue* tmp = malloc(sizeof(*tmp));
    tmp->data = data;
    tmp->next=NULL;
    if((*dq) == NULL)
    {
        (*dq) = tmp;
    }
    else
    {
        if ((*dq)->next == NULL)
        {
            (*dq)->next = tmp;
            tmp->prev   = (*dq);

        }
        else
        {

            dequeue* tmp_it  = malloc(sizeof(struct _dequeue_));
            tmp_it = (*dq)->next;
            while(tmp_it->next != NULL)
            {
                tmp_it = tmp_it->next;

            }
            tmp_it->next = tmp;
            tmp->prev    = tmp_it;

        }
    }
}

void dequeue_push_back(dequeue** dq, int data)
{
    dequeue* tmp = malloc(sizeof(struct _dequeue_));
    tmp->data = data;
    tmp->prev=NULL;
    if((*dq) == NULL)
    {
        (*dq) = tmp;
    }
    else
    {

        if ((*dq)->prev == NULL)
        {
            (*dq)->prev = tmp;
            tmp->next   = (*dq);

        }
        else
        {
            dequeue* tmp_it  = malloc(sizeof(struct _dequeue_));
            tmp_it = (*dq)->prev;
            while(tmp_it->prev != NULL)
            {
                tmp_it = tmp_it->prev;
            }
            tmp_it->prev = tmp;
            tmp->next    = tmp_it;

        }
    }
}

int dequeue_pop_front(dequeue** dq)
{
    dequeue* tmp_get = malloc(sizeof(struct _dequeue_));
    int output = 0;

    if((*dq)->next == NULL)
    {
        printf("\ndqnext==null\n");
    }
    else
    {
        tmp_get = (*dq);
        while(tmp_get->next != NULL)
        {
            tmp_get= tmp_get->next;
            output = tmp_get->data;
        }
        tmp_get=tmp_get->prev;
        free(tmp_get->next);
        tmp_get->next=NULL;
    }
    return output;
}

int dequeue_pop_back(dequeue** dq)
{
    dequeue* tmp_get = malloc(sizeof(struct _dequeue_));
    int output = 0;

    if((*dq)->prev == NULL)
    {
        printf("\ndqprev==null\n");
    }
    else
    {
        tmp_get = (*dq);
        while(tmp_get->prev != NULL)
        {

            output = tmp_get->data;
            tmp_get= tmp_get->prev;

        }
        free(tmp_get);
        tmp_get=NULL;
    }
    return output;
}

dequeue.h:

#ifndef dequeue_H
#define dequeue_H

struct _dequeue_ {
  struct _dequeue_* next;
  struct _dequeue_* prev;
  int data;
};

typedef struct _dequeue_ dequeue;

dequeue* dequeue_create();
void dequeue_destroy(dequeue** queue);

int dequeue_pop_front(dequeue** dq);
void dequeue_push_front(dequeue** dq, int data);

int dequeue_pop_back(dequeue** dq);
void dequeue_push_back(dequeue** dq, int data);

#endif  /* dequeue_H */

main.c中:

int main()
{
    dequeue* dq = dequeue_create();

    dequeue_push_front(&dq, 1);
    dequeue_push_back(&dq, 2);
    dequeue_push_front(&dq, 3);
    for (int cnt = 1; cnt <=4; cnt++)
    {
        printf("FINAL=%d ", dequeue_pop_front(&dq));
    }


    //TODO : dequeue_destroy(&dq);

    return 0;
}

我对指针很新,这似乎是我的问题。

我在pop函数中尝试做的是迭代指针以到达最后一个并释放最后一个指针。但它似乎没有释放指针。现在尝试了几种不同的方法,但似乎没有一种方法可行,可能是我设置推送功能的方式是不可能释放指针吗?

任何帮助非常感谢。 欢呼声

2 个答案:

答案 0 :(得分:0)

推动

dequeue_push_front(&dq, 1);
  

NULL&lt; - middle(1) - &gt; NULL

dq指向中间节点

dequeue_push_front(&dq, 2);
  

NULL&lt; - middle(1)&lt; - &gt;右(2) - &gt; NULL

dq仍然指向中间节点,因为只有在dq传递NULL

时,您的代码才会更改它
  

NULL&lt; - left(3)&lt; - &gt;中(1)&lt; - &gt;右(2) - &gt; NULL

dq 指向中间节点的原因相同

The Pops

让我们按照你的流行代码:

 tmp_get = (*dq);
 while(tmp_get->next != NULL)
 {
     tmp_get= tmp_get->next;
     output = tmp_get->data;
 }
 tmp_get=tmp_get->prev;
 free(tmp_get->next);
 tmp_get->next=NULL;

这导致以下状态:

  

NULL&lt; - left(3)&lt; - &gt;中(1) - &gt; NULL

dq 指向中间节点。下一步,每隔一次执行该功能

if((*dq)->next == NULL)

将评估为真,导致无法进一步更改。

其他问题

如评论中所述,pop函数中存在内存泄漏。见下文:

dequeue* tmp_get = malloc(sizeof(struct _dequeue_));
...
tmp_get = (*dq);
调用

malloc(),分配sizeof(struct _dequeue_)个字节的内存。返回一个指针,并将其分配给变量tmp_get。然后用不同的指针覆盖此指针,这意味着现在有一块您无法访问或释放的已分配内存块。我无法看到你为什么需要首先分配这个内存的原因。

答案 1 :(得分:0)

在深入研究实际问题之前的一些提示:

  • 在dequeue.c中,第一个#include应该是dequeue.h的,因为这是一个系统的方法来确定,dequeue.h包含了它自己需要的一切。
  • struct dequeue 应该被称为dequeue。 (后面的typedef可以使用相同的名称 - 这里没问题)

然后,有一些误解:你的_dequeue_s是一个出队的NODES但不是一个出队本身。所以,你应该有两个结构:

struct dequeue_node {
        struct dequeue_node * next;
        struct dequeue_node * prev;
        int data;
};

struct dequeue {
        struct dequeue_node * frst;
        struct dequeue_node * last;
        size_t size;
};

首先调用条目(而不是第一个)是我的个人风格,它使其长度为4个字符,如next / prev / last / size,但如果您愿意,可以先调用它。不需要大小但允许O(1)检索出队的大小。

通过这种方式,你不必走遍整个队列就能找到它。

所以,现在你的实际问题是:

创建第一个节点时,dequeue_push_front不会初始化tmp-&gt; prev(并且dequeue_push_back不会初始化tmp-&gt; next)。所以,你从一开始就出列了非法国家。

然后,当我想到&#34;前面&#34;时,我想到&#34;首先&#34;并假设有下一个。所以,差不多,你要交换next和prev的含义。假设这一个:

                       a               b               c
                +-------------+ +-------------+ +-------------+
                | next = b    | | next = c    | | next = NULL |
                | prev = NULL | | prev = a    | | prev = b    |
                +-------------+ +-------------+ +-------------+

我会打电话给#34;第一个&#34;和c&#34;最后&#34;。但是dequeue_push_front试图在这个ascii艺术中添加一个c元素。

鉴于您的命名,推送功能似乎是正确的(除了上述要点)。

pop函数现在有一个错误, s.b已经注意到了。谁再次删除了他的帖子 Ben Wainwright(他编辑,显示为删除后)。你检查(* dp) - &gt; next / prev == NULL,如果这是真的,你要拯救,但你应该删除该节点。所以对于dequeue_pop_front(在你的实现中):

if ((*dq)->next == NULL) {
    dequeue * tmp = (*dq);
    output = tmp->data;
    (*dq) = (*dq)->prev;
    if ((*dq)) {
            (*dq)->next = NULL;
    }
    free(tmp);
} else {
    ...

并且在pop_back中反之亦然。

其余的问题是效率低下和内存泄漏,对于后者你应该学会使用http://valgrind.org/来找到它们,而对于第一个,你应该总是问自己,天气声明可以移出一个循环,就像这里:(再次来自dequeue_pop_front):

    while(tmp_get->next != NULL)
    {
        tmp_get= tmp_get->next;
        output = tmp_get->data; // this can be moved out
    }

输出变量将不断被覆盖,直到循环结束,因此,将其输出:

    while(tmp_get->next != NULL)
    {
        tmp_get= tmp_get->next;
    }
    output = tmp_get->data; // this can be moved out

所以,最终的dequeue.c(但你应该用dequeue&amp; dequeue_node进行更改):

dequeue* dequeue_create()
{
    return NULL;
}
void dequeue_push_front(dequeue** dq, int data)
{
    dequeue* tmp = malloc(sizeof(*tmp));
    tmp->data = data;
    tmp->next=NULL;
    tmp->prev=NULL;
    if((*dq) == NULL)
    {
        (*dq) = tmp;
    }
    else
    {
        if ((*dq)->next == NULL)
        {
            (*dq)->next = tmp;
            tmp->prev   = (*dq);

        }
        else
        {

            dequeue* tmp_it  = malloc(sizeof(struct _dequeue_));
            tmp_it = (*dq)->next;
            while(tmp_it->next != NULL)
            {
                tmp_it = tmp_it->next;

            }
            tmp_it->next = tmp;
            tmp->prev    = tmp_it;

        }
    }
}

void dequeue_push_back(dequeue** dq, int data)
{
    dequeue* tmp = malloc(sizeof(struct _dequeue_));
    tmp->data = data;
    tmp->next=NULL;
    tmp->prev=NULL;
    if((*dq) == NULL)
    {
        (*dq) = tmp;
    }
    else
    {

        if ((*dq)->prev == NULL)
        {
            (*dq)->prev = tmp;
            tmp->next   = (*dq);

        }
        else
        {
            dequeue* tmp_it  = malloc(sizeof(struct _dequeue_));
            tmp_it = (*dq)->prev;
            while(tmp_it->prev != NULL)
            {
                tmp_it = tmp_it->prev;
            }
            tmp_it->prev = tmp;
            tmp->next    = tmp_it;

        }
    }
}

int dequeue_pop_front(dequeue** dq)
{
    dequeue* tmp_get = malloc(sizeof(struct _dequeue_));
    int output = 0;

    if((*dq)->next == NULL)
    {
        dequeue * tmp = (*dq);
        output = tmp->data;
        (*dq) = (*dq)->prev;
        if ((*dq)) {
                (*dq)->next = NULL;
        }
        free(tmp);
    }
    else
    {
        tmp_get = (*dq);
        while(tmp_get->next != NULL)
        {
            tmp_get= tmp_get->next;
            output = tmp_get->data;
        }
        tmp_get=tmp_get->prev;
        free(tmp_get->next);
        tmp_get->next=NULL;
    }
    return output;
}

int dequeue_pop_back(dequeue** dq)
{
    dequeue* tmp_get = malloc(sizeof(struct _dequeue_));
    int output = 0;

    if((*dq)->prev == NULL)
    {
        dequeue * tmp = (*dq);
        output = tmp->data;
        (*dq) = (*dq)->next;
        if ((*dq)) {
                (*dq)->prev = NULL;
        }
        free(tmp);
    }
    else
    {
        tmp_get = (*dq);
        while(tmp_get->prev != NULL)
        {

            output = tmp_get->data;
            tmp_get= tmp_get->prev;

        }
        free(tmp_get);
        tmp_get=NULL;
    }
    return output;
}