удаление элемента в стеке в C

Здесь я сделал простой тест, чтобы проверить, можно ли удалить элемент в стеке.

// This program test whether an object is dynamically allocated and passed as a parameter to a function , \
//free()ed in that function , then would it really get free()ed or still existing

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

typedef struct node
{
    int data ;
    struct node *next;
} node ;

void deleteElement(int *p)
{

    free(p);
}

void deleteNode(node *node)
{
    free(node);
}

int main()
{
    int i = 10 ;
    int *p = &i ;

    node *parent = (node *)malloc(sizeof(node));
    parent->data = 10;

    node *child = (node *)malloc(sizeof(node));
    parent->next = child ;

    deleteElement(p);
    printf("\np : %d",*p);

    deleteNode(parent);
    printf("\nparent node: %d",parent->data);
    printf("\nchild node : %d",child->data);
    return 0 ;
}

Но я получаю следующую ошибку

codejack@ubuntu:~/Code::Blocks/ProgrammingTests$ ./a.out 
*** glibc detected *** ./a.out: free(): invalid pointer: 0x00007fff9e9fa284 ***
======= Backtrace: =========
/lib/x86_64-linux-gnu/libc.so.6(+0x7eb96)[0x7f34da65cb96]
./a.out[0x4005c4]
./a.out[0x400635]
/lib/x86_64-linux-gnu/libc.so.6(__libc_start_main+0xed)[0x7f34da5ff76d]
./a.out[0x4004c9]
======= Memory map: ========
00400000-00401000 r-xp 00000000 07:00 383254                             /home/codejack/Code::Blocks/ProgrammingTests/a.out
00600000-00601000 r--p 00000000 07:00 383254                             /home/codejack/Code::Blocks/ProgrammingTests/a.out
00601000-00602000 rw-p 00001000 07:00 383254                             /home/codejack/Code::Blocks/ProgrammingTests/a.out
0190a000-0192b000 rw-p 00000000 00:00 0                                  [heap]
7f34da3c8000-7f34da3dd000 r-xp 00000000 07:00 197806                     /lib/x86_64-linux-gnu/libgcc_s.so.1
7f34da3dd000-7f34da5dc000 ---p 00015000 07:00 197806                     /lib/x86_64-linux-gnu/libgcc_s.so.1
7f34da5dc000-7f34da5dd000 r--p 00014000 07:00 197806                     /lib/x86_64-linux-gnu/libgcc_s.so.1
7f34da5dd000-7f34da5de000 rw-p 00015000 07:00 197806                     /lib/x86_64-linux-gnu/libgcc_s.so.1
7f34da5de000-7f34da793000 r-xp 00000000 07:00 700468                     /lib/x86_64-linux-gnu/libc-2.15.so
7f34da793000-7f34da992000 ---p 001b5000 07:00 700468                     /lib/x86_64-linux-gnu/libc-2.15.so
7f34da992000-7f34da996000 r--p 001b4000 07:00 700468                     /lib/x86_64-linux-gnu/libc-2.15.so
7f34da996000-7f34da998000 rw-p 001b8000 07:00 700468                     /lib/x86_64-linux-gnu/libc-2.15.so
7f34da998000-7f34da99d000 rw-p 00000000 00:00 0 
7f34da99d000-7f34da9bf000 r-xp 00000000 07:00 700456                     /lib/x86_64-linux-gnu/ld-2.15.so
7f34daba5000-7f34daba8000 rw-p 00000000 00:00 0 
7f34dabbc000-7f34dabbf000 rw-p 00000000 00:00 0 
7f34dabbf000-7f34dabc0000 r--p 00022000 07:00 700456                     /lib/x86_64-linux-gnu/ld-2.15.so
7f34dabc0000-7f34dabc2000 rw-p 00023000 07:00 700456                     /lib/x86_64-linux-gnu/ld-2.15.so
7fff9e9db000-7fff9e9fc000 rw-p 00000000 00:00 0                          [stack]
7fff9e9ff000-7fff9ea00000 r-xp 00000000 00:00 0                          [vdso]
ffffffffff600000-ffffffffff601000 r-xp 00000000 00:00 0                  [vsyscall]
Aborted (core dumped)

На самом деле я застрял при реализации удаления дерева. Я удалил конечные узлы, используя free(), и теперь родитель станет конечными узлами, а также удалит эти узлы с помощью рекурсии. Но проблема в том, что конечный узел на самом деле не удаляется, он все еще существует. А также метод, которым я следовал при удалении дерева, выглядит следующим образом

void deleteTree(struct node *root)
{
    if(root->left == NULL && root->right == NULL)
    {
       free(root);
    }
    else
    {
       if(root->left != NULL)
            deleteTree(root->left);
       if(root->right != NULL)
            deleteTree(root->right);
    }
}

Этот метод удалял только конечные узлы, а соответствующие родительские узлы не удалялись. После отладки в XCode я обнаружил, что листовые узлы не были удалены, они все еще были там. Почему же этот метод не показывает никаких ошибок, как в моем тесте???


person Subbu    schedule 16.06.2013    source источник


Ответы (2)


Три очевидные ошибки:

(1) deleteElement(p) в конечном итоге вызывает free() для указателя, который не был выделен с помощью malloc().

(2) Этот код:

deleteNode(parent);
printf("\nparent node: %d",parent->data);

ссылается на переменную parent после ее удаления.

(3) В deleteTree() после освобождения дочерних узлов вы сохраняете ссылку на них, так что вы никогда не удалите нелистовые узлы.

person Lee Daniel Crocker    schedule 16.06.2013
comment
Сэр, (2) выводит 0 в качестве вывода, (3) почему ссылка все еще существует?? - person Subbu; 16.06.2013
comment
(2) Может печатать что угодно. Это совершенно неопределенно. На самом деле наиболее вероятным содержимым удаленной памяти является то, что туда было помещено, поэтому код часто будет вести себя правильно, несмотря на то, что он неправильный. Объяснять, что он делает, не моя работа — это неправильно, и ему позволено делать что угодно. (3) Указатели left и right никогда не очищаются. - person Lee Daniel Crocker; 16.06.2013

Вы не можете использовать указатель free(), для которого не выделена память. В вашем случае вы пытаетесь освободить память стека, который недействителен.

void deleteElement(int *p)
{

    free(p);
}

int main()
{
    int i = 10 ;
    int *p = &i ;
    ....
    deleteElement(p);
    ...
}

В методе deleteTree() вы должны сбросить ->left или ->right соответственно после его free()ed, иначе он попытается получить доступ к недействительной/освобожденной памяти.

void deleteTree(struct node *root)
{
    if(root->left == NULL && root->right == NULL)
    {
       free(root);
    }
    else
    {
       if(root->left != NULL)
       {
            deleteTree(root->left);
            root->left = NULL;
       }
       if(root->right != NULL)
       {
            deleteTree(root->right);
            root->right = NULL;
       }
    }
}
person Rohan    schedule 16.06.2013
comment
Вы имеете в виду, что когда указатель передается как указатель и когда он находится в стеке, ему не выделяется память? - person Subbu; 16.06.2013
comment
Почему в deleteTree() это сработало?? почему в этом случае не отображается большая ошибка? - person Subbu; 16.06.2013
comment
@CodeJack, да, вы не должны освобождать указатель, которому вы явно не выделили память. - person Rohan; 16.06.2013