2016-06-30 3 views
1

Я попытался реализовать связанный связанный список в c. Я хотел иметь возможность использовать несколько экземпляров списка, и я хотел создать список в основной функции. Вот почему я решил реализовать его так, как я.C malloc valgrind - неинициализированная память в моей реализации с одним связанным списком

Код работает отлично, но меня беспокоит из-за вывода valgrind. Также я попытался использовать код в проекте во встроенной системе, и произошли странные ошибки.

Выход Valgrind является:

начиная ...

== 3570 == Условный переход или переход, зависит от величины неинициализированных (ов)

== 3570 == в 0x100000E8E : push_cfront (в ./map_test)

== 3570 == по 0x100000D4F: Основной (в ./map_test)

== 3570 == Неиницализированные значение было создано путем выделения кучи

== 3570 == в 0x100008EBB: таНос (в /usr/local/Cellar/valgrind/3.11.0/lib/valgrind/vgpreload_memcheck-amd64-darwin.so)

== 3570 == от 0x100000E80: push_cfront (в ./map_test)

== 3570 == от 0x100000D4F: Основной (в ./map_test)

== 3570 ==

. ..готовление

Также он говорит мне, что я теряю один блок. Где я делаю ошибку, освобождая его

== 3570 == УТЕЧКИ РЕЗЮМЕ:

== 3570 == определенно потеряли: 16 байт в 1 блоках

== 3570 == косвенно потерянным : 0 байт в 0 блоков

== 3570 == возможно потеряно: 2064 байт в 1 блоках

== 3570 == еще достижимы: 0 байт в 0 блоков

== 3570 == подавлено: 24,525 байт в 186 блоков

Пожалуйста, дайте мне подсказку о том, где я пошло не так.

test.c:

#include <stdio.h> 
#include <stdint.h> 
#include <stdlib.h> 
#include "command_list.h"  
int main() { 

    printf("starting...\n"); 

    Clist * command_list = malloc(sizeof(Clist)); 
    if (command_list == NULL) printf("Malloc Failed\n"); 
    command_list->head = NULL; 

    //push_cback(command_list, 0); 
    push_cfront(command_list,1); 

    free_clist(command_list); 
    free(command_list); 
    printf("\n...finished\n"); 
    return 0; 
} 

command_list.h:

#ifndef __COMMAND_LIST_H 
#define __COMMAND_LIST_H 

typedef struct cnode { 
    uint8_t command; 
    struct cnode * next; 
} Cnode; 

typedef struct clist { 
    Cnode * head; 
} Clist; 

void push_cback(Clist * list, uint8_t command); 
void push_cfront(Clist * list, uint8_t command); 
void free_clist(Clist * list); 

#endif 

command_list.с

void push_cfront(Clist * list, uint8_t command){ 
    Cnode * new_node; 
    new_node = malloc(sizeof(Cnode)); 
    if (new_node->next == NULL) { 
     return; 
    } 
    new_node->command = command; 
    new_node->next = list->head; 
    list->head = new_node; 
} 

void free_clist(Clist * list){ 
    if (list->head == NULL){ 
     return; //already empty 
    } 
    Cnode * current = list->head; 
    while (current->next != NULL){ 
     Cnode* temp = current->next; 
     free(current); 
     current = temp; 
    } 
    free(current); 
    list->head = NULL; 
} 
+3

На третьей строке '' push_cfront вы 'если (new_node-> следующая == NULL)' вы просто 'malloc'ed эту вещь; 'next' не установлен. Довольно уверен, что вы хотели использовать 'if (new_node == NULL)'. – WhozCraig

+1

О, и реквизит для использования Valgrind. – WhozCraig

+0

Я думаю, что вы должны проверить 'list == NULL', на всякий случай :) – niceman

ответ

0

У вас есть несколько проблем. Вы проверяете new_node->next (неинициализированные данные в памяти malloc'd) вместо new_node (возвращаемое значение malloc). На моем компьютере, по крайней мере, это также заставляет память не освобождаться, потому что случайно new_node->next имеет значение null, поэтому вы возвращаетесь без освобождения new_node. Кроме того, если вы хотите поддерживать нажатие на спину связанного списка, вам следует рассмотреть список, связанный с круговым соединением, потому что он позволяет эту операцию без необходимости проходить все это.

Наконец, несколько советов: хорошо, что вы используете valgrind, но будет полезно, если вы скомпилируете с -g, чтобы включить отладочные символы, чтобы valgrind расскажет вам номера строк. Кроме того, когда я создаю связанные списки, мне нравится использовать фиктивный головной узел для некоторых операций, чтобы избежать специального случая для пустых или одиночных списков. Для вставки в отсортированном связанного списка, эта техника выглядит следующим образом:

int sorted_insert(Clist *list, char new_command){ 
    Cnode _head = {NULL, list->head}, *head = &_head, *prev = head, *tmp;//head is an auto dummy node obviating null checks. 
    int ord = -1;//If there are no existing nodes, newObj would be less than all objects. 
    while(prev->next && (ord = (int)newObj - prev->next->command)) > 0){//Iterate by prev->next not curr to use only one pointer. 
     prev = prev->next;//Looping while there is a next node and its data compares less than new_command. 
    } 
    if((!ord) || !(tmp = malloc(sizeof(Cnode))){//newObj is already in the list or allocation failed. 
     return 0; 
    } 
    *tmp = (Cnode){.next=prev->next, .command=new_command}; 
    prev->next = tmp; 
    list->head = head->next;//un- add head which is then deallocated by stack frame cleanup. 
    return 1; 
} 
+0

Спасибо. Это сделало более ясным, почему иногда я терял некоторые блоки, а иногда и нет. На самом деле я скомпилировал программу с -g, а также использовал valgrind с этой командой valgrind --leak-check = full --track-originins = yes – lugges

0

new_node->next не инициализируется, когда вы проверяете его значение. Тебе это не нужно.

Если вы ищете ошибки malloc, установите код возврата для функции и проверьте ее при вызове.

До этого if ответвление в push_cfront не требуется.

... или вы хотели проверить вместо этого list->head?

0

Кроме того, есть проблема с этим куском кода в push_cfront

new_node = malloc(sizeof(Cnode)); 
if (new_node->next == NULL) { 
    return; 
} 

Это неопределенное поведение, поскольку new_node памяти не отформатирована. Вероятно, вам нужно было проверить if (new_node == NULL), чтобы узнать, действительно ли выделено память.

+0

Хорошо, спасибо всем за то, что указали на проблему с проверкой new_node-> next. Я не вижу проблемы с моим свободным методом. Я освободил оставшийся узел после цикла while. На самом деле, я думаю, вы пытаетесь освободить нуль в свой метод free_clist(). Или я ошибаюсь? – lugges

+0

@ lugges oh, вы правы. Пропущенный бесплатный (текущий), будет выглядеть более подробно, я сейчас удалю часть о free_clist из ответа – buld0zzr