2015-06-21 2 views
0

Я уже прочитал несколько ответов, заданных для подобных вопросов, но есть одна вещь, которая делает мой случай немного отличным от того, что я читал. Я использую связанный список для хранения данных для потоков для выбора и обработки. Узел представляет собой простой typedefПравильно освобожденная динамически распределенная структура

struct QueueNode; 

typedef struct QueueNode { 
    struct QueueNode* next; // pointer to the next node 
    void* data; 
} QueueNode; 

В списке

typedef struct LinkedQueue { 
    QueueNode* head; // pointer to the first Node 
    QueueNode* tail; // pointer to the last Node 
    long long k;  // the number of nodes in the queue 
} LinkedQueue; 

Оба инициализируются соответствующие функции, которые используют malloc. Когда поток нуждается в обработке данных, он вызывает одну функцию, которая выталкивает голову очереди и возвращает указатель void* data.

void* pop_data(LinkedQueue* queue) { 
    /* 
    Pops the head node from a queue, extracts data out of it and 
    frees the memory allocated by that node 
    */ 
    assert(queue->head && "Can't pop data from an empty queue"); 

    void* data = queue->head->data;   // extract data from head 
    QueueNode* old_head_pointer = queue->head; 
    queue->head = queue->head->next;   // replacing head with a new one 
    destroy_node(old_head_pointer);   // destroying the old head 

    return data; 
}; 

Дело в том, что destroy_node предполагается освободить память, выделенную для узла, не разрушая void* data указатель, так как данные используются в дальнейшем. Это было моим делом. Все примеры, которые я уже прочитал, описывают случай полного освобождения всего внутри узла, в то время как мне нужно сохранить этот указатель.

void destroy_node(QueueNode* node) { 
    /* 
    Frees memory allocated by a node. 
    */ 
    free(node->next); 
    free(node); 
}; 

В моих тестах это работает отлично, но так как я знаю, что free() фактически не стереть часть памяти и поскольку моя машина имеет тонны памяти тот факт, что я все еще могу получить доступ, что void* data указателя без сегментации на ошибки нельзя полагаться. Таким образом, в основном вопрос заключается в том, что я делаю это правильно или мои соображения действительно разумны? Если это действительно может привести к утечкам памяти или другим проблемам, связанным с памятью, как я должен это делать?

+3

Использование кода вы показываете, вы освобождаете новый 'head' указатель. Не освободите 'node-> next'. –

+0

'struct QueueNode' является неполным типом во всем этом коде ... Возможно, это неконфликтная ошибка, но ошибка, тем не менее, особенно если вы попытаетесь разыменовать« следующий »элемент. Могу ли я предложить вставить 'QueueNode' непосредственно после' typedef struct'? – Sebivor

+0

Фактически это определяется как 'typedef struct QueueNode {...' в реальном коде, но я ценю примечание. –

ответ

2

Вы делаете все правильно, когда вы обращаетесь к указателю data, прежде чем освободить весь узел. Выполнение обратного будет логической ошибкой. Не будет утечек памяти, если вы действительно освободите данные где-нибудь позже в своем коде.

Вы должны, однако, не освобождать поле next узла, поскольку оно также сделает этот узел недействительным, и это, вероятно, не то, что вы хотите сделать. «() Destroy_node» функция

+0

Должен ли я динамически выделять пространство для указателя 'void * data' в функции' pop_data' и явно скопировать указатель? Насколько я считаю, «данные» являются локальной переменной, и она освобождается после «возврата», если она не объявлена ​​как «статическая» или динамически распределенная. –

+0

'data' - действительно локальная переменная. Но его содержимое, вероятно, является возвращаемым значением вызова 'malloc' и остается в силе. Это адрес для содержимого, которое возвращается вызывающему, например, вы можете возвращать целочисленное значение, исходящее из локальной переменной, без проблем. – rems4e

0

если вы хотите сохранить указатель на «Данные»,

Затем сохраните этот указатель в локальную переменную перед вызовом

destroy_node() не оказывает влияния в памяти, где указывается «void * Data».

Как уже упоминалось в другом месте, не бесплатно() на «следующий» указатель, как на самом деле освобождает следующий узел в связанном списке (который «голова» была просто установить, чтобы указать на)

Это означает, что ' head 'теперь указывает на нераспределенную память.

Любые ссылки на эту нераспределенную память приводят к неопределенному поведению.

Это неопределенное поведение может привести к чему угодно, включая событие сбоя seg.

Все операции компиляции должны выполняться с включенным большинством/всеми предупреждениями.

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

каждый предупреждения говорит:

ISO C does not allow extra ';' outside of a function 
Смежные вопросы