Partage
  • Partager sur Facebook
  • Partager sur Twitter

La fonction refuse d'accéder à un champ du struct

    18 avril 2006 à 13:52:57

    Bonjour à tous.

    Voilà, j'ai un gros problème : je suis en train de coder le principe du jeu de la vie ((cf Wikipedia).

    Le principe : un échiquier, construit à partir d'un fichier de la forme suivante :
    5 5 (taille du tableau)
    1 2 (cases pleines)
    2 3
    3 4


    L'echiquier est un structure contenant 2 entiers : hauteur et largeur, et un tableau de char.

    Le problème vient de la fonction d'affichage du tableau, echiquier_affiche(Echiquier *e) qui refuse qu'on accède aux champs de l'echiquier fourni en paramètre. Voyez plutôt :

    #include <stdio.h>
    #include <stdlib.h>

    typedef char Case;

    typedef struct {
            int hauteur, largeur;
            Case *tabcases; // Tableau de cases
    } Echiquier;

    Echiquier* echiquier_creation(int larg, int haut) {
        int j;
        if (larg > 0 && haut > 0) {

            Echiquier *echiq = (Echiquier*) (calloc(1,sizeof(Echiquier)));
            echiq->hauteur = haut;
            echiq->largeur = larg;

            Case *c = (Case*) (calloc(larg*haut, sizeof(Case)));

            for(j = 0 ; j < echiq->hauteur*echiq->largeur ; j++) {
                c[j] = '.';
            }

            /*for(j = 0 ; j < echiq->hauteur*echiq->largeur ; j++) {
                printf("tabcases[%ld] = %c\n", j, c[j]);
            }*/


            echiq->tabcases = c;

            for(j = 0 ; j < echiq->hauteur*echiq->largeur ; j++) {
                printf("tabcases[%ld] = %c\n", j, echiq->tabcases[j]);
            }

            return echiq;
        }
    }

    void echiquier_suppression(Echiquier *e) {
        free(e->tabcases);
        free(e);
    }

    int echiquier_nombres_voisins(Echiquier *e, int x, int y) {

    }

    void echiquier_affiche(Echiquier *e) {
        if (e != NULL) { // L'echiquier existe
            printf("DEBUG : echiquier exists\n");

            // ****************************************************************** PARTIE A SUPPRIMER
            printf("\n");
            int j;
            for(j = 0 ; j < e->hauteur*e->largeur ; j++) {
                printf("tabcases[%d] = %c\n", j, e->tabcases[j]);
            }
            // ******************************************************************
        }
        else
            printf("DEBUG : echiquier doesn't exist\n");
    }


    void echiquier_initialise(Echiquier *e, char *path) {
            FILE* file = fopen(path, "r");
            if (file == NULL) { // Erreur fichier
            printf("DEBUG : file doesn't exist");
                exit(0);
            }
            else {
            printf("DEBUG : file exists\n");
                int larg, haut, x, y, i, j;
            if (fscanf(file, "%ld %ld", &larg, &haut) != EOF) {
                e = echiquier_creation(larg, haut);
            }

            printf("\n");
            for(j = 0 ; j < e->hauteur*e->largeur ; j++) {
                printf("tabcases[%ld] = %c\n", j, e->tabcases[j]);
            }
            }
    }

    int main(int argv, char **argc) {
        Echiquier* ech;
        echiquier_initialise(ech, "fichier.txt");

        echiquier_affiche(ech);

        echiquier_suppression(ech);
        return 0;
    }


    Vous pourrez voir, si vous avez la gentillesse de tester ce code, que tout plante si on laisse la partie encadrée dans la fonction echiquier_affiche().

    Est ce que quelqu'un voit la solution à mon problème ? Merci d'avance !

    StraToN
    • Partager sur Facebook
    • Partager sur Twitter
      18 avril 2006 à 14:02:53

      Je n'ai pas trouve ton erreure,mais je travaille moi aussi sur un jeu de la vie en ce moment. Si ca s'interresse vais regarder pour trouver le code source.
      • Partager sur Facebook
      • Partager sur Twitter
        18 avril 2006 à 14:10:11

        Quand tu passes en paramètres un pointeur c'est ce qui est pointé que tu peux modifié pas le pointeur.

        L'appel :
        type * pointeur1;
        appel(pointeur1);

        La fonction :
        appel(type * pointeur2)
        {
        //ici pointeur2 pointe vers la mm chose que pointeur1.
        Modifier ce qui est pointé par pointeur2 modifiera ce qui est pointé par pointeur1 mais modifier pointeur2 ne modifiera pas pointeur1
        }

        Donc fait plutot faire un retour à ta fonction initialise.

        De plus tu devrais lire le cours de M@teo car tu pourras utiliser la SDL pour afficher des pixels.

        Echiquier * echiquier_initialise(char *path) {
        Echiquier * tmp = NULL;       

        FILE* file = fopen(path, "r");
                if (file == NULL) { // Erreur fichier
                printf("DEBUG : file doesn't exist");
                    exit(0);
                }
                else {
                printf("DEBUG : file exists\n");
                    int larg, haut, x, y, i, j;
                if (fscanf(file, "%ld %ld", &larg, &haut) != EOF) {
                    tmp = echiquier_creation(larg, haut);
                }

                printf("\n");
                for(j = 0 ; j < e->hauteur*e->largeur ; j++) {
                    printf("tabcases[%ld] = %c\n", j, e->tabcases[j]);
                }
        return tmp;
                }
        }
        • Partager sur Facebook
        • Partager sur Twitter
          18 avril 2006 à 14:32:10

          Citation : StraToN

          Est ce que quelqu'un voit la solution à mon problème ?


          • main() : ech est un pointeur non initialisé. Tu le passes à echiquier_initialise(). Le comportement est indéterminé.
          • Il manque un appel à echiquier_creation() avant...
          • malloc() / calloc() peut échouer...

          Suite aux bonnes remarques de Kayl, ceci fonctionne :
          Secret (cliquez pour afficher)

          #include <stdio.h>
          #include <stdlib.h>

          #define DBG 0

          typedef char Case;

          typedef struct
          {
             int hauteur, largeur;
             Case *tabcases; // Tableau de cases
          }
          Echiquier;

          static Echiquier* echiquier_creation(int larg, int haut)
          {
             Echiquier *echiq = NULL;
             if (larg > 0 && haut > 0)
             {
                echiq = malloc(sizeof * echiq);

                if (echiq != NULL)
                {
                   /* mise a 0 */
                   {
                      static const Echiquier z;
                      *echiq = z;
                   }
                   Case *c = malloc (larg * haut * sizeof * c);

                   if (c != NULL)
                   {
                      int j;
                      for (j = 0 ; j < haut * larg ; j++)
                      {
                         c[j] = '.';
                      }
                      /* sauvegarde */
                      echiq->hauteur = haut;
                      echiq->largeur = larg;
                      echiq->tabcases = c;
          #if DBG

                      for (j = 0 ; j < echiq->hauteur*echiq->largeur ; j++)
                      {
                         printf("tabcases[%d] = %c\n", j, echiq->tabcases[j]);
                      }
                      printf ("\n");
          #endif
                   }
                   else
                   {
                      free(echiq), echiq = NULL;
                   }
                }
             }
             return echiq;
          }

          static void echiquier_suppression (Echiquier *e)
          {
             free(e->tabcases);
             free(e);
          }

          static int echiquier_nombres_voisins(Echiquier *e, int x, int y)
          {

          }

          static void echiquier_affiche(Echiquier *e)
          {
             if (e != NULL)
             { // L'echiquier existe
                int j;
                printf("DEBUG : echiquier exists\n");

                for (j = 0 ; j < e->hauteur*e->largeur ; j++)
                {
                   printf("tabcases[%d] = %c\n", j, e->tabcases[j]);
                }
                      printf ("\n");
             }
             else
             {
                printf("DEBUG : echiquier doesn't exist\n");
             }
          }


          static Echiquier *echiquier_initialise(char const *path)
          {
             Echiquier *e = NULL;

             FILE* file = fopen(path, "r");
             if (file != NULL)
             {
                char s[64];
                if (fgets(s, sizeof s, file) != NULL)
                {
                   int larg, haut;
                   if (sscanf(s, "%d %d", &larg, &haut) == 2)
                   {
                      printf ("creation d'un echiquier de %dx%d\n", larg, haut);
                      e = echiquier_creation(larg, haut);
          #if DBG

                      {
                         int j;
                         for (j = 0 ; j < e->hauteur*e->largeur ; j++)
                         {
                            printf("tabcases[%d] = %c\n", j, e->tabcases[j]);
                         }
                         printf("\n");
                      }
          #endif
                   }
                }
             }
             else
             {
                perror(path);
             }
             return e;
          }

          int main(int argv, char **argc)
          {
             Echiquier* ech = echiquier_initialise("fichier.txt");

             if (ech != NULL)
             {
                echiquier_affiche(ech);

                echiquier_suppression(ech), ech = NULL;
             }
             return 0;
          }
          • Partager sur Facebook
          • Partager sur Twitter
          Music only !
            18 avril 2006 à 15:55:43

            Merci beaucoup de votre aide!

            Je n'ai pas le temps de tester tout ça tout de suite :( , je testerai ce soir et j'essaierai de repasser demain pour vous informer du résultat.

            En attendant, merci infiniment !
            • Partager sur Facebook
            • Partager sur Twitter
              19 avril 2006 à 8:15:18

              Après avoir testé et regardé hier, je vous remercie encore une fois tous les 2. Et comme je ne suis pas tout à fait un spécialiste du C, j'ai quelques questions à propos de ce que tu as écrit.

              {
                 static const Echiquier z;
                 *echiq = z;
              }


              Cette partie n'est raccrochée à aucun bloc, c'est un bloc à part entière, mais à quoi sert il ? On peut le supprimer facilement, le programme fonctionnera toujours o_O.

              Autre question : est ce que sizeof * echiq = sizeof(echiq) ?

              Merci pour le conseil concernant la fonction echiquier_initialise() pour qu'elle renvoie un Echiquier, plutôt que d'utiliser un pointeur sur l'échiquier. J'avais fait comme ça suite à la consigne du prof de C :-° (moralité, n'écoutez jamais vos profs).

              echiquier_suppression(ech), ech = NULL;

              Un peu bizarre cette virgule, pourtant ça marche o_O...

              Aussi je voulais dire à Kayl :

              Citation : Kayl

              De plus tu devrais lire le cours de M@teo car tu pourras utiliser la SDL pour afficher des pixels.


              En fait, je préfère faire un code console pour l'instant, mais j'ai prévu d'en faire une plus tard.

              Sinon j'ai bien avancé hier, pour l'ajout des cases pleines en fonction de celles du fichier.

              Voici le code actuel :
              #include <stdio.h>
              #include <stdlib.h>

              typedef char Case;

              typedef struct
              {
                 int hauteur, largeur;
                 Case *tabcases; // Tableau de cases
              }
              Echiquier;

              Echiquier* echiquier_creation(int larg, int haut) {
                  Echiquier *echiq = NULL;
                  if (larg > 0 && haut > 0) {
                      /* On veut créer des bordures, donc on augmente de 2 la largeur
                       * et la hauteur
                       */

                      int tmp_larg = larg + 2, tmp_haut = haut + 2;

                      echiq = malloc(sizeof(echiq));

                      if (echiq != NULL) {
                          /* mise a 0 */
                          /*{
                              static const Echiquier z;
                              *echiq = z;
                          }*/

                          Case *c = malloc (tmp_larg * tmp_haut * sizeof(c));

                          if (c != NULL) {
                              int j;
                              for (j = 0 ; j < tmp_larg * tmp_haut ; j++) {
                                 c[j] = '.';
                              }
                              /* sauvegarde */
                              echiq->hauteur = haut;
                              echiq->largeur = larg;
                              echiq->tabcases = c;
                          }
                          else {
                              free(echiq), echiq = NULL;
                          }
                      }
                  }
                  return echiq;
              }

              void echiquier_suppression (Echiquier *e)
              {
                  free(e->tabcases);
                  free(e);
              }


              void echiquier_nombres_voisins(Echiquier *e, int x, int y) {
                  int cellindex = (y * e->largeur) - e->largeur + x - 1;
                  int empty = 0;
                  /* La case est-elle vide ? */
                  if (cellindex >= 0 && cellindex < e->largeur * e->hauteur) {
                      if (e->tabcases[cellindex] != '.') {
                          empty = 1;
                      }
                  }
                  printf("(%d,%d) correspond a la case %d. %d poisson dedans.\n", x, y, cellindex, empty);


              }


              void echiquier_affiche(Echiquier *e) {
                  if (e != NULL) { // L'echiquier existe
                      int j, prec=0;
                      for (j = 0 ; j < e->hauteur*e->largeur ; j++) {
                          int linenum = (j / e->largeur);
                          if (linenum != prec) {
                              printf("\n");
                          }
                          /* printf("tabcases[%d] = %c  x=%d  y=%d", j, e->tabcases[j], linenum); */
                          printf("%c ", e->tabcases[j]);
                          prec = linenum;
                      }
                      printf ("\n");
                  }
                  else {
                      printf("DEBUG : echiquier doesn't exist\n");
                  }
              }


              Echiquier *echiquier_initialise(char const *path) {
                  Echiquier *e = NULL;

                  FILE* file = fopen(path, "r");
                  if (file != NULL) {
                      char s[64];

                      /* Lecture de la 1ère ligne & création de l'échiquier */
                      if (fgets(s, sizeof(s), file) != NULL) {
                          int larg, haut;
                          if (sscanf(s, "%d %d", &larg, &haut) == 2) {
                              printf ("Creation d'un echiquier de %dx%d\n", larg, haut);
                              e = echiquier_creation(larg, haut);
                          }
                      }

                      /* Lecture des lignes suivantes */
                      int x, y;
                      int cellindex;

                      while (fgets(s, sizeof(s), file) != NULL) {
                          if (sscanf(s, "%d %d", &x, &y) == 2) {
                              if (x > 0 && x <= e->largeur) {
                                  if (y > 0 && y <= e->hauteur) {
                                      cellindex = (y * e->hauteur) - e->hauteur + x - 1;
                                      printf ("Valeurs chargees : %d %d, correspondent a la case %d\n", x, y, cellindex);

                                      if (x * y <= (e->largeur * e->hauteur) && x * y > 0) {
                                          e->tabcases[cellindex] = 'O';
                                      }
                                  }
                              }
                          }
                      }
                  }
                  else {
                      /* Erreur de chemin */
                      perror(path);
                  }
                  return e;
              }

              int main(int argv, char **argc)
              {
                  Echiquier* ech = echiquier_initialise("fichier.txt");

                  if (ech != NULL) {
                      printf("larg : %d -- haut : %d\n",ech->largeur, ech->hauteur);
                      echiquier_affiche(ech);
                      echiquier_nombres_voisins(ech,2,2);
                      echiquier_suppression(ech);
                      ech = NULL;
                  }
                  return 0;
              }


              Ah, dernière question purement idéologique : les {, vaut il mieux les mettre sur la ligne du prototype ou sur la ligne suivante, ou à l'appréciation du codeur ? Parce que je sais que M@teo les met après, alors que moi je les mets sur la ligne courante (déformation du Java :/).
              • Partager sur Facebook
              • Partager sur Twitter
                19 avril 2006 à 8:38:49

                Il vaut mieux rien du tout. C'est au choix en fonction du style que tu comptes respecter. Le tout est d'être cohérent.

                ANSI
                namespace foospace
                {
                    int Foo()
                    {
                        if (isBar)
                        {
                            bar();
                            return 1;
                        }
                        else
                            return 0;
                    }
                }


                K&R
                namespace foospace {
                    int Foo() {
                        if (isBar) {
                            bar();
                            return 1;
                         } else
                            return 0;
                    }
                }


                etc... (Linux, Gnu, Java style, ...)

                Si tu as Code::Blocks tu peux visualiser ces styles dans Plugins > Plugins' Settings > Source code formatter (AStyle). Une fois un style selectionné non seulement à l'édition il essaye de t'aider à respecter ce style mais à tout moment tu peux surligner du texte et faire Plugins > Source code formatter (AStyle) pour qu'il te remette ton code proprement (indentation, accolades, ...).
                • Partager sur Facebook
                • Partager sur Twitter
                  19 avril 2006 à 10:11:28

                  Cool ! J'utilise CodeBlocks (sous Linux et Windows) et je ne connaissais pas cette fonction :p J'essaierai ça dès que possible ! Merci ^^
                  • Partager sur Facebook
                  • Partager sur Twitter
                    19 avril 2006 à 11:45:20

                    Citation : StraToN


                    {
                       static const Echiquier z;
                       *echiq = z;
                    }



                    Cette partie n'est raccrochée à aucun bloc, c'est un bloc à part entière, mais à quoi sert il ? On peut le supprimer facilement, le programme fonctionnera toujours o_O.


                    Ce petit bloc sert à définir une variable statique à lecture seule automatiquement initialisée à 0 (z) du même type ce celle pointée par echiq. Donc en écrivant *echiq = z, je recopie z dans *echiq, ce qui a pour effet de lettre à 0 tous les champs de *echiq.

                    C'est une façon simple, rapide et portable d'initialiser une structure avec tous les champs à 0. Le bloc sert aussi à limiter la portée de z, qui n'interese qu'une ligne. Le qualificateur static permet une initialisaion à 0 par défaut. Combiné avec le qualificateur const, il indique au compilateur qu'il n'y aura pas d'accès en écriture dans z (lecture seule). Il peut donc optimiser l'implémentartion.

                    Citation : StraToN


                    Autre question : est ce que sizeof * echiq = sizeof(echiq) ?


                    Non. *echiq désigne la structure pointée par echiq
                    . sizeof *echiq est donc la taille de cette structure. sizeof(echiq) serait la taille du pointeur. Aucun intérêt.

                    Citation : StraToN


                    echiquier_suppression(ech), ech = NULL;


                    Un peu bizarre cette virgule, pourtant ça marche o_O...


                    C'est l'opérateur ','.(comma operator). Sémantiquement, il n'y a pas de différence avec
                    echiquier_suppression(ech);
                    ech = NULL;

                    Mais , avec une telle écriture, on serait tenté de séparer les deux instructions,
                    echiquier_suppression(ech);
                    ech = NULL;

                    ce qui fait courir le risque d'utiliser un pointeur invalide (free()) sans possibilité de contrôle (non NULL). Ca romprait la regle qui veut que la valeur d'un pointeur soit valide ou NULL. L'écriture avec la ',' rend en quelque sorte 'insécable' le groupe d'instructions, au moins sur le plan visuel. (Mais pour s'intercaler entre les deux, il fait vraiment le vouloir...).

                    De plus, les indenteurs automatiques respectent le groupe en le laissant sur une seule ligne...
                    • Partager sur Facebook
                    • Partager sur Twitter
                    Music only !
                      19 avril 2006 à 12:42:10

                      Citation : -ed-


                      Citation : StraToN


                      Autre question : est ce que sizeof * echiq = sizeof(echiq) ?


                      Non. *echiq désigne la structure pointée par echiq
                      . sizeof *echiq est donc la taille de cette structure. sizeof(echiq) serait la taille du pointeur. Aucun intérêt.



                      :-° la question idiote de ma part... Pourtant j'aurais dû y penser, aux pointeurs :D.
                      Pourtant, même après avoir remplacé les sizeof *echiq par des sizeof(echiq), le code fonctionne parfaitement o_O, alors soit j'ai de la chance, soit c'est faux...

                      Merci pour les autres explications, j'ai compris ^^.
                      • Partager sur Facebook
                      • Partager sur Twitter
                        19 avril 2006 à 16:33:24

                        Citation : StraToN

                        Pourtant, même après avoir remplacé les sizeof *echiq par des sizeof(echiq), le code fonctionne parfaitement o_O, alors soit j'ai de la chance, soit c'est faux...


                        Pour qu'un code soit conforme, il faut d'abord qu'il ne comporte pas de comportement indéfini. Or, faire une erreur de type qui entraine une incertitude sur la taille crée un comportement indéfini. (On a introduit une incertitude dans le priocess). Tout le programme devient faux.

                        Le problème, c'est que ni la compilation, ni l'exécution ne vont s'apercevoir du problème. Il peut donc subsister sans qu'on en voit les effets (sauf évidemment le jour de la démo devant le client, selon les principes bien connus de la Loi de Murphy...)

                        Pire encore, les effets pervers de ce comportement vont perturber un fonctionnement qui est pourtant validé. Bref, c'est le poison absolu qui peut coûter extrèmement chèr (mort d'homme en Médical ou en Avionique, explosion de fusée, de centrale nucléaire, rupture de barrage... On ne s'en tirera pas avec un 'oups!'). Faut pas rigoler avec ça.

                        Le C est puissant, mais dangereux entre les mains des débutants. Si les anciens insistent tant sur la sécurité, ce n'est pas sans raison. Je persiste à dire que le C n'est pas un langage pour informaticiens débutants. Trop de choses à apprendre et à maitriser d'un coup... Mais ce n'est que mon avis, et je le partage... En attendant, je m'efforce de recoller les morceaux...
                        • Partager sur Facebook
                        • Partager sur Twitter
                        Music only !
                          20 avril 2006 à 17:00:45

                          Wow... o_Oo_O

                          Noté en majuscules, enregistré, souligné 3 fois, encadré en rouge.

                          Pour rappel, la fameuse Loi de Murphy consiste en cette simple phrase : "Si cela doit arriver, alors cela arrivera."
                          On frémit devant de telles possibilités, et surtout devant de telles conséquences.

                          Conclusion : programmeurs, pratiquez toujours prudemment. En ce qui me concerne, j'y réfléchirai à plus d'une fois.

                          Ceci dit, pour qu'un programmeur ne soit plus débutant, il faut qu'il pratique. Est ce que tu veux dire que le débutant doit nécéssairement débuter par un autre langage que le C ? Java est-il un bon exemple ?
                          • Partager sur Facebook
                          • Partager sur Twitter
                            20 avril 2006 à 19:41:16

                            Citation : StraToN

                            Ceci dit, pour qu'un programmeur ne soit plus débutant, il faut qu'il pratique. Est ce que tu veux dire que le débutant doit nécéssairement débuter par un autre langage que le C ? Java est-il un bon exemple ?


                            Je le pense, oui. Java, un peu tordu... De mon temps, la réference c'était le Pascal (Turbo Pascal actually). Typage fort, compilateur intraitable, puissant, rapide...
                            • Partager sur Facebook
                            • Partager sur Twitter
                            Music only !

                            La fonction refuse d'accéder à un champ du struct

                            × 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