链接列表以错误的顺序返回值

时间:2011-10-05 07:48:02

标签: c memory-leaks linked-list

我已经(尝试)编写了LinkedList,但是,当我遍历列表中的所有元素时, 这些项目的输入顺序与插入顺序不同。

说,我这样插入:

slist_insert(list, "red");
slist_insert(list, "green");
slist_insert(list, "blue");
slist_insert(list, "yellow");
slist_insert(list, "pink");
slist_insert(list, "purple");
slist_insert(list, "beige");
slist_insert(list, "white");
slist_insert(list, "black");
slist_insert(list, "brown");
slist_insert(list, "fuchsia");
slist_insert(list, "aqua");
slist_insert(list, "magenta");

但是在循环中,这取而代之的是:

green
magenta
aqua
fuchsia
brown
black
white
beige
purple
pink
yellow
blue
red

我之前没有这样做过,请注意,所以这段代码很可能充满了与链接列表算法相关的元素错误:http://codepad.org/Sl0WVeos

这样的代码工作正常,但有几件事让我烦恼:

  • 错误的订单产生(如上所述)
  • 必须使用宏(有更好的方法吗?)
  • 即使在致电slist_destroy之后,仍有内存泄漏,我无法弄清楚它来自哪里

真的很感激帮助!

3 个答案:

答案 0 :(得分:6)

关于错误的商品订单

slist_impl_insertl()的逻辑错误。

让我们按照你的代码:

stringlist_t* slist_impl_insertl(stringlist_t* list, const char* str, unsigned int len)
{
    stringlist_t* newnode;
    if(list == NULL) // if the list is empty
    {
        newnode = slist_createl(str, len); // create a new item
        list = newnode;                    // insert the new item at the start of the list
        return list;
    }
    else // if the list is not empty
    {
        if(list->next == NULL) // if it contains only one item
        {
            list = slist_insertb(list, str, len); // insert a new item at the front of the list
            return list;
        }
        else // if it contains more than one item
        {
            newnode = slist_createl(str, len);                // create a new node
            newnode->next = (struct stringlist_t*)list->next; // insert the new node just after the first item !?!.
            list->next = (struct stringlist_t*)newnode;
            return list;
        }
    }
    return list; /* not reached */
}

因此,您的插入过程并不总是将新节点插入到同一位置。它有时会在开头插入,有时会插入第二个位置。这解释了为什么这些物品的顺序错误。

一个简单的解决方法是始终在列表的开头插入新节点,然后以相反的顺序生成项目。或者你可以遍历列表直到你到达终点(list->next == NULL),然后在最后一项之后插入新项目:

stringlist_t* slist_impl_insertl(stringlist_t* list, const char* str, unsigned int len)
{
    stringlist_t *iter;
    if(list == NULL)
    {
        list = slist_createl(str, len);
    }
    else
    {
        // find the last ist item
        iter = list; 
        while(iter->next!=NULL)
            iter = iter->next;
        // insert the new item at the end of the list
        iter->next = slist_createl(str,len);
    }
    return list;
}

关于使用宏

如果列表为空(list == NULL),则插入过程将修改列表以使其成为第一个项目。宏负责重新分配修改后的列表。如果您不想使用宏,则必须将list参数作为指针传递,以便可以在插入过程中直接修改它。

(首先编写代码的人使得他可以在列表中间的任何位置插入一个项目,而无需编写具体的程序)

这是slist_insert()的候选实现,不使用宏:

void slist_insert(stringlist_t** list, const char* str)
{
    *list = slist_impl_insertl(*list, str);
}

使用此实现,您必须更改在列表中插入项目的方式:

slist_insert(&list, "red"); // note the use of '&'

关于内存泄漏

销毁程序释放存储在每个项目中的字符串,这很好。但每个项目也是动态分配的,因此它们也需要被释放!你必须存储临时存储列表指针,前进到下一个项目,然后释放存储的指针,直到你到达列表的末尾。

void slist_destroy(stringlist_t* list)
{
    stringlist_t *temp;
    while(list != NULL)
    {
        // free the data contained in the current list item
        free(list->data);
        // save the pointer to the next item
        temp = slist_next(list);
        // free the current item
        free(list);
        // continue with the next item
        list = temp;
    }
}

答案 1 :(得分:2)

在这里,我给你一个自己完成的链表,可能会帮助你理解这个数据结构(我把插入和删除节点的功能放在一起)

void insert(LISTNODEPTR* sPtr, char item)
{
    LISTNODEPTR previousPtr,currentPtr,newPtr;

    newPtr = malloc(sizeof(LISTNODE));

    if(newPtr != NULL)
        {
        newPtr->value = item;
        newPtr->nextPtr = NULL;

        currentPtr = *sPtr;
        previousPtr = NULL;

        while(currentPtr != NULL && currentPtr->value < item)
        {
            previousPtr = currentPtr;
            currentPtr = currentPtr->nextPtr;
        }

        if(previousPtr == NULL)
        {
            newPtr->nextPtr = *sPtr;
            *sPtr = newPtr;
        }
        else
        {
            previousPtr->nextPtr = newPtr;
            newPtr->nextPtr = currentPtr;
        }
    }
    else
    {
        printf("No memory available\n");
    }
}

void delete(LISTNODEPTR* sPtr,char item)
{
    LISTNODEPTR currentPtr,previousPtr,tempPtr;

    if((*sPtr)->value == item)
    {
        tempPtr = *sPtr;
        *sPtr = (*sPtr)->nextPtr;
        free(tempPtr);
    }
    else
    {
        previousPtr = NULL;
        currentPtr = *sPtr;

        while(currentPtr != NULL && currentPtr->value != item)
        {
            previousPtr = currentPtr;
            currentPtr = currentPtr->nextPtr;
        }
        tempPtr = currentPtr;
        previousPtr->nextPtr = currentPtr->nextPtr;
        free(tempPtr);
    }
}

答案 2 :(得分:1)

newnode = slist_createl(str, len);
newnode->next = (struct stringlist_t*)list->next;//1)
list->next = (struct stringlist_t*)newnode;//2)
return list;

列出状态时: 绿光&GT;红 - &GT; NULL

1)newnode-&GT;红 - &GT; NULL

2)绿色 - &gt; newnode-&gt; red-&gt; NULL

newnode总是在绿色(绿色后)和红色之间插入。

<强> slist_destroy

slist_destroy释放字符串缓冲区,而不是释放节点!