2013-06-16 2 views
0

Здесь я сделал простой тест, чтобы проверить, можно ли удалить элемент в стеке.удаление элемента в стеке в 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 ; 
} 

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

[email protected]:~/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 я узнал, что листовые узлы не были удалены, они все еще были там. Итак, почему этот метод dont показывает какую-либо ошибку в качестве теста, который я сделал ???

ответ

1

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

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

(2) Этот код:

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

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

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

+0

Сэр, (2) печатает 0 в качестве вывода, (3) почему ссылка все еще существует? – Subbu

+0

(2) Можете напечатать что угодно. Это совершенно не определено. Фактически, наиболее вероятным содержимым удаленной памяти является то, что было там поставлено, поэтому код будет вести себя корректно, несмотря на то, что он ошибочен. Это не моя работа, чтобы объяснить, что она делает - это неправильно, и ей разрешено что-либо делать. (3) Указатели 'left' и' right' никогда не очищаются. –

1

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

void deleteElement(int *p) 
{ 

    free(p); 
} 

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

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

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; 
     } 
    } 
} 
+0

Вы имеете в виду, что указатель передается как указатель, а когда он находится в стеке, то ему не выделяется какая-либо память? – Subbu

+0

В deleteTree(), почему это сработало? почему большая ошибка не отображается в этом случае? – Subbu

+0

@CodeJack, да, вы не должны освобождать указатель, на который вы явно не выделили память. – Rohan