web-dev-qa-db-fra.com

Retourner un pointeur struct

Supposons que j'ai la structure et la fonction suivantes retournant un pointeur:

typedef struct {
  int num;
  void *nums;
  int size;
} Mystruct;

Mystruct *mystruct(int num, int size)
{ 
   //Is the following correct? Is there a more efficient way?
   Mystruct mystruct;
   mystruct.num = num;
   mystruct.size = size;
   mystruct.nums = malloc(num*sizeof(size));
   Mystruct *my;
   *my = mystruct;
   return my;
}

Je veux définir n'importe quel pointeur Mystruct en utilisant la fonction ci-dessus. Dois-je déclarer une variable Mystruct, définir les propriétés de Mystruct, lui affecter un pointeur et renvoyer le pointeur ou définir immédiatement les propriétés d'une propriété mystruct via un pointeur?

25
idealistikz

Dois-je déclarer une variable Mystruct, définir les propriétés de Mystruct, lui affecter un pointeur et renvoyer le pointeur

Certainement pas, car la variable définie dans la fonction (dans la classe de stockage "auto") disparaîtra à la fin de la fonction et vous renverrez un pointeur suspendu.

Vous pouvez accepter un pointeur vers un Mystruct (la responsabilité de l'appelant d'allouer cela) et le remplir; ou, vous pouvez utiliser malloc pour en créer un nouveau (la responsabilité de l'appelant de le libérer quand c'est fait). La deuxième option vous permet au moins de conserver la signature de fonction que vous semblez aimer:

Mystruct *mystruct(int num, int size)
{
   Mystruct *p = malloc(sizeof(MyStruct));
   ....
   return p;
}

mais elle est souvent inférieure - puisque l'appelant doit avoir des responsabilités de toute façon, peut aussi bien aller avec la première option et potentiellement gagner en performances (si l'appelant peut utiliser une instance de classe automatique parce qu'il sait que le champ d'utilisation est limité) .

37
Alex Martelli

Vous ne pouvez pas utiliser la variable car elle sera désallouée à la fermeture de la fonction. Par exemple:

Mystruct *mystruct(int num, int size)
{
   MyStruct x;
   x.num = 1;
   ...
   return &x;
}

Donnera une erreur de segmentation ou une violation d'accès car la mémoire de x est désallouée dès que vous quittez. Vous devez donc allouer de la mémoire pour la structure (et assurez-vous de la libérer plus tard) ou déclarer un global qui restera pour toujours. Exemple pour ce dernier ...

Mystruct *mystruct(int num, int size)
{
   MyStruct *x;
   x = (MyStruct*)malloc( sizeof( MyStruct ) );
   x->num = 1;
   ...
   return x;
}
7
staticman

Si vous écrivez du code générique et que vous ne savez pas comment l'utiliser, il est bon de proposer les deux options:

int mystructm(Mystruct *storage, int num, int size)
{
    int rv = 0;

    storage->num = num;
    storage->size = size;
    storage->nums = malloc(num*sizeof(size));
    if (!storage->nums)
        return -1;

    return 0;
}

Mystruct *mystruct(int num, int size)
{
    Mystruct *mp = (Mystruct *)malloc(sizeof(Mystruct));
    if (mp)
    {
        if (mystructm(mp, num, size) == -1)
        {
            free(mp);
            mp = NULL;
        }
    }

    return mp;
}

L'idée est qu'en tant que rédacteur de bibliothèque, vous ne devez pas dicter la politique (telle que chaque Mystruct doit être alloué dynamiquement), mais laisser le rédacteur d'application décider de cela.

3
R Samuel Klatchko

Allouer un nouveau Mystruct et y retourner un pointeur ressemblerait généralement plus ou moins à ceci:

Mystruct *mystruct(int num, int size)
{
   Mystruct *result;

   result = malloc(sizeof(MyStruct));
   if (!result)
     return NULL;

   result->num = num;
   ...

   return result;
}

Plus tard, lorsque vous aurez terminé avec le Mystruct alloué ici avec malloc, il devrait être à nouveau libéré avec free().

Le simple fait de déclarer une variable locale et de renvoyer un pointeur sur cette variable locale ne fonctionnera pas. La variable locale est hors de portée à la fin de la fonction et la mémoire où elle a été stockée est très probablement réutilisée à d'autres fins. Le pointeur renvoyé pointera toujours vers l'emplacement de mémoire où se trouvait autrefois la variable locale, mais comme cette variable n'existe plus, ce pointeur ne serait pas très utile.

2
sth

Il est important de se rappeler que le pointeur n'est pas quelque chose que vous attribuez à la structure, mais plutôt le pointeur indique l'emplacement en mémoire que vous souhaitez traiter comme une structure. Sur la base de votre question, vous souhaitez vraiment allouer la mémoire pour contenir la structure de données. Cela vous donne un pointeur sur l'emplacement mémoire alloué. Une fois que vous l'avez, vous pouvez le retourner.


MODIFIER (après avoir modifié la question d'origine) En regardant votre modification de la question, vous aurez certainement des problèmes avec le pointeur "mon". Ceci n'est pas initialisé et peut pointer n'importe où dans la mémoire. Lorsque vous essayez de copier la structure, vous obtiendrez probablement un défaut de segmentation.

2
graza

Une autre façon de le faire ..

int mystruct(Mystruct *mystruct, int num, int size){
   if(mystruct == NULL)
      return -1;

   mystruct->num = num;
   mystruct->size = size;
   ::
   return 0;
}

int main(){
   Mystruct my;

   if(mystruct(&my, 3, 4) != 0){
      fprintf(stderr, "Cannot init!\n");
      exit(0);
   }
   ::
}
2
N 1.1