问题释放我仍然需要的内存,链表

时间:2016-07-20 05:48:44

标签: c memory-management data-structures linked-list free

所以我正在做这个任务,作为规则的一部分,帮助者中额外定义的任何东西都需要在最后自由。 问题是:获取一个目的地空链表,取2个已经排序的链表,并将这两个与现有地址合并到目标链表中,我不允许定义新节点。 这就是我所拥有的

void llmrg(struct llist *dest, struct llist *src1, struct llist *src2)
{
    struct llnode *tempdest = dest->front;
    struct llnode *tempsrc;

    while (src1->front != NULL || src2->front != NULL)
    {
        if (src2->front == NULL)
        {
            tempdest->next = src1->front;
            src1->front = NULL;
        }
        else if (src1->front == NULL)
        {
            tempdest->next = src2->front;
            src2->front = NULL;
        }
        else
        {
            if ((src2->front == NULL) || (src1->front->item < src2->front->item))
            {
                tempsrc = src1->front->next;
                if (dest->front != NULL)
                {
                    tempdest->next = src1->front;
                    tempdest = tempdest->next;
                }
                else
                {
                    dest->front = src1->front;
                    tempdest = dest->front;
                }
                src1->front->next = NULL;
                src1->front = tempsrc;
            }
            else
            {
                tempsrc = src2->front->next;
                if (dest->front != NULL)
                {
                    tempdest->next = src2->front;
                    tempdest = tempdest->next;
                }
                else
                {
                    dest->front = src2->front;
                    tempdest = dest->front;
                }
                src2->front->next = NULL;
                src2->front = tempsrc;
            }
        }
    }
    free(tempsrc);
    free(tempdest);
}

所以现在我的问题是,如果我不做“免费”陈述,一切正常,但我不允许这样做,但如果我免费'临时'(免费'tempsrc'不导致问题),然后其中一个值消失,因为它仍然使用tempdest存储。

因此,如果我的列表是(1,3,5)和(2,4,6),结果应该是(1,2,3,4,5,6),并且它可以在没有自由的情况下工作, 但随着我的自由,我得到了(1,2,3,4,0,6)。

数据结构也是:

struct llnode { int item; struct llnode *next; };
struct llist { struct llnode *front; };

通过释放,我不是指链接列表,显然正在使用它们。我的意思是我为了解决这个问题而创建的2个指针tempdesttempsrc - 需要释放它们。

有人可以帮助我以某种方式免费tempdest并保持价值5吗?

4 个答案:

答案 0 :(得分:2)

正如我在评论中所说,

  

为什么你需要释放任何东西?合并两个列表时,每个列表中的每个项目都应该在结果列表中,因此不应释放任何项目。

因为你有一个&#39;列表头&#39;结构(struct llist),您必须设置传递到llmrg()的两个旧列表头结构,以便它们不再指向任何内容。

  

你不允许&#39;免费tempsrctempdest,因为它们不是由您的代码分配的。它们只是列表中项目的临时指针。如果你释放其中任何一个,你就会破坏它们。如果可能,请获取valgrind并使用它。它会帮助你看到你的方式的错误。在merge函数结束时,您需要确保src1->front是空指针,并且src2->front是空指针。但这就是全部。还有什么可以免费的。

这是您的代码适用于测试工具。请注意,此代码中的任何位置都无法调用malloc(),因此无需在任何地方调用free()。这主要是为了说明问题,而不是因为你会在真正的代码中使用非动态内存分配(但你没有显示列表创建代码,而且这样做也避免了必须编写代码)。 / p>

#include <stdio.h>

struct llnode { int item; struct llnode *next; };
struct llist { struct llnode *front; };

static
void llmrg(struct llist *dest, struct llist *src1, struct llist *src2)
{
    struct llnode *tempdest = dest->front;
    struct llnode *tempsrc;

    while (src1->front != NULL || src2->front != NULL)
    {
        if (src2->front == NULL)
        {
            tempdest->next = src1->front;
            src1->front = NULL;
        }
        else if (src1->front == NULL)
        {
            tempdest->next = src2->front;
            src2->front = NULL;
        }
        else
        {
            if ((src2->front == NULL) || (src1->front->item < src2->front->item))
            {
                tempsrc = src1->front->next;
                if (dest->front != NULL)
                {
                    tempdest->next = src1->front;
                    tempdest = tempdest->next;
                }
                else
                {
                    dest->front = src1->front;
                    tempdest = dest->front;
                }
                src1->front->next = NULL;
                src1->front = tempsrc;
            }
            else
            {
                tempsrc = src2->front->next;
                if (dest->front != NULL)
                {
                    tempdest->next = src2->front;
                    tempdest = tempdest->next;
                }
                else
                {
                    dest->front = src2->front;
                    tempdest = dest->front;
                }
                src2->front->next = NULL;
                src2->front = tempsrc;
            }
        }
    }
    src1->front = NULL;
    src2->front = NULL;
}

static void print_llist(const char *tag, struct llist *list)
{
    printf("%s:", tag);
    struct llnode *node = list->front;
    while (node != 0)
    {
        printf(" %d", node->item);
        node = node->next;
    }
    putchar('\n');
}

int main(void)
{
    struct llnode data[] =
    {
        { 1, &data[1] }, { 3, &data[2] }, { 5, 0 },
        { 2, &data[4] }, { 4, &data[5] }, { 6, 0 }
    };
    struct llist ll1 = { &data[0] };
    struct llist ll2 = { &data[3] };
    struct llist ll3 = { 0 };
    printf("Before:\n");
    print_llist("ll1", &ll1);
    print_llist("ll2", &ll2);
    print_llist("ll3", &ll3);

    llmrg(&ll3, &ll1, &ll2);

    printf("After:\n");
    print_llist("ll1", &ll1);
    print_llist("ll2", &ll2);
    print_llist("ll3", &ll3);

    return 0;
}

我在llmrg()功能的末尾添加了两个分配,代替了两个free()来电。我不确定他们是否有必要,但他们肯定会做这件事。显然,如果列表结构或节点结构是动态分配的,那么它们需要被释放,而不是llmrg()代码。

示例输出:

Before:
ll1: 1 3 5
ll2: 2 4 6
ll3:
After:
ll1:
ll2:
ll3: 1 2 3 4 5 6

请注意,您可以大大简化合并功能 - 减少25行代码。 (通常更容易使小函数正确,并保持正确。但是,使用struct llnode **dest无疑是微妙的,虽然有效。)当代码包含&(*dest)->next时,这相当于{{1 } { - &((*dest)->next)指向的next指针的地址。

*dest

测试数据略有不同;它会像原始数据一样快乐地处理原始数据。

示例输出:

#include <assert.h>
#include <stdio.h>

struct llnode { int item; struct llnode *next; };
struct llist { struct llnode *front; };

static
void llmrg(struct llist *dst0, struct llist *src1, struct llist *src2)
{
    struct llnode *node1 =  src1->front;
    struct llnode *node2 =  src2->front;
    struct llnode **dest = &dst0->front;

    src1->front = NULL;
    src2->front = NULL;

    while (node1 != NULL && node2 != NULL)
    {
        if (node1->item < node2->item)
        {
            *dest = node1;
            node1 = node1->next;
        }
        else
        {
            *dest = node2;
            node2 = node2->next;
        }
        dest = &(*dest)->next;
    }

    if (node1 != NULL)
        *dest = node1;
    if (node2 != NULL)
        *dest = node2;
}

static void print_llist(const char *tag, struct llist *list)
{
    printf("%s:", tag);
    struct llnode *node = list->front;
    while (node != 0)
    {
        printf(" %d", node->item);
        node = node->next;
    }
    putchar('\n');
}

int main(void)
{
    struct llnode data[] =
    {
        { 2, &data[1] }, { 3, &data[2] }, { 5, 0 },
        { 1, &data[4] }, { 4, &data[5] }, { 6, &data[6] }, { 8, 0 },
    };
    struct llist ll1 = { &data[0] };
    struct llist ll2 = { &data[3] };
    struct llist ll3 = { 0 };

    printf("Before:\n");
    print_llist("ll1", &ll1);
    print_llist("ll2", &ll2);
    print_llist("ll3", &ll3);

    llmrg(&ll3, &ll1, &ll2);

    printf("After:\n");
    print_llist("ll1", &ll1);
    print_llist("ll2", &ll2);
    print_llist("ll3", &ll3);

    return 0;
}

答案 1 :(得分:1)

  

我的意思是我为了解决这个问题而创建的2个指针tempdesttempsrc - 需要释放它们。

不,他们没有。你没有释放指针,释放了用malloc分配的内存块。你的函数没有malloc任何内存,所以它没有free

答案 2 :(得分:1)

无需释放tempsrc或tempdst。这些指针没有被分配任何内存,而只是指向你已经拥有和需要的内存(列表中的llnode)。你实际上不需要任何东西。你的情况与此类似:

int* someInts = malloc(sizeof(int) * 10); // allocates memory for 10 ints

int* tempInt = &someInt[5]; // points to the 5th int someInts, no new memory allocated 

//free(tempInt);
//There is no need to free this as it is just a pointer
//to some memory already "owned" by someInts

free(someInts);
//Freeing this pointer frees all the memory allocated in the first line.

答案 3 :(得分:-1)

您需要更多临时变量来存储指向当前每个输入列表的节点节点的指针。

For the lazy