Partage
  • Partager sur Facebook
  • Partager sur Twitter

Initialisez une structure

    27 février 2022 à 14:38:11

    Bonjour, j'essaye d'apprendre le C avec la formation pour débutant sur Openclassroom. J'essaye d'initialiser une structure comme demander dans le cours mais je ne suis pas parvenu à le faire moi même j'ai t trouvé une solution sur le forum pour écrire une fonction qui initialise ma structure, mais je ne la comprends pas totalement.

    Voila ma structure

    typedef struct Personne Personne;
    struct Personne
    {
        char nom[100];
        char prenom[100];
        char adresse[100];
        int age;
    };

    Voila la fonction

    void initPerson(Personne *user)
    {
        user->nom[0]=0;
        user->prenom[0]=0;
        user->adresse[0]=0;
        user->age=0;
    }

    Je ne comprends pas pourquoi on doit écrire le 0 dans les crochets après mes variables pourtant cela fonctionne car je pensais que cela voulais dire remplace la première valeur du tableau de caractère par 0. Quelqu'un saurait-il m'expliquer cette fonction ? 

    Merci d'avance.

    -
    Edité par Matline. 27 février 2022 à 14:42:05

    • Partager sur Facebook
    • Partager sur Twitter
      27 février 2022 à 14:53:23

      Bonjour, en C les chaînes de caractères se terminent par un '\0' (caractère nul) implicite qui indique la fin de la chaîne.

      Ici, ta fonction initialise le premier caractère uniquement à 0, mais si tu essaies d'utiliser printf pour afficher, rien ne se passera :

      #include <stdio.h>
      
      int main(void) {
          char r[] = "\0Hello !";
          printf("%s", r);
      }

      Ce code ne produit pas de sortie, à cause du \0.

      Sinon tu peux utiliser memset ou une simple boucle for pour itérer sur tes tableaux et initialiser chaque élément à 0.

      -
      Edité par Chi_Iroh 27 février 2022 à 14:56:15

      • Partager sur Facebook
      • Partager sur Twitter
        27 février 2022 à 15:12:52

        Ok merci beaucoup pour ton aide et ta rapidité !
        • Partager sur Facebook
        • Partager sur Twitter
          27 février 2022 à 15:19:50

          MathéoKaye a écrit:

          car je pensais que cela voulais dire remplace la première valeur du tableau de caractère par 0. 

          C'est bien ça !

          Les chaînes de caractère étant faite avec des tableaux de char et ayant la particularité d'avoir un caractère de fin de chaîne qui est le '\0' (caractère qui a pour valeur 0). Si tu mets le premier caractère de la chaîne à 0, tu en fais une chaîne vide. 

          Comme on est sur des tableaux destinés à recevoir des chaînes de caractères, j'au plutôt écris :

          user->nom[0]='\0';




          • Partager sur Facebook
          • Partager sur Twitter
          ...
            27 février 2022 à 16:34:35

            Tu peux également utiliser une notation un peu plus moderne (nous sommes plus de 30 ans après ANSI C après tout …) :

            void initPerson_modern(Personne *user)
            {
                *user = (Personne) {
                    .nom="",
                    .prenom="",
                    .adresse="",
                    .age=0,
                };
            }

            Ici tu dis que le contenu pointé est égal à un structure de type personne dans laquelle les champs ont pour valeur une chaîne vide pour nom, prénom et adresse et un champ age valant 0.

            On peut même en faire une fonction. Ce serait une fonction qui renvoie une structure Personne initialisée avec des valeur par défaut :

            Personne defaultPersonne(void) {
                return (Personne) {
                    .nom="",
                    .prenom="",
                    .adresse="",
                    .age=0,
                };
            }
            

            et utiliser ensuite cette fonction :

            void initPerson_modern(Personne *user)
            {
                *user = defaultPersonne();
            }

            Cela te permet, entre autre de centraliser la création d'une valeur par défaut ; du coup si les valeurs par défaut changent ou si tu modifies ta structure, tu n'auras qu'un endroit à modifier dans ton code.

            Une technique plus avancée (et un peu plus dangereuse)  est d'utiliser une macro :

            On commence par définir une simple fonction renvoyant son argument de type structure, la macro donne comme argument un structure par défaut en gérant d'éventuels ajouts :

            Personne _initPersonne(Personne p)
            {
                return p;
            }
            
            #define INIT_PERSONNE(...) _initPersonne( (Personne) {.nom="",      \
                                                                  .prenom="",   \
                                                                  .adresse="",  \
                                                                  .age=0,       \
                                                                  __VA_ARGS__} )
            
            void test()
            {
                Personne default_personne=INIT_PERSONNE();
                Personne jeune=INIT_PERSONNE(.nom="Djoul", .prenom="Kevin", .age=12);
                Personne jeune_inconnu=INIT_PERSONNE(.age=15);
                Personne vieux=INIT_PERSONNE(.age=50, .nom="Capet");
                Personne inconnu=INIT_PERSONNE(.adresse="8 rue Voltaire 75001 Paris");
            }
            

            Cela permet de simuler «des fonctions avec des valeurs d'arguments par défaut» … mais c'est assez casse gueule.


            Edit: typo dans le code (qui d'ailleurs est tapé à la volée en mode quick and dirty et donc non testé).

            -
            Edité par White Crow 27 février 2022 à 16:36:01

            • Partager sur Facebook
            • Partager sur Twitter
              27 février 2022 à 17:51:50

              Merci pour les informations supplémentaire !

              Je pense avoir compris les deux premières méthode plus modernes mais par contre la troisième avec la macros est un peu au dessus de mon niveau je pense (en tout cas je ne la comprends pas). Pour être sûr que j'ai bien compris la deuxième méthode je vais essayer de l'expliquer étape par étape.

              Tu crées une fonction de type Personne qui renvoie une variable de type personne d'ou le

              return (Personne);

              cette variable est ma Personne de base et je peux y changer les valeurs par défaut si j'en veux d'autres.

              J'imagine que le (void) se trouvant après le defaultPersonne veut dire que la fonction n'a pas besoin d'argument.

              Ensuite la seconde fonction égale le user à mon profil par défaut.

              Par contre, tu me dis que avec la deuxième méthode cela permet de centraliser la création de valeur par défaut, mais c'était déjà le cas avant non ?

              Excusez moi d'avance si mes questions sont un peu bêtes...

              • Partager sur Facebook
              • Partager sur Twitter
                1 mars 2022 à 17:24:01

                Si le langage C possédait la déduction de type comme C++, on écrirait simplement

                Personne defaultPersonne(void) {
                    return {                           // NE MARCHE PAS EN C
                        .nom="",
                        .prenom="",
                        .adresse="",
                        .age=0,
                    };
                }

                parce que le compilateur se dirait (*)

                • ligne 2 : on me demande de retourner quelque chose
                • mais ligne 1 on me dit que c'est du type Personne
                • donc - Ha ! - il faut que je retourne une personne
                • qui doit être décrite parce ce qui est marqué après "return"
                • le machin entre accolades ? - yes
                • bon alors ça doit être l'initialiseur d'une structure personne
                Mais bon, c'est du C, alors faut pas trop en demander, donc
                return (Personne) { ..... }
                

                le "typecast" après return, ça sert à dire que c'est un objet (une donnée) de type Personne qui est décrite juste après.
                PS: c'est un typecast, donc il doit être suivi de quelque chose
                return (Personne);           // Erreur syntaxe
                
                n'est pas acceptable
                a.c:11:20: error: expected expression before ‘;’ token
                   11 |  return (Personne) ;
                      |                    ^
                Si on veut retourner une structure non initialisée (dieu nous préserve de cette idée stupide), il faudrait écrire
                return (Personne){};
                


                (*) fiction commode : en fait, le compilateur, il se dit rien.

                -
                Edité par michelbillaud 1 mars 2022 à 17:31:29

                • Partager sur Facebook
                • Partager sur Twitter
                  2 mars 2022 à 7:53:33

                  Salut,

                  Plutôt que la macro, j'utilise un define pour les petites structures que je manipule beaucoup :

                  #define CLEAR_POINT     (SDL_Point){.x = 0, .y = 0}
                  #define CLEAR_ICOORD    (CEV_Icoord){.x = 0, .y = 0, .z = 0}
                  #define CLEAR_FCOORD    (CEV_Fcoord){.x = 0.0, .y = 0.0, .z = 0.0}
                  #define CLEAR_RECT      (SDL_Rect){.x = 0, .y = 0, .w = 0, .h = 0}

                  Cela permet d'initialiser, mais aussi de remettre à 0 à tout moment. Cela me sert aussi de NULL, si une fonction de type SDL_Rect constate un truc qui ne va pas.

                  SDL_Rect result         = CLEAR_RECT,
                           drawRect       = CLEAR_RECT;
                  
                  ....

                  Après, il n'est pas obligatoire d'initialiser si tu es certain que ta structure va passer à la moulinette. Disons que prendre l'habitude de le faire systématiquement évitera d'oublier le jour où ce sera nécessaire..

                  Pour les chaînes de char, j'aurais tendance à initialiser avec "Empty string" ou "Vide" ou n'importe quoi qui signifie clairement que le champ n'a pas été traité : Quand tu verras que ton programme n'affiche pas une chaîne, cela permettra de savoir si c'est à cause de la moulinette ou de l'affichage.

                  Bonne continuation.

                  • Partager sur Facebook
                  • Partager sur Twitter

                  Bonhomme !! | Jeu de plateforme : Prototype.

                    2 mars 2022 à 8:32:13

                    En fait il suffit d'initialiser un des membres à 0, 

                    r = (struct Rect){ .x = 0; };

                    Les autres membres sont mis à 0 / 0. / NULL / whatever.

                    Ils se sont loupés (oh, incroyable) dans la norme, en ne permettant pas une liste vide d'initialisateurs

                    r = (struct Rect){};  // pas permis 


                    qui est me semble-t-il une extension gnu.

                    -
                    Edité par michelbillaud 2 mars 2022 à 8:35:20

                    • Partager sur Facebook
                    • Partager sur Twitter

                    Initialisez une structure

                    × Après avoir cliqué sur "Répondre" vous serez invité à vous connecter pour que votre message soit publié.
                    × Attention, ce sujet est très ancien. Le déterrer n'est pas forcément approprié. Nous te conseillons de créer un nouveau sujet pour poser ta question.
                    • Editeur
                    • Markdown