2016-03-08 2 views
1

Я столкнулся с тем, что кажется странной проблемой при реализации единого списка. Я вызываю list_destroyer и передаю указатель на заголовок списка, однако при возврате метода передаваемый указатель все же указывает на полный список. Я не верю, что я передал структуру где угодно.Освобождение одного связанного списка в c

Вот мой список структуры и ЬурейеГо

typedef struct list list_t 
struct list{ 
    void* datum; 
    list_t* next; 
}; 

А вот код, который вызывает проблему

void list_destroy(list_t *head){ 
    list_t *destroy = head; 
    while(head){ 
     //printf("%d \n", list_size(head)); 
     head = head->next; 
     free(destroy); 
     destroy = head; 
    } 
    //printf("%d \n", list_size(head)); 
    head = NULL; 
    //printf("%d \n", list_size(head)); 
} 

Функция list_size была закомментирована, потому что они не нужны, но Я использую их для просмотра вывода кода. Выход printf показывает, что размер уменьшается. Два printf окружают «head = NULL;» оператор печатает нулевой размер. Это также подтверждается gdb. Однако, когда у меня есть этот код (следующий), вызывающий list_destroy, передаваемый указатель не изменяется.

int main(){ 
    list_t *test = NULL; 
    int a = 1; 
    int b = 2; 
    list_append(test,&a); 
    list_append(test,&b); 
    printf("%d \n", list_size(test)); 
    list_destroy(test); 
    printf("%d \n", list_size(test)); 
} 

я все еще получаю Printf выше и ниже list_destroy на оба выхода 2. Я не инициализирован новый list_t где-нибудь, так что я не вижу, как Printf после list_destroy будет по-прежнему выход 2, (особенно когда Printf в list_destroy говорит list_t * прошел в имеет размер 0 в конце.

+1

Я не знаю, если это адекватное объяснение (я не смотрел на свой код в деталях), но освобождение памяти не перезаписывает его. –

ответ

3

однако, когда метод возвращает указатель, который передается по-прежнему указывает на полный список.

Это неверно: когда функция retu rns, указатель указывает на то, что раньше было полным списком. Скорее всего, ваша система позволит вам пройти весь список без перерыва. Однако разыменование этого указателя после вызова не определено поведение, поэтому тот же код может быть поврежден в других системах.

Проблема имеет имя - head становится болтается указатель.

Решение проблемы просто - передать указатель на указатель, и установить его на NULL после завершения:

void list_destroy(list_t **headPtr){ 
    list_t *head = *headPtr; 
    list_t *destroy = head; 
    while(head){ 
     head = head->next; 
     free(destroy); 
     destroy = head; 
    } 
    *headPtr = NULL; 
} 
+0

Разве это действительно отличается от того, что у меня есть? Ваше использование * headPtr эквивалентно моей голове list_t *, не так ли? и у меня есть строка «head = NULL;» в самом конце. Поэтому указатель не должен болтаться. Является ли мой мыслительный процесс неправильным здесь? –

+0

@DrewKay Назначение 'head = NULL' в вашем коде не влияет на указатель, переданный в' list_destroy', потому что указатели передаются по значению. 'list_destroy' получает свою собственную личную копию' test' от 'main'. Ему разрешено назначать его независимо от того, что он пожелает; 'test' в функции' main' останется прежним. Мое изменение передает указатель указателем, позволяя присваивать внутри 'list_destroy' модифицировать указатель' test' от вашей функции 'main'. – dasblinkenlight

+0

Ах, спасибо. В этом есть смысл. Однако это для проекта класса, и реализация вызывает list_destroy (list_t * head), поэтому я отправлю письмо профессору и посмотрю, есть ли ошибка. –

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