2015-08-21 2 views
5

Я написал программу, использующую стек ADT.
Основной создает новый стек, давая 3 функции для использования с пользователем:Бесплатный указатель от внешней функции

Stack my_stack = sCreate (copy_int, free_int, print_int); 

, когда я взываю к функции «прятки»:

printf ("Peek: |%d|\n\n", *(int*)sPeek(my_stack)); 

у меня есть утечка памяти.

РЕЕК функция выглядит следующим образом:

Element sPeek (Stack stack){ 
if ((NULL == stack) || (0 >= stack->used_places)) 
    return NULL; 

Element returnElement = stack->copy_function(stack->stack_array[stack->used_places-1]); 
if (NULL == returnElement){ 
    free (returnElement); 
    return NULL; 
} 
return returnElement; 

Это вызвано, вероятно, по copy_function называется там, который является copy_int, который был дан пользователем:

Element copy_int (Element element){ 
int *new_int = (int*) malloc(sizeof(int*)); 
*new_int = *(int*)element; 
if (NULL != new_int) 
    return new_int; 
else 
    return NULL; 

Как я освобождаю указатель (malloc) из copy_int?

+1

Непосредственная связь с вашей проблемой, но действительно ли вы думаете, что выделение пространства для одного указателя int ('malloc (sizeof (int *))') является хорошей идеей? –

+0

Вы предлагаете сделать то же самое в стеке? Я имею в виду без malloc? –

+1

По возможности вы должны стараться не использовать с помощью 'malloc', в этом случае вам вообще не нужно' malloc', вы можете просто вернуть 'int' без использования malloc:' return * (int *) element; ' – ex0ns

ответ

1

В последнем фрагменте кода вы используете *new_int перед проверкой возвращаемого значения с malloc. Это вызовет ошибку сегментации, если new_int - NULL. Кроме того, if/else совершенно бесполезен, как написано. Эти четыре строки могут быть заменены на return new_int; без каких-либо изменений в поведении ни при каких обстоятельствах. Наконец, don't cast the return value from malloc.

Со всеми этими проблемами фиксированной, последний фрагмент кода выглядит так

Element copy_int (Element element) 
{ 
    int *new_int = malloc(sizeof(int)); 
    if (new_int) 
     *new_int = *(int*)element; 
    return new_int; 
} 

В функции sPeek, у вас есть такой же бесполезный if заявление. Если returnElement - NULL, нет ничего для free. Таким образом, функция sPeek должна быть

Element sPeek (Stack stack) 
{ 
    if (stack && stack->used_places > 0) 
     return stack->copy_function(stack->stack_array[stack->used_places-1]); 
    else 
     return NULL; 
} 

Наконец на ваш вопрос, память, возвращенный copy_intбудет утечки, если не сохранить копию этого указателя, и free, когда вы сделали с ним. Кроме того, вы запрашиваете другую ошибку сегментации, если передаете указатель NULL на printf. Таким образом, printf линия должна быть заменена кодом (при условии, что Element действительно void *)

int *value = sPeek(my_stack); 
if (value) 
    printf ("Peek: |%d|\n\n", *value); 
free(value); 
+0

Ваш ответ «исправил» мою проблему. Я использовал 2 исправления, и он отлично работает с меньшим количеством кода. –

1

Как освободить указатель (malloc) от copy_int?

Просто позвоните по номеру free(), если вам это больше не нужно.


Также здесь

int * new_int = (int*) malloc(sizeof(int*)); 
*new_int = *(int*)element; 
if (NULL != new_int) 
    return new_int; 
else 
    return NULL; 

тест на NULL должен быть сделан до снятия ссылок указателя element:

int *new_int = malloc(sizeof(int*)); 
if (NULL != new_int) 
{ 
    *new_int = *(int*)element; 
    return new_int; 
} 
else 
    return NULL; 

Примечания: Кастинг результат malloc/calloc/realloc не является необходимым в C и никоим образом не рекомендуется.


Также^2 вызов free() здесь:

if (NULL == returnElement){ 
    free (returnElement); 
    return NULL; 
} 

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

2
Element e = sPeek(my_stack); 
if (e) { 
    printf ("Peek: |%d|\n\n", *(int*)e); 
} 
free(e); 

Кажется немного очевидным, поэтому не уверен, что это вы имели в виду.

1

Любая функция, которая возвращает ресурс, который не автоматически освобождаться после использования должны иметь документацию, как освободить ресурс. В случае malloc(), это документально, как free(), для fopen() это fclose() и т.д.

Когда вы создаете функцию самостоятельно, вы можете, например, обратитесь к free(), если вы вернете указатель, который вы в свою очередь получили от malloc(). Если у вас более сложная настройка, вам может понадобиться создать свою собственную функцию.

Рассматривая вашу функцию, вы выделяете память с использованием malloc(), затем назначаете ее памяти (или взрываете, если выделение не удается, которое вы проверяете слишком поздно), а затем возвращайте точно указатель, полученный от malloc(). Поэтому вы возвращаете ресурс, который может (и должен!) Быть выпущен с free().

BTW: Подумайте о том, чтобы не копировать вещи без необходимости. Ваш вызов copy_int() кажется лишним для меня, просто верните указатель на const int, ссылаясь на существующий элемент, и вы должны быть в порядке.

Смежные вопросы