bonjour,

petite question sur la libération de mémoire allouée dynamiquement.

Le code suivant ne me donne aucune erreur sous valgrind et s'exécute correctement.

Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
#include <stdio.h>
#include <stdlib.h>
 
const int SIZE = 10;
const int NEW_SIZE = 20;
 
enum errors {
    OUT_OF_MEMORY = 1
};
 
typedef struct {
    int number;
    char* street;
    int zip_code;
    char* city;
    char* country;
} address_t;
 
typedef struct {
    char* first_name;
    char* last_name;
    address_t* address;
} person_t;
 
int out_of_memory() {
    perror("out of memory\n");
    return OUT_OF_MEMORY;
}
 
void print_address(address_t* address) {
    printf("Address:\n");
    printf("Number: %d\n", address->number);
    printf("Street: %s\n", address->street);
    printf("Zip Code: %d\n", address->zip_code);
    printf("City: %s\n", address->city);
    printf("Country: %s\n", address->country);
}
 
void print_someone(person_t* person) {
    printf("Person:\n");
    printf("First Name: %s\n", person->first_name);
    printf("Last Name: %s\n", person->last_name);
    print_address(person->address);
}
 
int create_someone() {
    address_t* address = calloc(1, sizeof(address_t));
    if (address == NULL) {
        return out_of_memory();
    }
    address->number = 1;
    address->street = "boulevard of broken dreams";
    address->zip_code = 55555;
    address->city = "New York";
    address->country = "USA";
 
    person_t* person = calloc(1, sizeof(person_t));
    if (person == NULL) {
        return out_of_memory();
    }
    person->first_name = "John";
    person->last_name = "Doe";
    person->address = address;
    print_someone(person);
    free(address);
    free(person);
    return 0;
}
 
int main(void) {
    int return_code;
    printf("hello, world\n");
    int a[SIZE];
    a[0] = 1;
    int *b, *c;
    b = malloc(SIZE * sizeof(int));
    if (b == NULL) {
        return out_of_memory();
    }
    c = calloc(SIZE, sizeof(int));
    if (c == NULL) {
        return out_of_memory();
    }
    b[0] = 1;
    c[0] = 1;
    int i;
    for (i = 0; i < SIZE; ++i) {
        printf("%d ", c[i]);
    }
    printf("\n");
    c = realloc(c, NEW_SIZE * sizeof(int));
    // TODO ckeck that realloc actually allocated new memory for larger sizes
    for (i = 0; i < NEW_SIZE - SIZE; ++i) {
        c[i+NEW_SIZE-SIZE] = 1;
    }
    for (i = 0; i < NEW_SIZE; ++i) {
        printf("%d ", c[i]);
    }
    printf("\n");
    free(b);
    free(c);
 
    return_code = create_someone();
    if (!return_code) {
        return return_code;
    }
    printf("bye bye, world\n");
    return 0;
}
en revanche, dans le main, si j'invoque la fonction create_someone() avant les free(b) et free(c) :

Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
    return_code = create_someone();
    if (!return_code) {
        return return_code;
    }
    free(b);
    free(c);
    printf("bye bye, world\n");
j'ai des fuites mémoires détectées par valgrind :

$ valgrind --leak-check=yes ./testc
==31751== Memcheck, a memory error detector.
==31751== Copyright (C) 2002-2006, and GNU GPL'd, by Julian Seward et al.
==31751== Using LibVEX rev 1658, a library for dynamic binary translation.
==31751== Copyright (C) 2004-2006, and GNU GPL'd, by OpenWorks LLP.
==31751== Using valgrind-3.2.1-Debian, a dynamic binary instrumentation framework.
==31751== Copyright (C) 2000-2006, and GNU GPL'd, by Julian Seward et al.
==31751== For more details, rerun with: -v
==31751==
hello, world
1 0 0 0 0 0 0 0 0 0
1 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1
Person:
First Name: John
Last Name: Doe
Address:
Number: 1
Street: boulevard of broken dreams
Zip Code: 55555
City: New York
Country: USA
==31751==
==31751== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 11 from 1)
==31751== malloc/free: in use at exit: 120 bytes in 2 blocks.
==31751== malloc/free: 5 allocs, 3 frees, 192 bytes allocated.
==31751== For counts of detected errors, rerun with: -v
==31751== searching for pointers to 2 not-freed blocks.
==31751== checked 59,624 bytes.
==31751==
==31751== 40 bytes in 1 blocks are definitely lost in loss record 1 of 2
==31751== at 0x401D38B: malloc (vg_replace_malloc.c:149)
==31751== by 0x80486E8: main (main.c:76)
==31751==
==31751==
==31751== 80 bytes in 1 blocks are definitely lost in loss record 2 of 2
==31751== at 0x401D487: realloc (vg_replace_malloc.c:306)
==31751== by 0x804878F: main (main.c:91)
==31751==
==31751== LEAK SUMMARY:
==31751== definitely lost: 120 bytes in 2 blocks.
==31751== possibly lost: 0 bytes in 0 blocks.
==31751== still reachable: 0 bytes in 0 blocks.
==31751== suppressed: 0 bytes in 0 blocks.
==31751== Reachable blocks (those to which a pointer was found) are not shown.
==31751== To see them, rerun with: --show-reachable=yes
Je suppose que c'est normal, mais je ne comprends pas pourquoi la libération de cette mémoire ne peut pas se faire après l'appel à cette méthode. Il y a effectivement d'autres opérations d'allocation de mémoire dans cette méthode, mais j'ai également essayé en ne mettant qu'un printf dans la fonction create_someone(), et le problème est le même.

J'imagine qu'il y a peut-être des opérations effectuées automatiquement sur le tas lors de l'invocation d'une fonction qui feraient que la libération ne soit plus possible après l'invocation de cette fonction, mais je ne sais pas quoi exactement. Et du coup je ne trouve pas ça super pratique de devoir libérér la mémoire avant d'invoquer n'importe quelle fonction à l'intérieure d'une autre...

Enfin voilà, c'est probablement un problème de base, mais bon...