101 votes

malloc pour les structures et les pointeurs en C

Supposons que je veuille définir une structure représentant la longueur du vecteur et ses valeurs comme :

struct Vector{
    double* x;
    int n;
};

Maintenant, supposons que je veuille définir un vecteur y et lui allouer de la mémoire.

struct Vector *y = (struct Vector*)malloc(sizeof(struct Vector));

Mes recherches sur Internet montrent que je dois allouer la mémoire pour x séparément.

y->x = (double*)malloc(10*sizeof(double));

Mais, il semble que j'alloue la mémoire pour y->x deux fois, l'une pendant l'allocation de la mémoire pour y et l'autre pendant l'allocation de la mémoire pour y->x, et cela semble un gaspillage de mémoire. J'apprécierais beaucoup que vous me fassiez savoir ce que le compilateur fait réellement et quelle serait la bonne façon de procéder. initialiser à la fois y et y->x.

Merci d'avance.

182voto

paxdiablo Points 341644

Non, tu es no l'allocation de la mémoire pour y->x deux fois.

Au lieu de cela, vous allouez de la mémoire pour la structure (qui inclut un pointeur) plus quelque chose vers lequel ce pointeur doit pointer.

Pensez-y de cette façon :

         1          2
        +-----+    +------+
y------>|  x------>|  *x  |
        |  n  |    +------+
        +-----+

Vous avez donc besoin des deux allocations ( 1 y 2 ) pour tout stocker.

En outre, votre type doit être struct Vector *y puisqu'il s'agit d'un pointeur, et vous ne devriez jamais transférer la valeur de retour de malloc en C, car il peut cacher certains problèmes que vous ne voulez pas voir cachés - le C est parfaitement capable de convertir implicitement l'adresse IP de l'utilisateur en une adresse IP. void* la valeur de retour à tout autre pointeur.

Et, bien sûr, vous souhaitez probablement encapsuler la création de ces vecteurs pour en faciliter la gestion, comme avec :

struct Vector {
    double *data;    // no place for x and n in readable code :-)
    size_t size;
};

struct Vector *newVector (size_t sz) {
    // Try to allocate vector structure.

    struct Vector *retVal = malloc (sizeof (struct Vector));
    if (retVal == NULL)
        return NULL;

    // Try to allocate vector data, free structure if fail.

    retVal->data = malloc (sz * sizeof (double));
    if (retVal->data == NULL) {
        free (retVal);
        return NULL;
    }

    // Set size and return.

    retVal->size = sz;
    return retVal;
}

void delVector (struct Vector *vector) {
    // Can safely assume vector is NULL or fully built.

    if (vector != NULL) {
        free (vector->data);
        free (vector);
    }
}

En encapsulant la création de cette manière, vous vous assurez que les vecteurs sont soit entièrement construits, soit pas construits du tout - il n'y a aucune chance qu'ils soient à moitié construits. Cela vous permet également de modifier totalement les structures de données sous-jacentes à l'avenir sans affecter les clients (par exemple, si vous vouliez en faire des tableaux épars pour troquer l'espace contre la vitesse).

5voto

Karthik T Points 19418

La première fois, vous allouez de la mémoire pour les éléments suivants Vector ce qui signifie que les variables x , n .

Cependant x n'indique pas encore quelque chose d'utile .

C'est pourquoi une deuxième allocation est également nécessaire .

4voto

Wernsey Points 3227

En principe, vous le faites déjà correctement. Pour ce que vous voulez, vous avez besoin de deux malloc() s.

Juste quelques commentaires :

struct Vector y = (struct Vector*)malloc(sizeof(struct Vector));
y->x = (double*)malloc(10*sizeof(double));

devrait être

struct Vector *y = malloc(sizeof *y); /* Note the pointer */
y->x = calloc(10, sizeof *y->x);

Dans la première ligne, vous allouez de la mémoire pour un objet Vector. malloc() renvoie un pointeur vers la mémoire allouée, donc y doit être un pointeur de vecteur. Dans la deuxième ligne, vous allouez de la mémoire pour un tableau de 10 doubles.

En C, vous n'avez pas besoin des casts explicites, et l'écriture de sizeof *y au lieu de sizeof(struct Vector) est meilleur pour la sécurité des types, et en plus, il permet d'économiser sur la saisie.

Vous pouvez réorganiser votre structure et faire un seul malloc() comme ça :

struct Vector{    
    int n;
    double x[];
};
struct Vector *y = malloc(sizeof *y + 10 * sizeof(double));

3voto

rajneesh Points 971

Quelques points

struct Vector y = (struct Vector*)malloc(sizeof(struct Vector)); c'est faux

il devrait l'être struct Vector *y = (struct Vector*)malloc(sizeof(struct Vector)); depuis y détient le pointeur sur struct Vector .

1er malloc() alloue seulement assez de mémoire pour contenir la structure Vector (qui est un pointeur sur double + int)

2ème malloc() allouer réellement de la mémoire pour contenir 10 doubles.

1voto

Andremoniy Points 7349

Lorsque vous allouez de la mémoire pour struct Vector vous allouez simplement de la mémoire pour le pointeur x c'est-à-dire pour l'espace, où sa valeur, qui contient l'adresse, sera placée. De cette façon, vous n'allouez pas de mémoire pour le bloc, sur lequel la valeur de y.x fera référence.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X