IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

 C Discussion :

Passage de tableau de pointeur par reference


Sujet :

C

  1. #1
    Membre éclairé
    Profil pro
    Ingénieur sécurité
    Inscrit en
    Février 2007
    Messages
    574
    Détails du profil
    Informations personnelles :
    Âge : 39
    Localisation : Etats-Unis

    Informations professionnelles :
    Activité : Ingénieur sécurité
    Secteur : Industrie

    Informations forums :
    Inscription : Février 2007
    Messages : 574
    Points : 751
    Points
    751
    Par défaut Passage de tableau de pointeur par reference
    Bonjour a tous pour mon premier post sur le forum C.

    Je me suis mis au C y'a tres peu de temps, et j'avoue que je galere avec les passages d'arguments par reference.
    J'ai fait une fonction toute simple qui decoupe une chaine de longueur indefinie en un tableau, et qui renvoie ce tableau, ainsi que sa longueur.
    J'arrive a renvoyer le tableau de pointeurs, mais pas a le renvoyer par reference:
    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
     
    int strarr(char *string, char *sep, char ***strarray)
    {
      int nbElem = 0;
      char *token = NULL, *saveptr = NULL, *copy = strdup(string);
      for (token = strtok_r(copy, sep, &saveptr); token != NULL; token = strtok_r(NULL, sep, &saveptr))
      {
        char **success = NULL;
        if ((success = (char **)realloc(*strarray, (nbElem + 1) * sizeof(char *))) == NULL)
          return -1;
        *strarray = success;
        *strarray[nbElem++] = strdup(token);
      }
      free(copy);
      return nbElem;
    }
    Le code de l'appellant est le suivant:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
     
    char **strarray = NULL;
    int nbValues = strarr("/abc/def/ghi/klmn", "/", &strarray);
    int i = 0;
    for (i = 0; i < nbValues; i++)
      printf("%s\n", strarray[i]);
    [/CODE]

    Mon code fonctionne correctement si je renvoie le pointeur par return, mais bon, ce n'est pas ce que je veux:
    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
     
    char **strarr(char *string, char *sep)
    {
      int nbElem = 0;
      char *token = NULL, *saveptr = NULL, *copy = strdup(string);
      char **strarray = NULL;
      for (token = strtok_r(copy, sep, &saveptr); token != NULL; token = strtok_r(NULL, sep, &saveptr))
      {
        char **success = NULL;
        if ((success = (char **)realloc(strarray, (nbElem + 1) * sizeof(char *))) == NULL)
          return -1;
        strarray = success;
        strarray[nbElem++] = strdup(token);
      }
      free(copy);
      return strarray;
    }
    Dans gdb, je vois que le SIGSEV est leve sur l'instruction suivante *strarray[nbElem++] = strdup(token);, mais je n'arrice pas a comprendre pourquoi.

    Autres petites questions annexes:
    1. pourquoi est-ce que le passage par reference necessite un niveau d'indirection supplementaire?
    2. Ici, je laisse la responsabilite a l'appellant de liberer le tableau retourne ainsi que ses elements. Quelles sont les bonnes pratiques dans ce cas?


    Merci beaucoup.

  2. #2
    Expert éminent sénior
    Avatar de diogene
    Homme Profil pro
    Enseignant Chercheur
    Inscrit en
    Juin 2005
    Messages
    5 761
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Enseignant Chercheur
    Secteur : Enseignement

    Informations forums :
    Inscription : Juin 2005
    Messages : 5 761
    Points : 13 926
    Points
    13 926
    Par défaut
    Attention à la priorité des opérateurs :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    (*strarray)[nbElem++] = strdup(token);
    pourquoi est-ce que le passage par reference necessite un niveau d'indirection supplementaire?
    Le passage de paramètres en C est toujours un passage par copie : une variable locale du type spécifiée est créée et initialisée par la valeur passée en argument. La fonction travaille sur cette copie. Si on veut, dans une fonction, accéder à un objet extérieur (et non global), il faut donc passer son adresse (en fait une copie de l'adresse) pour que la fonction sachant où se trouve l'objet puisse y accéder.

    Ici, je laisse la responsabilite a l'appellant de liberer le tableau retourne ainsi que ses elements. Quelles sont les bonnes pratiques dans ce cas?
    On aime bien que si l'objet est créé dans une fonction, cette fonction le libère également, mais ce n'est pas toujours possible.
    Cela dépend également du point de vue adopté sur qui crée l'objet :
    Dans ton cas, on peut considérer que c'est la fonction qui appelle strarr() qui crée le tableau de pointeurs et les chaines de caractères. Tu peux d'ailleurs choisir le nom de la fonction strarr() pour bien exprimer cette création et la nécessité de la détruire. Il est alors de bon ton que la fonction qui appelle strarr() effectue également les libérations. D'ailleurs, tu as intérêt à créer une fonction pour cela.
    Par exemple :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    ....Fonc(....)
    {
     char **strarray = NULL;
     int nbValues = newStrarr("/abc/def/ghi/klmn", "/", &strarray);
    ....
     deleteStrarr(strarray );
    }
    Publication : Concepts en C

    Mon avatar : Glenn Gould

    --------------------------------------------------------------------------
    Une réponse vous a été utile ? Remerciez son auteur en cliquant le pouce vert !

  3. #3
    Membre éclairé
    Profil pro
    Ingénieur sécurité
    Inscrit en
    Février 2007
    Messages
    574
    Détails du profil
    Informations personnelles :
    Âge : 39
    Localisation : Etats-Unis

    Informations professionnelles :
    Activité : Ingénieur sécurité
    Secteur : Industrie

    Informations forums :
    Inscription : Février 2007
    Messages : 574
    Points : 751
    Points
    751
    Par défaut
    Citation Envoyé par diogene Voir le message
    Attention à la priorité des opérateurs :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    (*strarray)[nbElem++] = strdup(token);
    Ah ok, j'ecrivais non pas dans le tableau, mais a la valeur pointee par l'element du tableau.
    Citation Envoyé par diogene Voir le message
    Le passage de paramètres en C est toujours un passage par copie : une variable locale du type spécifiée est créée et initialisée par la valeur passée en argument. La fonction travaille sur cette copie. Si on veut, dans une fonction, accéder à un objet extérieur (et non global), il faut donc passer son adresse (en fait une copie de l'adresse) pour que la fonction sachant où se trouve l'objet puisse y accéder.
    Merci, ca devient clair. D'ailleurs c'est peut etre moi, mais dans mes lectures je n'ai trouve nul part ou ce fait etait explique. Le fait que la fonction travaille sur cette copie explique effectivement le niveau d'indirection supplementaire.
    Citation Envoyé par diogene Voir le message
    On aime bien que si l'objet est créé dans une fonction, cette fonction le libère également, mais ce n'est pas toujours possible.
    Cela dépend également du point de vue adopté sur qui crée l'objet :
    Dans ton cas, on peut considérer que c'est la fonction qui appelle strarr() qui crée le tableau de pointeurs et les chaines de caractères. Tu peux d'ailleurs choisir le nom de la fonction strarr() pour bien exprimer cette création et la nécessité de la détruire. Il est alors de bon ton que la fonction qui appelle strarr() effectue également les libérations. D'ailleurs, tu as intérêt à créer une fonction pour cela.
    Oui, c'est ce que j'avais lu. Ca semble logique.

    Derniere question, dans la plupart des sources que j'ai regarde qui utlise realloc, la reallocation double la taille du tableau au besoin (je ne le fait pas ici par simplicite). Ceci implique que l'ajout de nouvelle donnee suit une fonction x^2, ce qui intuitivement ne me semble pas logique. Je m'attendrai plus a quelque chose de lineaire.
    Est-ce que ce doublement de capacite est purement empirique?

    Merci encore.

  4. #4
    Expert éminent sénior
    Avatar de diogene
    Homme Profil pro
    Enseignant Chercheur
    Inscrit en
    Juin 2005
    Messages
    5 761
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Enseignant Chercheur
    Secteur : Enseignement

    Informations forums :
    Inscription : Juin 2005
    Messages : 5 761
    Points : 13 926
    Points
    13 926
    Par défaut
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    ...Est-ce que ce doublement de capacite est purement empirique?
    La réallocation est une opération qui peut être coûteuse en terme de performances. Le but de ce genre de choses est de limiter le nombre de realloc(). Bien sûr, le choix de l'accroissement de la taille allouée dépend beaucoup de la situation à traiter et cette méthode ne peut être considérée comme une panacée (je crois d'ailleurs que plutôt qu'un facteur 2, un facteur voisin de 1.5 est d'ordinaire proposé).
    Publication : Concepts en C

    Mon avatar : Glenn Gould

    --------------------------------------------------------------------------
    Une réponse vous a été utile ? Remerciez son auteur en cliquant le pouce vert !

  5. #5
    Membre expert
    Avatar de Golgotha
    Homme Profil pro
    Full-stack Web Developer
    Inscrit en
    Août 2007
    Messages
    1 386
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Full-stack Web Developer
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Août 2007
    Messages : 1 386
    Points : 3 531
    Points
    3 531
    Billets dans le blog
    1
    Par défaut
    diogene

    J'ai passé un peux de temps à essayer de résoudre ce problème hier

    j'avais pas vu la priorité des opérateurs,
    Consultant et développeur full-stack spécialiste du Web
    faq jQuery - règles du forum - faqs web

  6. #6
    Membre éclairé
    Profil pro
    Ingénieur sécurité
    Inscrit en
    Février 2007
    Messages
    574
    Détails du profil
    Informations personnelles :
    Âge : 39
    Localisation : Etats-Unis

    Informations professionnelles :
    Activité : Ingénieur sécurité
    Secteur : Industrie

    Informations forums :
    Inscription : Février 2007
    Messages : 574
    Points : 751
    Points
    751
    Par défaut
    Une derniere question si c'est pas de trop, comment est-ce que vous auriez implemente cette methode? Utiliser la stack n'est pas possible dans un contexte dynamique comme ca je pense...
    Bref, si vous avez un peu de temps et d'envie, j'aimerai bien voir par curiosite des implementations ou idees de comment traiter ce probleme de tableau 2d dynamique.

    Merci de tes reponses diogene. Probleme resolu.

  7. #7
    Expert éminent sénior
    Avatar de Médinoc
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Septembre 2005
    Messages
    27 369
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 40
    Localisation : France

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2005
    Messages : 27 369
    Points : 41 519
    Points
    41 519
    Par défaut
    Généralement, j'agrandis un tableau dynamique en multipliant sa taille par 1.5 (ou par racine de 2 si je veux jouer au pédant).

    L'important est que le multiplicateur soit inférieur ou égal au nombre d'or, pour une raison dont j'ai oublié les détails.


    Une autre solution peut être d'utiliser une liste chaînée durant l'exécution de la fonction, puis transformer tout ça en un grand tableau. Avec les bons calculs, on peut même allouer toute la place nécessaire (tableau de pointeurs + chaînes) en une fois, bénéficiant ainsi d'une meilleure localité (et d'une libération plus facile, vu qu'un seul free() sera nécessaire).
    Bien sûr, tout regrouper n'est pratique que si l'on ne prévoit pas de modifier les chaînes par la suite.
    SVP, pas de questions techniques par MP. Surtout si je ne vous ai jamais parlé avant.

    "Aw, come on, who would be so stupid as to insert a cast to make an error go away without actually fixing the error?"
    Apparently everyone.
    -- Raymond Chen.
    Traduction obligatoire: "Oh, voyons, qui serait assez stupide pour mettre un cast pour faire disparaitre un message d'erreur sans vraiment corriger l'erreur?" - Apparemment, tout le monde. -- Raymond Chen.

  8. #8
    Membre chevronné
    Profil pro
    Inscrit en
    Août 2006
    Messages
    1 104
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Août 2006
    Messages : 1 104
    Points : 1 750
    Points
    1 750
    Par défaut
    Citation Envoyé par Médinoc Voir le message
    L'important est que le multiplicateur soit inférieur ou égal au nombre d'or, pour une raison dont j'ai oublié les détails.
    J'ai trouvé un PDF qui explique la chose : http://www.bourguet.org/realloc.pdf

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. Réponses: 5
    Dernier message: 27/03/2008, 14h32
  2. Passage de tableau de pointeurs vers objets
    Par gnulix dans le forum C++
    Réponses: 5
    Dernier message: 14/04/2007, 19h41
  3. Passage de tableau à une fonction par pointeur
    Par progfou dans le forum C++
    Réponses: 15
    Dernier message: 23/02/2007, 11h45
  4. [Tableaux] passage de tableau en parametre par l'url
    Par arnolpourri dans le forum Langage
    Réponses: 10
    Dernier message: 15/06/2006, 14h32
  5. Réponses: 8
    Dernier message: 10/03/2006, 17h28

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo