2014-07-29 5 views
1

Я делаю урок из Learn C the Hard way онлайн-курс. В примере кода ниже я не понимаю, почему нужны два вызова free(). Я думал, что нужно только позвонить free() один раз, потому что наступает только один malloc(). Может кто-нибудь уточнить, почему нам нужны два?C - Свободная память после strdup()

Если я прокомментирую free(who->name);, тогда valgrind сообщает мне, что я потерял память о памяти;

LEAK SUMMARY: 
definitely lost: 21 bytes in 2 blocks 

Вот код:

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

struct Person { 
    char *name; 
    int age; 
    int height; 
    int weight; 
}; 

struct Person *Person_create(char *name, int age, int height, int weight) 
{ 
    struct Person *who = malloc(sizeof(struct Person)); 
    assert(who != NULL); 

    who->name = strdup(name); 
    who->age = age; 
    who->height = height; 
    who->weight = weight; 

    return who; 
} 

void Person_destroy(struct Person *who) 
{ 
    assert(who != NULL); 

    free(who->name); /* Why this one??! */ 
    free(who); 
} 

int main(int argc, char *argv[]) 
{ 
    // make two people structures 
    struct Person *joe = Person_create(
      "Joe Alex", 32, 64, 140); 

    struct Person *frank = Person_create(
      "Frank Blank", 20, 72, 180); 

    // destroy them both so we clean up 
    Person_destroy(joe); 
    Person_destroy(frank); 

    return 0; 
} 
+1

Поскольку также strdup() выделяет память, тогда он должен быть освобожден (см. [Doc] (http://man7.org/linux/man-pages/man3/strdup.3.html)). –

+0

'who-> name = strdup (name);' здесь вы выделяете память, то есть strdup() выделяет. –

+1

'strdup' является маскировкой' malloc'. – AnT

ответ

9

strdup(3) является документально в

The strdup() function returns a pointer to a new string which is a 
    duplicate of the string s. Memory for the new string is obtained 
    with malloc(3), and can be freed with free(3). 

BTW, так как Matt McNabb прокомментировал strdup является стандартом в Posix, п ot в спецификации языка C99.

Конечно free освобождает только зону памяти, которую вы передаете (она не волшебным и косвенным образом не освобождает зону, указанную внутри зоны памяти, которую вы передаете). Опять же, free(3) говорит:

The free() function frees the memory space pointed to by ptr, which 
    must have been returned by a previous call to malloc(), calloc() or 
    realloc(). Otherwise, or if free(ptr) has already been called 
    before, undefined behavior occurs. If ptr is NULL, no operation is 
    performed. 

Читайте больше о C dynamic memory allocation. Если вам это не нравится, узнайте о garbage collection. С помощью C на Linux и некоторых других системах вы можете использовать Boehm's conservative garbage collector. Затем вы используете GC_MALLOC и/или GC_MALLOC_ATOMIC вместо malloc и GC_STRDUP вместо strdup, и вы не будете беспокоиться о free (иногда вы можете использовать GC_FREE, если хотите). Я считаю это очень полезным, но у него есть некоторые недостатки (немного медленнее, чем malloc, и нет явной гарантии о выпуске памяти ...).

Читайте о memory corruption и memory leaks

Кстати, вы должны сначала скомпилировать программу со всеми предупреждениями и отладочной информации (например, gcc -Wall -g). Затем вы можете использовать свой отладчик (gdb), установить точку останова в malloc после того, как main было достигнуто, и увидите, когда вызывается malloc. Вы увидите, что strdup звонит malloc ....


FYI, на Linux, malloc реализуется с помощью mmap(2) -and иногда старых sbrk(2) - системных вызовов -в получить «большие» области памяти (несколько килобайта или даже мегабайты), и free иногда может звонить munmap(2) - для этих больших регионов - но чаще всего он просто отмечает освобожденный блок как многоразовый, так что блок может быть повторно использован в некотором будущем звонков на malloc. Следовательно, программа, выполняющая malloc и free, может не выпускать все ранее использованные данные в ядро. См. Также this question about memory fragmentation.

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