2016-11-28 3 views
0

Я пытаюсь реализовать «мою» версию безопасного массива в C, и у меня есть проблема утечки памяти, когда я пытаюсь освободить мою структуру, которую я создал, и я не могу понять, проблема.Свободная память для struct corrupt heap

#include <stdio.h> 
#include <stdlib.h> 

typedef struct safe_array safe_array; 
struct safe_array 
{ 
    size_t size; 
    int * safe_array; 
}; 

void init_array(safe_array* safe_array, size_t size, int initial_value) 
{ 
    safe_array->safe_array = malloc(sizeof(int) * size); 
    for (size_t i = 0; i < size; i++) 
    { 
     safe_array->safe_array[i] = initial_value; 
    } 
    safe_array->size = size; 
} 

void free_array(safe_array* safe_array) 
{ 
    free(safe_array->safe_array); 
    free(safe_array); 
} 

int* access_array_element(safe_array* safe_array, size_t index) 
{ 
    int out_of_range = 0; 
    if (index >= safe_array->size) 
    { 
     return 0; 
    } 

    return &safe_array->safe_array[index]; 
} 

int main() 
{ 

    /*Create a safe_array and print its elements*/ 
    safe_array my_safe; 
    init_array(&my_safe, 5, 2); 
    for (size_t i = 0; i < my_safe.size; i++) 
    { 
     printf("Element %d is %d", i, *access_array_element(&my_safe, i)); 
    } 

    /*Free the safe_array*/ 
    free_array(&my_safe); 

    return 0; 
} 

Проблема возникает, когда я пытаюсь сделать free(safe_array), но я не понимаю, что именно происходит. Я не могу освободить его, потому что я никогда не выделял ему память, если это так, как я могу полностью освободить эту структуру?

Точное сообщение, которое я получаю, это Debug Assertion Failed со ссылкой на файл debug_heap.cpp.

Мне нужно уточнить, что я хочу иметь возможность освободить всю структуру не только от ее содержимого.

+0

Вы тщательно перепутали код, используя одно и то же имя дважды, начиная с 'typedef struct safe_array safe_array;'. Взгляните на функцию 'free_array', где каждый идентификатор является' safe_array'. Насколько безопасным может быть такое обфускация? –

+0

Правда, мой плохой, у меня не было много творчества на этом ... Тем не менее, у вас есть идея? –

+0

Uh .. 'unsafe_array'? Извините, если это кажется жестоким, но если вы не поняли, как использовать выделение памяти в C, вам не удастся написать более безопасную реализацию. –

ответ

2

Проблема заключается в том, что &my_safe представляет собой указатель на структуру выделено на стеке (объявив его в качестве локальной переменной), а не один выделяется в куче (с помощью malloc). Поэтому вы не можете позвонить free.

С init_array требуется, чтобы клиентский код уже присвоил структуру, free_array также должен требовать, чтобы клиентский код обрабатывал освобождение структуры после этого. Так же, как init_array только выделяет память для содержимого массива, free_array следует только освобождать память для содержимого массива:

void free_array(safe_array* safe_array) 
{ 
    free(safe_array->safe_array); 
} 
+0

Оба ответа хороши, однако этот вопрос более подробно. Тем не менее, обязательно прочитайте комментарии ниже ответа от immibis, они очень полезны! В основном, то, что я закончил, было 'safe_array_struct * my_safe = malloc (sizeof (safe_array_struct)) ;, а затем удалил' & 'to' my_safe' в вызове функций. –

2

Это правильно. Вы можете free вещей, которые были выделены malloc (или косвенно, как с strdup). Вы не можете free вещей, которые не были выделены с помощью malloc, а my_safe - это не то, что было выделено malloc.

+0

Тогда нужно ли мне что-то вроде 'my_safe = malloc (sizeof (safe_array))' сразу после создания 'my_safe', чтобы освободить его? –

+2

@YohanObadia: У вас есть дизайнерское решение. Значения 'safe_array_struct' выделяются в стеке или должны быть всегда выделены кучей? Если они могут быть выделены в стеке, вы не должны пытаться освободить 'safe_array_struct' в коде освобождения; вы только освобождаете данные массива, хранящиеся в структуре.Если вызывающий абонент динамически выделяет 'safe_array_struct', тогда их ответственность освобождает его. OTOH, если пользователи не могут выделять значения safe_array_struct, вам необходимо изменить интерфейс на функцию создания: 'safe_array_struct * init_array (size_t size, int init);'. –

+0

@YohanObadia 'my_safe = malloc (sizeof (safe_array))' не будет компилироваться, потому что 'my_safe' не является переменной указателя. – immibis

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