释放我创建的双链表

时间:2019-01-24 16:07:06

标签: c free

我试图释放我创建的链表,但是失败了。

我问过“合并双链表”的上一个问题的扩展名,如果您不检查它或对此一无所知,就可以了。
   我创建了两个双链表,然后将它们合并,然后,我要释放它们。所以我写了delete_list()函数。
   但最终,我失败了,错误是“对象0x100404110的错误:未分配释放的指针”。
   如果我只释放第一个列表l,则代码有效。但是,如果我尝试释放全部或两个,则代码会崩溃。
   有人可以帮我吗?谢谢!

from sklearn.feature_extraction.text import CountVectorizer 

vectorizer = CountVectorizer() 

corpus = ['This is the first document.','This is the second second second second document.','And the third one.','Is this the first document?'] 

X = vectorizer.fit_transform(corpus)

没有错误。

3 个答案:

答案 0 :(得分:2)

我相信您的问题在于调用传递给delete_list函数的组件列表上的merge_list

如果我正确理解您的代码,则list实际上只是指向链接列表的第一个节点的指针。您的create_list分配节点,并返回第一个节点的地址,然后您出于任何原因将其丢弃,从而得到指向第二个已分配节点的指针。

类似这样的东西:

list l = pointer to [1] -> [2] -> [3] ...
list m = pointer to [5] -> [10] -> [15] ...

您的merge_list通过更改下一个/上一个指针,使用相同的节点对两个列表执行合并排序。

while(a&&b)
{
    if(a->value<=b->value)
    {
       p->next = a;
       a->prior=p;
       p=a;
       a=a->next;

这意味着列表指针l和列表指针m和列表指针n(合并列表)都指向相同的节点。当您执行list n = merge_list(l,m)时,结果将类似于:

list n = pointer to [1] -> [2] -> [3] -> [5] -> [10] ...
list l = pointer to ^
list m = pointer to 5 ...................^

('l'和'm'指针没有改变,但是它们指向的节点被合并功能修改了。)

当您尝试在删除功能中free的列表节点时,删除列表'l'的第一个调用将起作用。删除列表“ m”的调用将立即失败(如果在我的示例中,如果“ m”的第一个节点大于“ l”的第一个节点),或者释放某些节点,然后失败。删除“ n”将失败,因为在删除“ l”和“ m”的调用中删除了组成“ n”的所有节点。

您可以通过多种方式解决此问题。最简单的方法就是在调用合并时将l和m列表指针重置为NULL,因为在您的系统中,合并两个列表会“消耗”它们,因此所有权从参数转移到结果。

list n = merge_list(l, m); l = m = NULL;

另一种方式是使合并功能创建重复的节点,这意味着merge_list实际上将产生两个列表的副本,从而允许调用者维护参数的所有权。

list n = merge_list(l, m);
// now n, l, m, all exist and are separate

最终的解决方案是为您创建一个位于调用者和节点对象之间的真正的“列表”对象。可以对此对象进行修改以反映这两种情况,但是它是独立的,因此在合并操作期间不会被覆盖,等等。(顺便说一句,我不建议这样做,这是正式的,但是效率很低。)

答案 1 :(得分:2)

为什么您不能释放3个列表的明显答案是因为您没有3个列表。您的函数merge_list的作用恰如其名。它正在将2个列表合并到1个列表中。因此,您不必释放2个原始列表,只需要释放合并的两个列表即可。

答案 2 :(得分:0)

函数create_list()有几个问题,包括不检查错误,不正确处理列表开头的新节点的插入以及不正确处理链接列表的第一个条目。

代码的格式/样式有很多不足之处。

单字符参数和局部变量名称无意义。此类名称应表示contentusage

delete_list()不应返回任何内容,因为没有剩余可返回的内容。因此签名更改为:

void delete_List( Node *list )

不应该typedef指针,因为那样只会使代码混乱。

以下建议的代码解决了上述问题,并对代码进行了格式化以提高可读性

注意:尚未经过测试

struct NODE
{
   struct NODE* prior;
   struct NODE* next;
   int value;
};
typedef struct NODE  Node;

Node * create_list()
{
    Node * head = NULL;

    printf("Please enter the length of double linked list:\n");
    int len;
    if( scanf("%d",&len) != 1 )
    {
        fprintf( stderr, "scanf for length of list failed\n" );
        return NULL;
    }

    for( int i=0; i<len; i++ )
    {
        Node * newNode = malloc(sizeof(Node));
        if ( !newNode )
        {
            perror( "malloc for list nodefailed" );
            // cleanup here
            exit( EXIT_FAILURE );
        }

        if ( !head )
        { // then first entry into linked list
            newNode->next  = NULL;
            newNode->prior = NULL;
        }

        else
        {
            //insert node at front of list
            newNode->next  = head;
            head->prior = newNode;
            newNode->prior = NULL;
        }

        printf("Please enter the value of node:\n");
        int val;
        if( scanf("%d",&val) != 1 )
        {
            fprintf( stderr, "scanf for node value failed\n" );
            // clean up here
            exit( EXIT_FAILURE );
        }

        newNode->value = val;
        head = newNode;
    }
    return head;
}


Node * merge_list( Node *left, Node *right )//合并两个非递减双向链表
{
    if( !left || !right)
        exit(-1);

    Node * workNode   = NULL;
    Node * returnNode = NULL;

    while ( left && right ) 
    {
        if( !workNode )
        { // then first loop
            if( left->value <= right->value )
            {
                workNode = left;
                left = left->next;
            }

            else
            {
                 workNode = right;
                 right = right->next;
            }

            // remember address of beginning of merged list
            returnNode = workNode;
        }


        else if( left->value <= right->value )
        {
            workNode->next  = left;
            left->prior = workNode;
            workNode = left;
            left = left->next;
        }

        else
        {
            workNode->next  = right;
            right->prior = workNode;
            workNode = right;
            right = right->next;
        }
    }

    // if more entries in left
    if( left )
    {
        workNode->next = left;
    }

    else if( right )
    {
        workNode->next = right;
    }
    return returnNode;
}


void delete_List( Node *list )
{
    if(list==NULL)
    {
        printf("List is empty!");
        exit(-1);
    }

    Node * temp;

    while(list)
    {
        temp = list->next;
        free( list );
        list = temp;
    }
}