Partage
  • Partager sur Facebook
  • Partager sur Twitter

Fonction qui créer un tab 2D de taille x

Fonction qui créer un tab de struct 2D de taille donnée en paramètres

    5 juin 2022 à 12:15:49

    Bonjour,

    J'aurai besoin de votre aide pour pouvoir coder ma fonction qui va créer un tableau de structures à deux dimensions.

    Le tableau sera soit de 9x9 ou soit de 16x16, taille indiquée par l'utilisateur avant de créer le tableau.

    Voici ma structure :

    typedef struct{
           int etat;
           int bomb;
           char contenu;
    } tabstr;

     Si cela vous aide à comprendre ma requête, voici mon code bien évidemment faux :

    tabstr crea_grillle(int x){
           tabstr grille[x][x];
           for (int i=0; i < x;i++){
                  for (int j=0; j < x; j++){
                         grille[i][j].contenu = '0';
                         grille[i][j].etat = 0;
                         grille[i][j].bomb = 0;
                  }
           }
           return grille[x][x];
    }
    
    int main(){
           tab grille;
           grille = crea_grille(9); // j'essaie donc de créer                             un tableau 9x9
           return 0;
    
    }



    -
    Edité par dyd 5 juin 2022 à 12:23:33

    • Partager sur Facebook
    • Partager sur Twitter
      5 juin 2022 à 13:42:48

      Plusieurs erreur dans ton code :

      - ligne 14 le type tab n'existe pas ! (probablement que tu voulais utiliser le type tabstr) ?

      - ligne 10 tu retourne une case extérieur à ton tableau ! Probablement que tu voulais retourner le tableau, or en C, il n'est pas possible de retourner un tableau* seulement son adresse. Tout en sachant que retourner l'adresse d'un tableau local à la fonction est une erreur car le tableau n'existe plus hors de la fonction.

      - Si tu souhaites créer ton tableau dans une fonction, il va falloir utiliser l'allocation dynamique avec malloc !

      * sauf s'il est un champ d'une structure.

      • Partager sur Facebook
      • Partager sur Twitter
      ...
        5 juin 2022 à 14:46:01

        Ou alors déclarer un tableau de taille fixe égale à 16 (le maxi possible).

         tabstr grille[16][16];
               for (int i=0; i < x;i++){ /* etc. */}
               return grille;

        Il faudra juste faire attention à ne pas perdre en route la taille réellement utilisée (la mettre dans une variable, ou bien l'adjoindre au tableau dans une structure).

        -
        Edité par robun 5 juin 2022 à 14:46:48

        • Partager sur Facebook
        • Partager sur Twitter
          5 juin 2022 à 15:09:44

          @robun

          rouIoude a écrit:

          Tout en sachant que retourner l'adresse d'un tableau local à la fonction est une erreur car le tableau n'existe plus hors de la fonction.



          • Partager sur Facebook
          • Partager sur Twitter
          ...
            5 juin 2022 à 17:01:55

            Bon, à mon avis le problème vient d'un manque de vocabulaire. Le verbe "créer" est utilisé en long en large et à travers, sans exprimer réellement ce qu'on veut faire : déclarer, définir, réserver, allouer, initialiser etc.

            1. Quand je vois

            int main(){
                   tab grille;
                   grille = crea_grille(9); // j'essaie donc de créer un tableau 9x9
             

            je me dis que la variable "grille" a été déclarée, donc y a pas à la créer, mais à l'initialiser.

            2. Si on on sait que ça représente un tableau dont la taille ne bougera pas ensuite, pourquoi ne pas la déclarer comme telle ?

            struct element {
            	int data;
            };
            
            int main() {
               struct element a2[2][2];
               ...
            
            

            avec tout bêtement sa taille ?

            3. Ensuite il reste à l'initialiser avec ... un appel à une fonction qui sert à initialiser ?

            	init_array(2, a2);

            Un programme pour montrer tout ça :

            #include <stdio.h>
            
            struct element {
            	int data;
            };
            
            void init_array(int size, struct element array[size][size]) {
            	for (int r = 0; r < size; r++) {
            		for (int c = 0; c < size; c++) {
            			array[r][c].data = 10*(r+1) + c + 1;
            		}
            	}
            }
            
            void print_array(int size, struct element array[size][size]) {
            	printf("size %d x %d :\n", size, size);
            	for (int r = 0; r < size; r++) {
            		for (int c = 0; c < size; c++) {
            			printf("%3d", array[r][c].data);
            		}
            		printf("\n");
            	}
            }
            
            int main() {
               struct element a2[2][2];
               struct element a3[3][3];
            
            	init_array(2, a2);
            	init_array(3, a3);
            
            	print_array(2, a2);
            	print_array(3, a3);
            }
            

            Execution

            $ ./prog 
            size 2 x 2 :
             11 12
             21 22
            size 3 x 3 :
             11 12 13
             21 22 23
             31 32 33
            



            ---

            Une autre approche serait de définir un type de données, qui représente un tableau 2D de taille fixée à l'exécution.  Avec des opérations pour

            • initialiser le tableau (en indiquant sa taille) ce qui déclenchera une allocation mémoire
            • consulter/modifier un élément du tableau
            • consulter sa taille
            • libérer la mémoire allouée
            • ...
            C'est dommage de vouloir s'emmerder faire ça en C, ça serait bien plus simple en C++ avec les conteneurs std::vector etc.





            -
            Edité par michelbillaud 5 juin 2022 à 17:08:07

            • Partager sur Facebook
            • Partager sur Twitter
              5 juin 2022 à 17:20:10

              Et si la taille n'est pas connue à la conpilation mais fournie par l'utilisateur à l'éxécution?
              Ça marche des VLA à deux dimensions?
              Sinon, il faut utiliser des malloc dans la fonction de "création et initialisation".
              Et les débutants ne savent pas comment faire. Un "bon" cours le montrerait.
              Pire encore, on peut ramener le tableau 2D à un tableau 1D, mais il faut vraiment savoir comment jouer avec les indices.
              Je demande donc à dyd de préciser ce qu'il veut faire.
              • Partager sur Facebook
              • Partager sur Twitter

              Le Tout est souvent plus grand que la somme de ses parties.

                5 juin 2022 à 17:27:52

                > VLA à deux dimensions

                Testé sur l'appel de test(4), avec la fonction test qui définit un VLA

                void test(int size) {
                    printf("With a VLA\n");
                    struct element array[size][size];
                    init_array(size, array);
                    print_array(size, array);
                }

                Execution

                With a VLA
                size 4 x 4 :
                 11 12 13 14
                 21 22 23 24
                 31 32 33 34
                 41 42 43 44
                


                L'allocation dynamique + la linearisation, ça me parait un "overkill" pour l'instant.  On en est à vouloir initialiser des grilles, c'est tout.



                -
                Edité par michelbillaud 5 juin 2022 à 17:31:59

                • Partager sur Facebook
                • Partager sur Twitter
                  5 juin 2022 à 17:42:27

                  Sauf qu'il faut préciser que le tableau devrait être "déclaré" dans le main et "initialisé" dans la fonction.

                  Et ça doit se faire "après" avoir saisi les dimensions.

                  Et comment tu passes les dimensions à la fonctions?

                  Les boucles devraient être dans le main et la fonction initialise une seule structure.

                  -
                  Edité par PierrotLeFou 5 juin 2022 à 18:01:51

                  • Partager sur Facebook
                  • Partager sur Twitter

                  Le Tout est souvent plus grand que la somme de ses parties.

                    5 juin 2022 à 17:55:18

                    rouIoude a écrit:

                    @robun

                    rouIoude a écrit:

                    Tout en sachant que retourner l'adresse d'un tableau local à la fonction est une erreur car le tableau n'existe plus hors de la fonction.



                    Ah oui ! Le tableau doit être un paramètre de la fonction de création. (C'est ce qu'on fait en général. Moralité : ne pas chercher à être original...)

                    --------

                    Un paramètre de la fonction d'initialisation. Les précisions de michelbillaud sont importantes et aident à savoir ce qu'on fait.

                    -
                    Edité par robun 5 juin 2022 à 17:59:07

                    • Partager sur Facebook
                    • Partager sur Twitter
                      5 juin 2022 à 18:22:06

                      J'ai écrit du code simplifié pour initiialiser un tableau 2D défini avec une VLa:
                      -
                      #include <stdio.h>
                      /*
                      typedef struct{
                          int etat;
                          int bomb;
                          char contenu;
                      } tabstr;
                      */
                      typedef int tabstr;
                       

                      // La longueur doit être précisée avant le tableau.
                      void initialiser(int size, tabstr tab[size][size]) {
                          for(int i=0; i<size; i++) {
                              for(int j=0; j<size; j++) {
                                  tab[i][j] =(i+1)*10+j+1;
                              }
                          }
                      }
                       
                      int main(void) {
                          int size = 4;
                          tabstr tab[size][size];
                          initialiser(size, tab);
                          for(int i=0; i<size; i++) {
                              for(int j=0; j<size; j++) {
                                  printf("%d ", tab[i][j]);
                              }
                              printf("\n");
                          }
                          return 0;
                      }

                      -
                      Edité par PierrotLeFou 5 juin 2022 à 18:42:13

                      • Partager sur Facebook
                      • Partager sur Twitter

                      Le Tout est souvent plus grand que la somme de ses parties.

                        5 juin 2022 à 20:01:07

                        Sinon, si on part sur l'idée d'une structure qui contient la représentation d'un tableau de taille arbitraire, on peut se taper l'allocation et la linéarisation.

                        #include <stdio.h>
                        #include <stdlib.h>
                        
                        struct element {
                            int data;
                        };
                        
                        struct grid {
                            int size;
                            struct element *array;
                        };
                        
                        
                        void grid_set(struct grid *g, int r, int c, struct element e) {
                            g->array[r * g->size + c] = e;
                        }
                        
                        struct element grid_get(struct grid *g, int r, int c) {
                            return g->array[r * g->size + c];
                        }
                        
                        
                        void init_grid(int size, struct grid *g) {
                            g->size = size;
                            g->array = malloc(size * size *sizeof(struct element));
                        
                            for (int r = 0; r < size; r++) {
                                for (int c = 0; c < size; c++) {
                                    grid_set(g, r, c, (struct element) {
                                        .data = 10*(r+1) + c + 1}
                                        );
                                }
                            }
                        }
                        
                        
                        void delete_grid(struct grid *g) {
                            free(g->array);
                            g->array = NULL;
                            g->size = 0;
                        }
                        
                        void print_grid(struct grid * g)
                        {
                            printf("grid with size %d x %d :\n", g->size, g->size);
                            for (int r = 0; r < g->size; r++) {
                                for (int c = 0; c < g->size; c++) {
                                    printf("%3d", grid_get(g, r, c).data);
                                }
                                printf("\n");
                            }
                        }
                        
                        void test_grid(int size) {
                            struct grid grid;
                            init_grid(size, & grid);
                            print_grid(& grid);
                            delete_grid(& grid);
                        }
                        
                        int main()
                        {
                            test_grid(3);
                            test_grid(4);
                        }
                        
                        

                        Execution garantie sans fuite

                        $ valgrind ./prog 
                        ==17737== Memcheck, a memory error detector
                        ==17737== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
                        ==17737== Using Valgrind-3.16.1 and LibVEX; rerun with -h for copyright info
                        ==17737== Command: ./prog
                        ==17737== 
                        grid with size 3 x 3 :
                         11 12 13
                         21 22 23
                         31 32 33
                        grid with size 4 x 4 :
                         11 12 13 14
                         21 22 23 24
                         31 32 33 34
                         41 42 43 44
                        ==17737== 
                        ==17737== HEAP SUMMARY:
                        ==17737==     in use at exit: 0 bytes in 0 blocks
                        ==17737==   total heap usage: 3 allocs, 3 frees, 1,124 bytes allocated
                        ==17737== 
                        ==17737== All heap blocks were freed -- no leaks are possible
                        ==17737== 
                        ==17737== For lists of detected and suppressed errors, rerun with: -s
                        ==17737== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)


                        ---

                        Remarques

                        1. Un truc amusant (?), c'est que dans quasiment tous les cours/tutoriels que j'ai vu sur ce sujet de l'allocation dynamique, le type se sent obligé de faire une fonction pour allouer la structure "principale" : celle qui s'appelle "grid" ici, ou la structure list pour les chainages.

                        Ca vient probablement d'une obstination à persister dans la confusion douteuse entre liste et pointeur d'élément. En réalité L'allocation est nécessaire pour les maillons de la liste, ça n'oblige en rien d'allouer dynamiquement la structure de départ...

                        2. Maintenant qu'on a des structures, on peut  aussi les retourner et faire une initialisation par affectation

                        void test_grid(int size) {
                        
                            struct grid grid = build_grid(size);
                        
                            print_grid(& grid);
                            delete_grid(& grid);
                        }

                        avec

                        struct grid build_grid(int size) {
                            struct grid grid;
                            init_grid(size, &grid);
                            return grid;
                        }

                        3. Comme Noel approche, on peut aussi revoir les accesseurs

                        struct element * grid_at(struct grid *g, int r, int c) {
                            return  & (g->array[r * g->size + c])
                        }
                        
                        void grid_set(struct grid *g, int r, int c, struct element e) {
                            *grid_at(g, r, c) = e;
                        }
                        
                        struct element grid_get(struct grid *g, int r, int c) {
                            return *grid_at(g,r,c);
                        }
                        


                        Avec l'inlining tout devrait se passer très bien.




                        -
                        Edité par michelbillaud 5 juin 2022 à 20:22:52

                        • Partager sur Facebook
                        • Partager sur Twitter
                          5 juin 2022 à 21:57:51

                          Bonjour,

                          michelbillaud a écrit:

                          Sinon, si on part sur l'idée d'une structure qui contient la représentation d'un tableau de taille arbitraire, on peut se taper l'allocation et la linéarisation.
                          [...]

                          Alors oui … je dirai presque «évidemment». Ça sent fortement le TP sur le démineur, et à partir de là si on a envie d'avoir une modélisation propre il faut avoir quelque chose qui représente le plateau de jeu.

                          dyd a écrit:

                          Bonjour,

                          J'aurai besoin de votre aide pour pouvoir coder ma fonction qui va créer un tableau de structures à deux dimensions.

                          Le tableau sera soit de 9x9 ou soit de 16x16, taille indiquée par l'utilisateur avant de créer le tableau.

                          [...]

                          Ici on clairement un besoin réduit. Et tant qu'à faire autant se simplifier la vie comme propose Robun :

                          robun a écrit:

                          Ou alors déclarer un tableau de taille fixe égale à 16 (le maxi possible).[...]

                          On peut aisément commencer par un :

                          #define BOARD_MAX_SIZE ((size_t)16)
                          
                          struct board {
                              size_t size;
                              struct cell data[BOARD_MAX_SIZE+2][BOARD_MAX_SIZE+2];
                              …
                          };

                          Ici j'ajoute 2 à chaque dimension dans le but d'avoir une couronne de cellule particulière hors-jeu pour s'affranchir de certains tests pour vérifier si l'on se trouve en bord de plateau.

                          Dans le cadre d'un démineur, une cellule pourra soit être un mur (=une cellule de la couronne), soit une cellule vide, soit une cellule piégée. On peut imaginer quelque chose comme :

                          enum cell_kind { CELL_WALL, CELL_EMPTY, CELL_BOMB };
                          
                          struct cell {
                              enum cell_kind kind;
                              …
                          };

                          Si on décide ensuite d'intégrer dans une seule structure non seulement le plateau mais également l'avancement du jeu (même si une structure réservée à l'affichage serait plus classique dans un modèle MVC par exemple) on peut y rajouter :

                          enum cell_status { CS_HIDDEN, CS_SHOWN, CS_FLAGGED };
                          
                          struct cell {
                              enum cell_kind kind;
                              enum cell_status status;
                              …
                          };




                          • Partager sur Facebook
                          • Partager sur Twitter

                          Fonction qui créer un tab 2D de taille x

                          × 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