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 :

Copie *totale* de structures


Sujet :

C

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre averti
    Profil pro
    Inscrit en
    Mars 2009
    Messages
    17
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mars 2009
    Messages : 17
    Par défaut Copie *totale* de structures
    Bonjour.

    Je n'arrive pas à faire une copie *complète* de structure. Les cas rencontrés dans
    les FAQs que j'ai lues ne traitaient que du cas simple d'une copie sans "profondeur"
    et sans pointeur.
    Lorsque j'utilise "memcopy" les résultats sont identiques.
    Faut-il passer par "malloc" ?

    Je vous fournis un code (artificiel, juste pour illustrer mon problème).

    Je crée donc une voiture "car1" qui me sert de modèle pour créer une
    autre, "car2". Dans mon cas réel j'ai beaucoup plus de champs dans
    mes structures.
    Un point à noter : dans la structure "Car" je veux un *pointeur*
    sur la structure "Engine", parce qu'il pourra se faire que la voiture
    n'aie pas de moteur (donc p_engine = NULL).

    En dessous du code figure ce que j'obtiens dans ma console.

    Je débute en C. Merci.

    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
     
    #inclut <stdio.h>
     
    struct Engine {
        int displacement;
    };
     
    struct Car {
        int mass;
        struct Engine * p_engine;
    };
     
    void copy_engine(struct Engine * p_engine_src, struct Engine * p_engine_dest) {
     
        p_engine_dest->displacement = p_engine_src->displacement;
     
        return;
    }
     
    void copy_car(struct Car * p_car_src, struct Car * p_car_dest) {
     
        p_car_dest->mass = p_car_src->mass;
        copy_engine(p_car_src->p_engine, p_car_dest->p_engine);
     
        return;
    }
     
    void build_engine(struct Engine * p_engine) {
     
        p_engine->displacement = 1400;
     
        return;
    }
     
    void build_car(struct Car * p_car) {
     
        struct Engine engine;
     
        build_engine(&engine);
        p_car->mass = 1200;
     
        return;
    }
     
    void print_car(struct Car * p_car) {
     
        printf("car:%p\n", (void *) p_car);
        printf("  car.mass:%d\n", p_car->mass);
        printf("  car.p_engine:%p\n", (void *) p_car->p_engine);
        printf("  car.p_engine.displacement:%d\n", p_car->p_engine->displacement);
     
        return;
    }
     
    int main (int argc, char *argv[]) {
     
        struct Car car1;
        struct Car car2;
     
        build_car(&car1);
        copy_car(&car1, &car2);
     
        print_car(&car1);
        print_car(&car2);
     
        return 0;
    }
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
     
    car:0xbff75a3c
      car.mass:1200
      car.p_engine:0xb7dcdc8c
      car.p_engine.displacement:18589
    car:0xbff75a34
      car.mass:1200
      car.p_engine:0xbff75a58
      car.p_engine.displacement:18589

  2. #2
    Expert éminent
    Avatar de Emmanuel Delahaye
    Profil pro
    Retraité
    Inscrit en
    Décembre 2003
    Messages
    14 512
    Détails du profil
    Informations personnelles :
    Âge : 68
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Retraité

    Informations forums :
    Inscription : Décembre 2003
    Messages : 14 512
    Par défaut
    Citation Envoyé par bourba Voir le message
    Je vous fournis un code (artificiel, juste pour illustrer mon problème).
    Merci de vérifier le code avant de le poster ...
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
     
     
    -------------- Build: Debug in hello ---------------
     
    Compiling: main.c
    Linking console executable: bin\Debug\hello.exe
    C:\dev\hello\main.c:1:2: invalid preprocessing directive #inclut
    C:\dev\hello\main.c: In function `print_car':
    C:\dev\hello\main.c:46: warning: implicit declaration of function `printf'
    C:\dev\hello\main.c: At top level:
    C:\dev\hello\main.c:54: warning: unused parameter 'argc'
    C:\dev\hello\main.c:54: warning: unused parameter 'argv'
    Process terminated with status 1 (0 minutes, 0 seconds)
    1 errors, 3 warnings
    La première question à se poser est "ai-je vraiment besoin de copier une structure ?"

    Ensuite, si tu y tiens, pour une structure linéaire, il suffit d'utiliser l'opérateur d'affectation '='.

    Si la structure n'est pas linéaire (pointeurs), c'est plus compliqué. Il faut écrire une fonction qui recrée une nouvelle structure. Certaines parties pointées sont peut être statiques, d'autre dynamiques. Il faut le savoir à coup sur, quitte à ajouter un flag...

    C'est relativement complexe, et encore une fois, est-ce bien nécessaire ?

    Dans ton code, la fonction qui crée la structure est incorrecte.
    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
     
    #include <stdio.h>
     
    struct Engine
    {
       int displacement;
    };
     
    struct Car
    {
       int mass;
       struct Engine *p_engine;
    };
     
    static void build_engine (struct Engine *p_engine)
    {
       p_engine->displacement = 1400;
     
       return;
    }
     
    static void build_car (struct Car *p_car)
    {
       struct Engine engine;
     
       build_engine (&engine);
       p_car->mass = 1200;
     
       return;
    }
     
    static void print_car (struct Car *p_car)
    {
     
       printf ("car:%p\n", (void *) p_car);
       printf (" car.mass:%d\n", p_car->mass);
       printf (" car.p_engine:%p\n", (void *) p_car->p_engine);
       printf (" car.p_engine.displacement:%d\n", p_car->p_engine->displacement);
     
       return;
    }
     
    int main (void)
    {
       struct Car car1;
     
       build_car (&car1);
       print_car (&car1);
       return 0;
    }
    car1.p_engine n'est jamais initialisé.

    Attention, il doit l'être avec une adresse valide pendant l'exécution, c'est à dire statique ou dynamique. Elle ne peut être locale, que si elle provient du plus haut niveau (main()). A éviter.

  3. #3
    Membre averti
    Profil pro
    Inscrit en
    Mars 2009
    Messages
    17
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mars 2009
    Messages : 17
    Par défaut
    Désolé ! J'avais évidemment bien "#include" dans ma source,
    j'ai dû substituer par erreur dans le correcteur orthographique...

    Sur le fond...
    J'ai déjà lu qu'il était inhabituel de copier des structures. Ça me
    surprend un peu.
    Imaginons que mon application crée et manipule des voitures, je
    peux donc créer une pile stockant les adresses de chaque
    structure "Car" créée au fur et à mesure.
    Imaginons que l'on souhaite ensuite se servir d'une voiture comme
    *modèle* pour en créer une autre. Je fournirai donc l'adresse de
    la struct Car source et celle de la structure Car destination, en
    modifiant éventuellement des champs de la deuxième par la suite.
    J'aurai donc, sans rentrer dans le détail de l'implémentation :

    Une liste chaînée :

    all_cars = ( 0xab0... : adresse N°1 d'une structure Car,
    0xdb1... : adresse N°2 d'une structure Car, ... )

    Une fonction de création :

    void copy_car(struct Car * p_car_src, struct Car * p_car_dest) { ... }

    Dans une application réelle j'aurais probablement beaucoup de champs
    dans "Car", l'idée de copie me semblait extrêmement naturelle.
    Je n'arrive pas à voir ce qu'il y a de non conforme dans l'esprit
    du C dans une copie de structure.

  4. #4
    Expert éminent
    Avatar de Emmanuel Delahaye
    Profil pro
    Retraité
    Inscrit en
    Décembre 2003
    Messages
    14 512
    Détails du profil
    Informations personnelles :
    Âge : 68
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Retraité

    Informations forums :
    Inscription : Décembre 2003
    Messages : 14 512
    Par défaut
    Citation Envoyé par bourba Voir le message
    J'ai déjà lu qu'il était inhabituel de copier des structures. Ça me
    surprend un peu.
    Imaginons que mon application crée et manipule des voitures, je
    peux donc créer une pile stockant les adresses de chaque
    structure "Car" créée au fur et à mesure.
    Imaginons que l'on souhaite ensuite se servir d'une voiture comme
    *modèle* pour en créer une autre.
    Voilà. C'est à peu près le seul cas 'réel' que je connaisse.

    Mais il y a déjà des erreurs dans la code de base. Tu as une correction à me proposer ?

  5. #5
    Membre averti
    Profil pro
    Inscrit en
    Mars 2009
    Messages
    17
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mars 2009
    Messages : 17
    Par défaut
    Ce code fonctionne :
    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
     
    #include <stdio.h>
     
    struct Engine {
        int displacement;
    };
     
    struct Car {
        int mass;
        struct Engine * p_engine;
    };
     
    void copy_engine(struct Engine * p_engine_src, struct Engine * p_engine_dest) {
     
        p_engine_dest->displacement = p_engine_src->displacement;
     
        return;
    }
     
    void copy_car(struct Car * p_car_src, struct Car * p_car_dest) {
     
        p_car_dest->mass = p_car_src->mass;
        copy_engine(p_car_src->p_engine, p_car_dest->p_engine);
     
        return;
    }
     
    void build_engine(struct Engine * p_engine) {
     
        p_engine->displacement = 1400;
     
        return;
    }
     
    void build_car(struct Car * p_car, struct Engine * p_engine) {
     
        build_engine(p_engine);
        p_car->p_engine = p_engine;
        p_car->mass = 1200;
     
        return;
    }
     
    void print_car(struct Car * p_car) {
     
        printf("car:%p\n", (void *) p_car);
        printf("  car.mass:%d\n", p_car->mass);
        printf("  car.p_engine:%p\n", (void *) p_car->p_engine);
        printf("  car.p_engine.displacement:%d\n", p_car->p_engine->displacement);
     
        return;
    }
     
    int main (int argc, char *argv[]) {
     
        struct Car car1;
        struct Car car2;
        struct Engine engine1;
     
        build_car(&car1, &engine1);
        copy_car(&car1, &car2);
        car2.p_engine->displacement = 1600;
     
        print_car(&car1);
        print_car(&car2);
     
        return 0;
    }
    Retour console :

    car:0xbfd4601c
    car.mass:1200
    car.p_engine:0xbfd46010
    car.p_engine.displacement:1400
    car:0xbfd46014
    car.mass:1200
    car.p_engine:0xbfd46038
    car.p_engine.displacement:1600

  6. #6
    Membre averti
    Profil pro
    Inscrit en
    Mars 2009
    Messages
    17
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mars 2009
    Messages : 17
    Par défaut
    C'est étonnant ce que tu me dis, "cloner" des structures est une opération qui m'a très souvent parue être nécessaire ! Je dois manquer de recul en programmation C
    Ou un début d'intoxication par la POO ?

  7. #7
    Expert éminent
    Avatar de Emmanuel Delahaye
    Profil pro
    Retraité
    Inscrit en
    Décembre 2003
    Messages
    14 512
    Détails du profil
    Informations personnelles :
    Âge : 68
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Retraité

    Informations forums :
    Inscription : Décembre 2003
    Messages : 14 512
    Par défaut
    Citation Envoyé par bourba Voir le message
    Ce code fonctionne :
    par hasard uniquement. Chez moi, c'est le crash :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
     
    car:0022FF38
      car.mass:1200
      car.p_engine:0022FF44
      car.p_engine.displacement:1400
     
    Process returned -1073741819 (0xC0000005)   execution time : 4.282 s
    Press any key to continue.
    le p_engine de la deuxième structure n'est pas initialisé. Tu le déréférences : le comportement est indéfini.

    Pour éviter les comportements hasardeux, je conseille d'initialiser les structures avant usage :
    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
     
    #include <stdio.h>
     
    struct Engine
    {
       int displacement;
    };
     
    struct Car
    {
       int mass;
       struct Engine *p_engine;
    };
     
    static void copy_engine (struct Engine *p_engine_src,
                             struct Engine *p_engine_dest)
    {
       p_engine_dest->displacement = p_engine_src->displacement;
    }
     
    static void copy_car (struct Car *p_car_src, struct Car *p_car_dest)
    {
       p_car_dest->mass = p_car_src->mass;
       copy_engine (p_car_src->p_engine, p_car_dest->p_engine);
    }
     
    static void build_engine (struct Engine *p_engine)
    {
       p_engine->displacement = 1400;
    }
     
    static void build_car (struct Car *p_car, struct Engine *p_engine)
    {
       build_engine (p_engine);
       p_car->p_engine = p_engine;
       p_car->mass = 1200;
     
    }
     
    static void print_car (struct Car const *p_car)
    {
       printf ("car:%p\n", (void *) p_car);
       printf ("  car.mass:%d\n", p_car->mass);
       printf ("  car.p_engine:%p\n", (void *) p_car->p_engine);
       printf ("  car.p_engine.displacement:%d\n", p_car->p_engine->displacement);
     
    }
     
    int main (void)
    {
       struct Car car1 = {0};
       struct Engine engine1 = {0};
     
       build_car (&car1, &engine1);
       print_car (&car1);
     
       {
          struct Car car2 = {0};
          copy_car (&car1, &car2);
          car2.p_engine->displacement = 1600;
          print_car (&car2);
       }
       return 0;
    }

Discussions similaires

  1. Copie d'une structure
    Par wallace27 dans le forum C
    Réponses: 6
    Dernier message: 12/02/2015, 17h49
  2. [MySQL] Copie de la structure d'une table mysql
    Par Psycha dans le forum PHP & Base de données
    Réponses: 4
    Dernier message: 26/05/2009, 14h33
  3. Copie d'une structure.
    Par gerald3d dans le forum C
    Réponses: 12
    Dernier message: 24/03/2008, 12h22
  4. Réponses: 8
    Dernier message: 21/05/2007, 21h40
  5. copie de la structure d'un IB(Dataset)dans un CLientDataSet
    Par AKSEL dans le forum Bases de données
    Réponses: 2
    Dernier message: 07/07/2005, 17h07

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