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

  1. #1
    Nouveau Candidat au Club
    Homme Profil pro
    Étudiant
    Inscrit en
    octobre 2019
    Messages
    1
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 20
    Localisation : France, Gironde (Aquitaine)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : octobre 2019
    Messages : 1
    Points : 1
    Points
    1
    Par défaut Fonction d'allocation d'un tableau dynamique dans une structure
    Bonjour,

    Voici un cas de débutant dont je ne trouve pas la bonne solution:
    Il me faut définir une fonction createArray prenant en paramètre un entier. La fonction allouera dynamiquement une variable de type dynIntArray ne contenant aucun élément mais pouvant stocker sans réallocation jusqu’à n entiers . La fonction renverra l'adresse de la zone mémoire nouvellement allouée.

    La struct est :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    typedef struct{
        int * tab;
        unsigned int capacity;
        unsigned int size;
    } dynIntArray;
    Ma fonction :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    dynIntArray* createArray(unsigned int capacity){
     
        if (capacity > 0) // Il faut qu'il ait au moins une case
        {
            dynIntArray dyn;
            dynIntArray* dyn =(dynIntArray*) malloc(sizeof(dynIntArray)); // On alloue de la mémoire pour le tableau
            dyn.tab = (int*) malloc(capacity * sizeof(int));
            return dyn ;
        }else{
            return 0;
     
        }
    }
    Je ne comprends pas comment à la fois allouer la mémoire pour le tab dynamique et pour la structure elle-même, cela me semble répétitif et je ne sais donc pas quoi vraiment retourner. Il doit me manquer une information.
    De même cela m'aidera pour créer une fonction qui elle libérera la mémoire allouée.

    Merci d'avance pour les âmes perdues qui m'aideront .

  2. #2
    Expert confirmé
    Avatar de gerald3d
    Homme Profil pro
    Conducteur de train
    Inscrit en
    février 2008
    Messages
    2 085
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 49
    Localisation : France, Côte d'Or (Bourgogne)

    Informations professionnelles :
    Activité : Conducteur de train
    Secteur : Transports

    Informations forums :
    Inscription : février 2008
    Messages : 2 085
    Points : 4 055
    Points
    4 055
    Billets dans le blog
    4
    Par défaut
    Bonjour.

    Tout d'abord, il faut essayer tant que faire ce peut d'avoir un code le plus concis possible, sans perdre pour autant la lisibilité de ce dernier.

    En partant de ce principe on peut déjà modifier ta fonction ainsi :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    dynIntArray* createArray(unsigned int capacity){
     
        if (capacity == 0) // Retourne NULL si le paramètre transmis n'est pas correcte.
          return NULL;
     
        dynIntArray dyn;
        dynIntArray* dyn =(dynIntArray*) malloc(sizeof(dynIntArray)); // On alloue de la mémoire pour le tableau
        dyn.tab = (int*) malloc(capacity * sizeof(int));
     
        return dyn ;
    }
    Tu vois déjà qu'on gagne en indentation et en nombre de lignes. La clarté du code reste encore très bonne.

    Pour ton souci, lorsque tu alloues il faut allouer la taille de la donnée X le nombre de données que tu désires mémoriser.
    Donc on aura plutôt :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    dynIntArray* createArray(unsigned int capacity){
     
        if (capacity == 0) // Retourne NULL si le paramètre transmis n'est pas correcte.
          return NULL;
    
        dynIntArray* dyn = malloc(sizeof(dynIntArray) * capacity); // On alloue de la mémoire pour le tableau
     
        return dyn ;
    }
    Comme tu peux le voir j'ai sérieusement simplifié ton code et ajouté la multiplication nécessaire. Ta fonction renverra NULL si l'allocation a causé une erreur ou si capacity=0. D'ailleurs on pourrait aussi supprimer le test de capacity puisque malloc(); renvoie NULL si on cherche à allouer 0 élément.
    Pour finir tu remarqueras que j'ai supprimé le cast de malloc();. En C il ne sert à rien.

    J'ai modifié ton code car je ne comprends pas cette histoire de structure. Ici tu as une allocation d'un tableau contenant capacity éléments de type dynIntArray. Si tu peux préciser un peu le but final de l'exercice...
    Utilisation de Glade avec Gtk+ - N'oubliez pas de consulter les FAQ Gtk et les cours et tutoriels Gtk

  3. #3
    Expert confirmé
    Homme Profil pro
    Ingénieur développement matériel électronique
    Inscrit en
    décembre 2015
    Messages
    989
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Ingénieur développement matériel électronique
    Secteur : High Tech - Électronique et micro-électronique

    Informations forums :
    Inscription : décembre 2015
    Messages : 989
    Points : 4 997
    Points
    4 997
    Par défaut
    Bonjour,

    On pourrait ne faire qu'une allocation en regroupant les 2 zones, mais si on veut agrandir la capacity ça ne marchera plus. Il faut donc conserver les 2 allocations, et il faut penser à bien tout initialiser :
    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
    dynIntArray* createArray( unsigned capacity ) {
        if ( capacity == 0u ) // Retourne NULL si le paramètre transmis n'est pas correct
          return  NULL;
     
        dynIntArray*  dyn = malloc( sizeof(*dyn) ); 
        dyn.tab = malloc( capacity * sizeof(int) );
        dyn.capacity = capacity;          // noter capacité
        dyn.size = 0u;                    // vide pour le moment
     
        return  dyn;
    }
     
    bool changeArrayCapacity( dynIntArray* pdyn , unsigned capacity ) {
        if ( capacity == 0u )
            return  false;                 // erreur paramètre
     
        int*  newTab = realloc( pdyn->tab , capacity * sizeof(int) );
        if ( newTab == NULL )
            return  false;                 // erreur mémoire
     
        pdyn->tab = newTab;
        pdyn->capacity = capacity;         // noter nouvelle capacité
        if ( pdyn->capacity < pdyn->size )
            pdyn->size = pdyn->capacity;   // a pu perdre des éléments
     
        return  true;
    }

  4. #4
    Modérateur

    Avatar de Bktero
    Homme Profil pro
    ...
    Inscrit en
    juin 2009
    Messages
    4 266
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 32
    Localisation : France, Loire Atlantique (Pays de la Loire)

    Informations professionnelles :
    Activité : ...

    Informations forums :
    Inscription : juin 2009
    Messages : 4 266
    Points : 12 689
    Points
    12 689
    Billets dans le blog
    1
    Par défaut
    C'est moi qui capte rien ou l'allocation d'un dynIntArray ne sert à rien ?

    Il suffit de créer une structure en local, allouer une zone d'entiers, mettre l'adresse dans la structure, renvoyer la structure par copie.

  5. #5
    Membre chevronné
    Avatar de sambia39
    Homme Profil pro
    No Comment
    Inscrit en
    mai 2010
    Messages
    481
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Loiret (Centre)

    Informations professionnelles :
    Activité : No Comment
    Secteur : High Tech - Matériel informatique

    Informations forums :
    Inscription : mai 2010
    Messages : 481
    Points : 1 773
    Points
    1 773
    Par défaut
    Bonjour,
    Je suis d'avis avec @Bktero sur le fait que l'on peut tout simplement avoir une seule fonction qui se charge d'allouer la mémoire nécessaire pour tab et donc pas besoin de consommer davantage de mémoire.

    De plus, si l'on veut optimiser les choses, on peut très bien écrire comme dans l'exemple ci-dessous l'allocation de mémoire et donc même si l'on fournie une valeur du genre 0 ou -1. malloc va tous naturellement renvoyer soit NULL ou un pointeur "invalide qui peut être utilisé avec free".

    Code C : 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
     
    int *get_capacity( size_t size ){
        int *dt = NULL;
        return ( (NULL == (dt = malloc(size * sizeof *dt)) ) ? NULL : dt ); 
    }
     
     
    int main(void) {
        dynIntArray dt;
        if( NULL == (dt.tab = get_capacity(0)) ){
            (void)fprintf(stderr, "Error allocation");
            abort();    //crash si -1
        }
        /*
        *   utilisation 
        */
        /* -- snip --*/
     
        free(dt.tab);
        dt.tab = NULL;
        return EXIT_SUCCESS;
    }

    À bientôt,
    Celui qui peut, agit. Celui qui ne peut pas, enseigne.
    Il y a deux sortes de savants: les spécialistes, qui connaissent tout sur rien,
    et les philosophes, qui ne connaissent rien sur tout.
    George Bernard Shaw

  6. #6
    Expert éminent sénior
    Avatar de Sve@r
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    février 2006
    Messages
    7 486
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Oise (Picardie)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : février 2006
    Messages : 7 486
    Points : 21 313
    Points
    21 313
    Billets dans le blog
    1
    Par défaut
    Bonjour
    Citation Envoyé par KaKou87 Voir le message
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    typedef struct{
        int * tab;
        unsigned int capacity;
        unsigned int size;
    } dynIntArray;
    Ma fonction :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    dynIntArray* createArray(unsigned int capacity){
     
        if (capacity > 0) // Il faut qu'il ait au moins une case
        {
            dynIntArray dyn;
            dynIntArray* dyn =(dynIntArray*) malloc(sizeof(dynIntArray)); // On alloue de la mémoire pour le tableau
            dyn.tab = (int*) malloc(capacity * sizeof(int));
            return dyn ;
        }else{
            return 0;
     
        }
    }
    Déjà la ligne 5 dynIntArray dyn; ne sert à rien et nuit à la compréhension.
    Et ensuite, quand on a un pointeur de structures et qu'on veut accéder à ses membres, on utilise la flèche => dyn->tab=malloc(...).

    Citation Envoyé par KaKou87 Voir le message
    Je ne comprends pas comment à la fois allouer la mémoire pour le tab dynamique et pour la structure elle-même, cela me semble répétitif
    Oui, répétitif. Mais c'est toi qui veut faire ces deux actions. Donc il faut les faire. Hé oui, le C est très bas niveau.
    Dis-toi que ce sont deux actions différentes (allouer de la mémoire pour la structure puis remplir un de ses membres). Sauf que la valeur que tu stockes dans ledit membre c'est (pur hasard) l'adresse d'une zone elle-aussi allouée.

    Citation Envoyé par KaKou87 Voir le message
    et je ne sais donc pas quoi vraiment retourner. Il doit me manquer une information.
    Ben tu l'as dit => la structure allouée => return dyn.

    Et le code de gerald3d reprend parfaitement ce que tu veux faire (sauf que lui aussi il a oublié la flèche à cause de ta ligne 5)

    Code c : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    dynIntArray* createArray(unsigned int capacity){
     
        if (capacity == 0) // Retourne NULL si le paramètre transmis n'est pas correct.
          return NULL;
     
        dynIntArray* dyn = malloc(sizeof(dynIntArray)); // On alloue de la mémoire pour la structure
        dyn->tab = malloc(capacity * sizeof(int));  // On alloue de la mémoire pour le tableau
     
        return dyn ;
    }

    Citation Envoyé par KaKou87 Voir le message
    De même cela m'aidera pour créer une fonction qui elle libérera la mémoire allouée.
    Code c : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    void freeArray(dynIntArray *dyn) {
        free(dyn->tab);
        free(dyn);
    }

    Citation Envoyé par Bktero Voir le message
    C'est moi qui capte rien ou l'allocation d'un dynIntArray ne sert à rien ?
    Ben peut-être qu'il veut gérer plusieurs structures de façon indépendantes...
    Mon Tutoriel sur la programmation «Shell»
    Sinon il y en a pleins d'autres. N'oubliez pas non plus les différentes faq disponibles sur ce site

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

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

    Informations forums :
    Inscription : septembre 2005
    Messages : 27 015
    Points : 40 098
    Points
    40 098
    Par défaut
    Attention, penser à régler dyn->capacity, et initialiser dyn->size à zéro.
    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.

Discussions similaires

  1. Réponses: 7
    Dernier message: 17/01/2012, 17h01
  2. Réponses: 11
    Dernier message: 09/02/2010, 11h42
  3. parcourir un tableau dynamique dans une structure
    Par brunolekid dans le forum C
    Réponses: 4
    Dernier message: 23/10/2009, 15h24
  4. Réponses: 1
    Dernier message: 23/06/2006, 11h19
  5. Réponses: 9
    Dernier message: 22/06/2006, 20h06

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