Dans un autre fils, j'ai posé un code proposant un schéma d'allocation de mémoire pour un type abstrait de donnée Matrix qui a suscité le débat sur le plan du respect des contraintes d'alignement (Version 3 ci-dessous). Je crée ici une nouvelle discussion pour ne pas polluer le thread initial. Si la version 1 du code ci-dessous est celle généralement proposée, la version 2 est probablement plus facile à gérer par un débutant (moins d'allocation, gestion des erreurs allégée). Du point de vue de la performance, pour des grosse matrices, y a-t-il un avantage à allouer la mémoire pour chaque ligne de la matrice comme dans la version 1, par rapport à une allocation en masse comme dans la version 2 (p.ex. moins de swap)? Ou inversemment?

Les trois versions proposées sont:

Version 1: (nlines + 2) allocations de mémoire:
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
struct Matrix
{
    double **_data;
    size_t dim[2];
};
#define MATRIX_INIT {NULL, {0}}
 
struct Matrix *m_matrix_new(size_t nlines, size_t ncols)
{
    struct Matrix *self = NULL;
 
    if (nlines > 0 && ncols > 0)
    {
        /* Hop, on change les habitudes et on alloue tout en un bloc */
        self = malloc(sizeof *self);
        if (self != NULL)
        {
            static const struct Matrix tmp = MATRIX_INIT;
            /* Initialisation de tous les champs de la structure a une valeur
               nulle */
            *self = tmp;
 
            self->dim[0] = nlines;
            self->dim[1] = ncols;
 
            self->_data = malloc(nlines * sizeof *self->_data);
            if (self->_data != NULL)
            {
                size_t i;
                size_t j;
                int err = 0;
 
                for (i = 0; i < nlines && err == 0; i++)
                {
                    self->_data[i] = malloc(ncols *sizeof *self->_data[i]);
                    if (self->_data[i] == NULL)
                    {
                        /* Echec d'allocation: on fait le menage, on sort de
                           la boucle et on renvoit la valeur NULL */
                        do
                        {
                            i--;
                            free(self->_data[i]);
                        }
                        while (i > 0);
 
                        free(self->_data);
                        free(self), self = NULL;
 
                        err = 1;
                    }
                }
 
                if (err == 0)
                {
                    /* Initialisation */
                    for (i = 0; i < nlines; i++)
                    {
                        for (j = 0; j < ncols; j++)
                        {
                            self->_data[i][j] = 0.0;
                        }
                    }
                }
            }
            else
            {
                /* Echec de l'allocation: on fait le menage et on renvoit la
                   valeur NULL */
                free(self), self = NULL;
            }
        }
        else
        {
            /* Echec de l'allocation de memoire pour self: rien a faire, on
               renvoit la valeur NULL. */
        }
    }
 
    return self;
}
 
struct Matrix * m_matrix_delete(struct Matrix *self)
{
    if (self != NULL)
    {
        size_t i;
 
        for (i = 0; i < self->dim[0]; i++)
        {
            free(self->_data[i]);
        }
        free(self->_data);
        free(self), self = NULL;
    }
 
    return self;
}
Version 2: 3 allocations de mémoire:
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
struct Matrix
{
    double **_data;
    size_t dim[2];
};
#define MATRIX_INIT {NULL, {0}}
 
struct Matrix *m_matrix_new(size_t nlines, size_t ncols)
{
    struct Matrix *self = NULL;
 
    if (nlines > 0 && ncols > 0)
    {
        /* Hop, on change les habitudes et on alloue tout en un bloc */
        self = malloc(sizeof *self);
        if (self != NULL)
        {
            static const struct Matrix tmp = MATRIX_INIT;
            /* Initialisation de tous les champs de la structure a une valeur
               nulle */
            *self = tmp;
 
            self->dim[0] = nlines;
            self->dim[1] = ncols;
 
            self->_data = malloc(nlines * sizeof *self->_data);
            if (self->_data != NULL)
            {
                self->_data[0] = malloc(nlines * ncols * sizeof *self->_data[0]);
                if (self->_data[0] != NULL)
                {
                    int i;
 
                    for (i = 1; i < nlines; i++)
                    {
                        self->_data[i] = self->_data[0] + i * ncols;
                    }
 
                    /* Initialization */
                    for (i = 0; i < nlines * ncols; i++)
                    {
                        self->_data[0][i] = 0.0;
                    }
                }
                else
                {
                    /* Echec de l'allocation de memoire: on fait le menage et on
                       renvoit la valeur NULL */
                    free(self->_data);
                    free(self), self = NULL;
                }
            }
            else
            {
                /* Echec de l'allocation: on fait le menage et on renvoit la
                   valeur NULL */
                free(self), self = NULL;
            }
        }
        else
        {
            /* Echec de l'allocation de memoire pour self: rien a faire, on
               renvoit la valeur NULL. */
        }
    }
 
    return self;
}
 
struct Matrix * m_matrix_delete(struct Matrix *self)
{
    if (self != NULL)
    {
        free(self->_data[0]);
        free(self->_data);
        free(self), self = NULL;
    }
 
    return self;
}
Version 3: 1 allocation de mémoire:
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
struct Matrix
{
    double **_data;
    size_t dim[2];
};
#define MATRIX_INIT {NULL, {0}}
 
struct Matrix *m_matrix_new(size_t nlines, size_t ncols)
{
    struct Matrix *self = NULL;
 
    if (nlines > 0 && ncols > 0)
    {
        /* Hop, on change les habitudes et on alloue tout en un bloc */
        self = malloc(sizeof *self + nlines * sizeof *self->_data +
                      nlines * ncols * sizeof **self->_data);
        if (self != NULL)
        {
            size_t i, j;
            static const struct Matrix tmp = MATRIX_INIT;
            /* Initialisation de tous les champs de la structure a une valeur
               nulle */
            *self = tmp;
 
            self->dim[0] = nlines;
            self->dim[1] = ncols;
 
            /* Mise en forme de l'objet pour que tout pointe ou il faut */
            self->_data = (double **) (self + 1);
            self->_data[0] = (double *) (self->_data + nlines);
 
 
            for (i = (size_t) 1; i < nlines; i++)
            {
                self->_data[i] = self->_data[0] + i * ncols;
 
            }
 
            /* Initialisation des elements de la matrice */
            for (i = (size_t) 0; i < nlines; i++)
            {
                for (j = (size_t) 0; j < ncols; j++)
                {
                    self->_data[i][j] = 0.0;
                }
            }
 
        }
    }
 
    return self;
}
 
void m_matrix_delete(struct Matrix *self)
{
    if (self != NULL)
    {
        free(self);
    }
}
Avec mes meilleures salutations

Thierry