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 :

[MALLOC] Pourquoi mon code fonctionne-t-il ? (structures imbriquées)


Sujet :

C

  1. #1
    Membre à l'essai
    Profil pro
    Inscrit en
    Avril 2007
    Messages
    12
    Détails du profil
    Informations personnelles :
    Âge : 49
    Localisation : France

    Informations forums :
    Inscription : Avril 2007
    Messages : 12
    Points : 11
    Points
    11
    Par défaut [MALLOC] Pourquoi mon code fonctionne-t-il ? (structures imbriquées)
    Bonjour à tous,

    (Si ça peut aider je code avec VC++ 2005 et je suis débutant en C).

    J'ai donc un gros problème : mon code fonctionne plus sérieusement, il semble fonctionner mais j'ai dû changer mon raisonnement (pour un que je ne comprends pas) en cours de route.

    J'explique vite fait : à la base je comptais créer un tableau dynamique de 3 structures imbriquées dynamiques. N'y arrivant (toujours) pas j'ai tout remis à plat pour le faire étapes par étapes en commençant par allouer & initialiser 2 structures imbriquées (cf. code)
    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
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <errno.h>
    //#include "structures.h"
     
    #define TAILLE_MAX 16
    #define NB_MAX 4
     
    /* Déclaration des types */
    typedef struct Struc_2 Struc_2 ;
    struct Struc_2
    {
        char uneChaine_2[TAILLE_MAX + 1] ;
        int unEntier_2 ;
        int unAutreEntier_2 ;
    } ;
     
    typedef struct Struc_1 Struc_1 ;
    struct Struc_1
    {
        char uneChaine_1[TAILLE_MAX + 1] ;
        Struc_2 * lesStruc_2 ;
    } ;
     
    /* Programme Principal */
    int main (void)
    {
        int i = 0 ;	                  // indice de boucle
        errno_t err = 0 ;            // code d'erreur
        Struc_1 * uneStruc_1 = NULL ; // Pointeur vers une struct de type Struc_1
     
        // On demande la place en mémoire pour notre struct de type Struc_1
        uneStruc_1 = malloc (sizeof (Struc_1)) ;
        if (uneStruc_1 == NULL)
        {
            printf ("\n *** Erreur #1: allocation\n") ;
            return EXIT_FAILURE ;
        }
        // On demande la place en mémoire pour notre tableau de 'sous-struct' de type Struc_2
        uneStruc_1->lesStruc_2 = malloc (sizeof (Struc_2) * NB_MAX) ;
        if (uneStruc_1->lesStruc_2 == NULL)
        {
            printf ("\n *** Erreur #2: allocation\n") ;
            return EXIT_FAILURE ;
        }
        //---------   Initialisation de notre structure de données   ---------//
        // Initialisation de uneStruc_1
        err = strcpy_s (uneStruc_1->uneChaine_1,
                        sizeof (uneStruc_1->uneChaine_1),
                        "Une chaine 1") ;
        if (err != 0)
        {
            printf ("\n *** Erreur #1: strcpy_s\n") ;
            return EXIT_FAILURE ;
        }
        // Initialisation de uneStruc_2
        for (i = 0 ; i < NB_MAX ; i ++)
        {
            err = strcpy_s (uneStruc_1->lesStruc_2[i].uneChaine_2,
                            sizeof (uneStruc_1->lesStruc_2[i].uneChaine_2),
                            "Une chaine 2") ;
            if (err != 0)
            {
                printf ("\n *** Erreur #2: strcpy_s\n") ;
                return EXIT_FAILURE ;
            }
            uneStruc_1->lesStruc_2[i].unEntier_2 = 0 ;
            uneStruc_1->lesStruc_2[i].unAutreEntier_2 = 0 ;
        }
        // Libération de la mémoire
        free (uneStruc_1->lesStruc_2) ;
        free (uneStruc_1) ;
     
        return EXIT_SUCCESS ;
    }
    (J'espère que d'avoir remplacé mes noms de variables par des noms génériques ne le rend pas illisible).

    Donc mon 1er raisonnement lors de mes allocations était :
    • Avant d'allouer la place en mémoire pour maStruc_1 il faut que je connaisse sa taille.
    • Sa taille étant liée à celle de lesStruct_2 (future tableau dynamique de Struc_2 de NB_MAX éléments), il faut d'abord allouer ce tableau de Struc_2.


    Maintenant en pratique, avec cet ordre d'allocations, le code compilait mais générait une exception de Windows à l'exécution. Exception que je pressentais même si mon ordre d'allocation me paraissait logique.

    Je me suis donc résigné d'aller à l'encontre de mon raisonnement et allouer en première maStruc_1. Dans ma p'tite tête, j'allais allouer sans problèmes maStruc_1 mais avec un espace mémoire juste suffisant pour contenir maChaine_1 et un pointeur Struc_2*. Par conséquent j'allais écraser une zone mémoire avec ma deuxième allocation.

    Bon pendant que j'écrivais je me dis que le 2ème raisonnement est logique finalement ... La 1ère allocation me donne effectivement la place pour seulement une chaine et un pointeur et ce pointeur pointe sur la zone allouée au 2ème malloc() qui n'a pas lieu d'être imbriquée comme la représentation graphique qu'on peut se faire d'une structure imbriquée... oui ?

    Bon après ce monologue =) , mes questions :
    1. Ce code fonctionne-t-il effectivement ou attend t-il qu'on tourne le dos pour planter ? Est-ce-que j'ai fait n'importe quoi ?
    2. J'ai lu par-ci par-là que la somme des sizeof(données_membres) était pour les uns égale au sizeof(Structure) et pour les autres non... qu'en est-il ?
    3. Pour créer un tableau dynamique de Struc_1 est-ce-que je vais devoir passer par un tableau de pointeur vers des Struc_1 (Struc_1 ** mesStruc_1) ?
    4. Mes 2 free() doivent-ils être suivis respectivement de uneStruc_1->lesStruc_2 = NULL ; et uneStruc_1 = NULL ;


    Merci de m'éclairer, promis je ferais plus court la prochaine fois ! =)

  2. #2
    Membre éclairé Avatar de stephl
    Profil pro
    Développeur informatique
    Inscrit en
    Février 2007
    Messages
    643
    Détails du profil
    Informations personnelles :
    Localisation : Canada

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Février 2007
    Messages : 643
    Points : 771
    Points
    771
    Par défaut
    1. Je n'ai pas noté d'erreur dans votre code.
    2. Pas toujours vrai. Dépend du système (des contraintes d'alignement).
    3. Pas nécessairement. Struc_1 * suffit.
    4. Pas obligatoire.

  3. #3
    Expert éminent sénior
    Avatar de Médinoc
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Septembre 2005
    Messages
    27 381
    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 381
    Points : 41 578
    Points
    41 578
    Par défaut
    Bonjour,
    1. À part une convention d'écriture horrible (espace entre fonction et parenthèse), je n'ai pas vraiment vu d'erreur de codage.
      Sois seulement prévenu que si la chaîne passée à strcpy_s() est trop grande, la fonction plantera au lieu de retourner une erreur : pour éviter que les fonctions "secure" de M$ plantent, il faut d'abord changer le invalid parameter handler pour une fonction qui ne plante pas.
      De plus, ces fonctions ne sont pas portables.
    2. Pareil que stephl, c'est plus souvent faux que vrai sur une architecture comme un PC moderne sous Windows.
    3. C'est comme tu veux: Un tableau dynamique de structures ou de pointeurs sur structures. Dans certains cas (notamment quand on joue avec realloc()), seul le tableau de pointeurs est sain (si on a d'autres pointeurs ailleurs qui pointent sur une structure donnée).
    4. Conseillé, mais pas obligatoire. Impossible si un pointeur est constant et initialisé par un malloc(), par exemple.


    Par contre, deux petites remarques sur l'emploi de sizeof() :
    • Pour des raisons de maintenabilité, tu peux remplacer sizeof(Struc_1) par sizeof(*uneStruc_1) (même quand le pointeur est encore NULL). Ainsi, tu évites de répéter le type.
    • Puisque tu utilises déjà un truc non-standard (strcpy_s()), je te conseille d'utiliser ARRAYSIZE() et non sizeof() pour le second paramètre. Ainsi, si un jour tu remplaces tes char par des wchar_t, ça ne plantera pas...

  4. #4
    Membre à l'essai
    Profil pro
    Inscrit en
    Avril 2007
    Messages
    12
    Détails du profil
    Informations personnelles :
    Âge : 49
    Localisation : France

    Informations forums :
    Inscription : Avril 2007
    Messages : 12
    Points : 11
    Points
    11
    Par défaut
    Merci pour les réponses.

    Désolé pour mes conventions, se sont celles qu'on m'avait appris à la fac quand je faisais du C++ et il FALLAIT les respecter sous peine de voir ses projets partir à la poubelle =) (Et encore je n'applique plus pour les tab []).

    Je, n'ai pas compris le coup du sizeof(Struc_1) en quoi vaut-il mieux répéter le nom du pointeur plutôt que son type ?

    Les fonctions 'secure' à la base c'était pour ne pas avoir les warnings comme quoi les fonctions standards étaient dépréciées. Maintenant si ça plante pour éviter un overflow ça reste un mal pour un mal, cela dit c'est plus joli sans warning.

    D'après Google ARRAYSIZE() serait défini dans shlwapip.h que je n'ai pas, je l'ai donc défini 'à la main'.

    J'ai enfin résolu mon problème d'imbrication de 3 struct dynamiques en partant de l'hypothèse que mon code était effectivement bon

  5. #5
    Expert éminent sénior
    Avatar de Médinoc
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Septembre 2005
    Messages
    27 381
    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 381
    Points : 41 578
    Points
    41 578
    Par défaut
    Démonstration pour le sizeof() :
    Tu pars de ce code :
    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
    #include <stdio.h>
    #include <stdlib.h>
     
    struct uneStructure { int a; };
    struct uneAutreStructure { int b,c,d; };
     
    int main(void)
    {
        struct uneStructure * pStruc = malloc(sizeof(struct uneStructure));
        if(pStruc == NULL)
            return 1;
     
        pStruc->a = 1;
     
        printf("%d\n", pStruc->a);
     
        free(pStruc);
        return 0;
    }
    Et un jour, on change de structure, mais on oublie de changer le sizeof() (et ça ne fait aucune erreur de compilation, ni aucun warning) :
    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
    #include <stdio.h>
    #include <stdlib.h>
     
    struct uneStructure { int a; };
    struct uneAutreStructure { int b,c,d; };
     
    int main(void)
    {
        struct uneAutreStructure * pStruc = malloc(sizeof(struct uneStructure));
        if(pStruc == NULL)
            return 1;
     
        pStruc->b = 2;
        pStruc->c = 3;
        pStruc->d = 4;
     
        printf("%d %d %d\n", pStruc->b, pStruc->c, pStruc->d);
     
        free(pStruc);
        return 0;
    }
    Si à la place de sizeof(struct ...) on avait utilisé sizeof(*pStruc), il n'y aurait rien à changer dans le sizeof, ce serait toujours *pStruc. Voilà comment on évite un bug...

  6. #6
    Expert éminent sénior
    Avatar de Médinoc
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Septembre 2005
    Messages
    27 381
    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 381
    Points : 41 578
    Points
    41 578
    Par défaut
    ARRAYSIZE() est généralement défini par les headers Windows de base, notamment dans winnt.h... Mais seulement sous Visual, pas sous MinGW.

    C'est pourquoi en C, on peut généralement se contenter de ceci:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    #ifndef ARRAYSIZE
    #define ARRAYSIZE(x) (sizeof(x)/sizeof(x[0]))
    #endif
    En C++, on a droit à un truc plus compliqué qui empêche de l'utiliser sur des pointeurs (encore un bon moyen d'éviter des bugs).
    http://www.developpez.net/forums/sho...87&postcount=6

  7. #7
    Membre à l'essai
    Profil pro
    Inscrit en
    Avril 2007
    Messages
    12
    Détails du profil
    Informations personnelles :
    Âge : 49
    Localisation : France

    Informations forums :
    Inscription : Avril 2007
    Messages : 12
    Points : 11
    Points
    11
    Par défaut
    Effectivement j'adopterais le sizeof(*ptr). Pour la macro, je l'avais bien rajouté.

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

Discussions similaires

  1. Pourquoi mon code rotate ne fonctionne pas?
    Par PhilHype dans le forum jQuery
    Réponses: 6
    Dernier message: 04/11/2013, 11h13
  2. Réponses: 5
    Dernier message: 17/02/2011, 14h45
  3. Pourquoi mon code ne fonctionne pas sur Linux
    Par Amaury_35 dans le forum Langage
    Réponses: 2
    Dernier message: 24/08/2009, 09h58
  4. pourquoi mon code ne fonctionne pas
    Par jmlb35 dans le forum VBA Access
    Réponses: 2
    Dernier message: 30/06/2008, 19h02
  5. Un alert() en plus et mon code fonctionne, sans il foire :|
    Par narnou dans le forum Général JavaScript
    Réponses: 4
    Dernier message: 07/03/2006, 13h44

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