Partage
  • Partager sur Facebook
  • Partager sur Twitter

Problème pointeur sur tableau 2D

Sujet résolu
    25 juin 2019 à 18:32:57

    Bonjour, j'essaye d'afficher mon tableau 2D en utilisant une fonction mais mon code ne compile pas. J'ai chercher sur plusieurs forum mais je n'arrive pas a trouver la solution. Je pense qu'il faut cree un pointeur vers mon tableau 2D mais je ne sais pas comment m'y prendre, voici mon code :

    #include <stdio.h>
    #include <stdlib.h>
    #define W 40
    #define H 12
    void ligne();
    void create_tab(char **tab);
    
    int main()
    {
    
        char tab2D[H][W];
    
        for (int j=0;j<H;j++)
        {
            for(int i=0;i<W;i++)
            {
                tab2D[j][i] = '.';
            }
        }
    
        create_tab(tab2D);
    
        return 0;
    }
    
    void ligne()
    {
        printf("     ");
    
        for(int i=0;i<W+2;i++)
        {
            printf("#");
        }
        puts("");
    
    }
    
    void create_tab(char **tab)
    {
    
        ligne();
    
        for (int j=0;j<H;j++)
        {
        printf("     #");
            for(int i=0;i<W;i++)
            {
                printf("%c",tab[j][i]);
    
                if (i == W-1) puts("#");
    
            }
    
        }
    
        ligne();
    
    }

    -
    Edité par MrTeed 25 juin 2019 à 18:35:13

    • Partager sur Facebook
    • Partager sur Twitter
    MrTeed
      25 juin 2019 à 18:52:21

      Ton tableau est un tableau de 20 tableaux de 40 char.

      Donc tu envois à la fonction un pointeur sur des tableaux de 40 char,

      Donc le prototype de la fonction devrait être :

      void create_tab(char (*tab)[W]);



      • Partager sur Facebook
      • Partager sur Twitter
        25 juin 2019 à 19:00:41

        rouloude a écrit:

        Ton tableau est un tableau de 20 tableaux de 40 char.

        Donc tu envois à la fonction un pointeur sur des tableaux de 40 char,

        Donc le prototype de la fonction devrait être :

        void create_tab(char (*tab)[W]);



        J'ai remplacé le prototype et effectivement ça fonctionne.

        Mais pour que ça fonctionne j'ai d'abord crée un pointeur sur mon tableau.

            char **pTab = tab2D;
        
            create_tab(pTab);
        


        Pourquoi est ce que j'ai une erreur lorsque que je fais directement :

            create_tab(Tab2D);

        ça devrait fonctionner pourtant ? Ya un truc qui m'échappe...

        Merci pour ta réponse rapide !



        • Partager sur Facebook
        • Partager sur Twitter
        MrTeed
          25 juin 2019 à 20:55:34

              char **pTab = tab2D;

          Ça, ce n'est pas correcte. Tu dois d'ailleurs avoir un warning !

          un pointeur de pointeur sur char, n'est pas fait pour pointer sur un tableau de tableau de char. (un tableau n'est pas un pointeur.)

          Pourquoi tu as une erreur sur create_tab, et bien pour la même raison.



          • Partager sur Facebook
          • Partager sur Twitter
            25 juin 2019 à 21:36:09

            Enfaite oui, j'avais 2 warning.

            Je viens de reessayer avec Tab2D et finalement ça fonctionne... Bizarre ça avait pas fonctionner tout à l'heure.

            En tous cas merci, c'est bon du coup nikel :)

            Juste un dernier truc : J'ai pas compris pourquoi on écrit pas ça 

            void create_tab(char (*tab)[W])

            comme ça

            void create_tab(char *tab[W])

            ou enfaite tout simplement comme ça ?

            void create_tab(char tab[][W])

            Les parenthèses signifie quoi enfaite? 



            • Partager sur Facebook
            • Partager sur Twitter
            MrTeed
              25 juin 2019 à 22:02:05

              Les parenthèses c'est pour dire que c'est un pointeur sur tableau.

              Ta dernière écriture est équivalente à pointeur sur tableau, donc fonctionne aussi.

              • Partager sur Facebook
              • Partager sur Twitter
                27 juin 2019 à 14:53:13

                En général c'est une question de style - un avantage de char tab[][W] c'est que ça implique a priori que ce n'est pas qu'un pointeur de tableau. Après personnellement je n'écris jamais tab[][W] je préfère mettre **tab parce que j'y vois plus clair comme ça (par contre je perds l'info statique que la taille des lignes de tab est W)

                EDIT : comme l'a indiqué rouloude, ce que je viens de dire est une grosse bêtise

                -
                Edité par potterman28wxcv 27 juin 2019 à 17:27:06

                • Partager sur Facebook
                • Partager sur Twitter
                  27 juin 2019 à 16:47:00

                  potterman28wxcv a écrit:

                  En général c'est une question de style - un avantage de char tab[][W] c'est que ça implique a priori que ce n'est pas qu'un pointeur de tableau. Après personnellement je n'écris jamais tab[][W] je préfère mettre **tab parce que j'y vois plus clair comme ça (par contre je perds l'info statique que la taille des lignes de tab est W)

                  Ce n'est pas une question de style : tab[][W] n'est pas équivalent à  **tab ,

                  Un pointeur sur tableau n'est pas un pointeur sur pointeur !

                  • Partager sur Facebook
                  • Partager sur Twitter
                    27 juin 2019 à 16:56:58

                    rouloude a écrit:

                    Les parenthèses c'est pour dire que c'est un pointeur sur tableau.

                    Ta dernière écriture est équivalente à pointeur sur tableau, donc fonctionne aussi.


                    Ah d'accord, je comprend mieux, merci beaucoup :)
                    • Partager sur Facebook
                    • Partager sur Twitter
                    MrTeed
                      27 juin 2019 à 17:26:37

                      rouloude a écrit:

                      potterman28wxcv a écrit:

                      En général c'est une question de style - un avantage de char tab[][W] c'est que ça implique a priori que ce n'est pas qu'un pointeur de tableau. Après personnellement je n'écris jamais tab[][W] je préfère mettre **tab parce que j'y vois plus clair comme ça (par contre je perds l'info statique que la taille des lignes de tab est W)

                      Ce n'est pas une question de style : tab[][W] n'est pas équivalent à  **tab ,

                      Un pointeur sur tableau n'est pas un pointeur sur pointeur !

                      Oui tu as tout à fait raison ! Mea culpa. ça n'a jamais été mon fort les tableaux à plusieurs dimensions.

                      Est-ce que ces deux codes sont équivalents selon toi ? J'ai essayé de regarder l'assembleur généré mais je n'arrive pas à m'en convaincre

                      #define SY 100
                      
                      int f(int *t, int sx){
                          int S = 0;
                          int i, j;
                          for (i = 0 ; i < sx ; i++){
                              for (j = 0 ; j < SY ; j++){
                                  S += t[SY*i+j];
                              }
                          }
                          return S;
                      }
                      
                      int g(int t[][SY], int sx){
                          int S = 0;
                          int i, j;
                          for (i = 0 ; i < sx ; i++){
                              for (j = 0 ; j < SY ; j++){
                                  S += t[i][j];
                              }
                          }
                          return S;
                      }

                      https://godbolt.org/z/zFkF59




                      -
                      Edité par potterman28wxcv 27 juin 2019 à 17:27:27

                      • Partager sur Facebook
                      • Partager sur Twitter
                        27 juin 2019 à 18:35:32

                        A mon avis pas tout à fait, d'ailleurs tu n'envois pas le même type de paramètre à la fonction.

                        Après faut pas toujours ce fier au code généré, selon le contexte et les optimisations le code généré pourrait être le même (j'ai pas vérifié).

                        La fonction f prend le tableau comme s'il était un simple tableau (à une dimension).

                        La fonction f est plus souple car si tu passais les deux tailles en paramètre, tu pourrais traiter des tableaux de tableaux de tailles diverses.

                        • Partager sur Facebook
                        • Partager sur Twitter
                          27 juin 2019 à 22:44:19

                          Bonjour,

                          Oui, les 2 fonctions font la même chose, elles additionnent sx lignes de SY entiers consécutifs. Il y a quand même une différence, le premier paramètre à passer est différent - du moins par le type, mais pas par sa valeur.
                          Et selon toi, la fonction suivante est-elle équivalente, et peut-elle être une optimisation de ton code?

                          int  h( const int *t, int sx ) {
                              int  S = 0;
                              for ( const int* fin = t+sx*SY ; t<fin ; ++t ) {
                                  S += *t;
                              }
                              return  S;
                          }
                          • Partager sur Facebook
                          • Partager sur Twitter
                          Bjarne Stroustrup : "C++ has become too expert friendly"
                            28 juin 2019 à 10:27:32

                            La différence que je vois c'est que tu utilises une seule boucle for au lieu de deux - et tu utilises une variable de moins vu que tu n'as qu'une boucle for au lieu de deux. Par contre c'est pas du tout lisible je trouve, j'aurais personnellement écrit ça plutôt comme ceci :

                            int  h2( const int *t, int sx ) {
                                int  S = 0;
                                for ( int i = 0 ; i < sx*SY ; i++ ) {
                                    S += t[i];
                                }
                                return  S;
                            }

                            Par rapport à toi j'utilise deux temporaires en plus (à la louche) mais au moins ce que la fonction fait est clair.. J'ai tendance à préférer la clarté à la performance (enfin, à partir du moment où ça ne modifie pas la complexité bien sûr).

                            Bon, j'ai été un peu curieux de mesurer tout ça, donc j'ai fait ce programme :

                            #include <time.h>
                            #include <stdlib.h>
                            #include <stdio.h>
                            #include <stdbool.h>
                            
                            #define SY 1000
                            #define SX 1000
                            #define REPEAT 10000
                            
                            int f(const int *t, int sx){
                                int S = 0;
                                int i, j;
                                for (i = 0 ; i < sx ; i++){
                                    for (j = 0 ; j < SY ; j++){
                                        S += t[SY*i+j];
                                    }
                                }
                                return S;
                            }
                            
                            int g(const int t[][SY], int sx){
                                int S = 0;
                                int i, j;
                                for (i = 0 ; i < sx ; i++){
                                    for (j = 0 ; j < SY ; j++){
                                        S += t[i][j];
                                    }
                                }
                                return S;
                            }
                            
                            int  h( const int *t, int sx ) {
                                int  S = 0;
                                for ( const int* fin = t+sx*SY ; t<fin ; ++t ) {
                                    S += *t;
                                }
                                return  S;
                            }
                            
                            int  h2( const int *t, int sx ) {
                                int  S = 0;
                                for ( int i = 0 ; i < sx*SY ; i++ ) {
                                    S += t[i];
                                }
                                return  S;
                            }
                            
                            void test_and_print(char *s, int (*func)(const int *, int), int *t, int sx, bool dry_run){
                              clock_t start, stop;
                              int val;
                              int i;
                            
                              start = clock();
                              for (i = 0; i< REPEAT; i++)
                                val = func(t, sx);
                              stop = clock();
                            
                              if (dry_run)
                                return;
                            
                              printf("%s execution\n", s);
                              printf("\tValue: %d\n", val);
                              printf("\tTime: %ld\n", (stop-start)/REPEAT);
                            }
                            
                            int main(void){
                              srand(time(NULL));
                              
                              int t[SX][SY];
                              for (int i = 0; i < SX; i++)
                                for (int j = 0; j < SY; j++)
                                  t[i][j] = rand();
                            
                              test_and_print("h2", h2, t, SX, true);
                              test_and_print("f", f, t, SX, false);
                              test_and_print("g", g, t, SX, false);
                              test_and_print("h", h, t, SX, false);
                              test_and_print("h2", h2, t, SX, false);
                            
                              return 0;
                            }
                            
                            Je compile en -g -std=c99 -O3 -Wall. Et j'ignore bien gentiment les warnings que ça me donne :p Le compilo me fait bien savoir qu'un "int *" et un "int (*)[1000]" ce n'est pas la même chose.

                            Ce programme va donc répéter 10000 fois le calcul, sur un tableau de 1000*1000

                            Je répète ce programme 3 fois, ça donne :

                            [sixcy@margeriaz:oc] ./2dsum 
                            f execution
                                    Value: 1226605698
                                    Time: 199
                            g execution
                                    Value: 1226605698
                                    Time: 200
                            h execution
                                    Value: 1226605698
                                    Time: 203
                            h2 execution
                                    Value: 1226605698
                                    Time: 195
                            [sixcy@margeriaz:oc] ./2dsum 
                            f execution
                                    Value: -1192628864
                                    Time: 202
                            g execution
                                    Value: -1192628864
                                    Time: 198
                            h execution
                                    Value: -1192628864
                                    Time: 205
                            h2 execution
                                    Value: -1192628864
                                    Time: 194
                            [sixcy@margeriaz:oc] ./2dsum 
                            f execution
                                    Value: -457814823
                                    Time: 195
                            g execution
                                    Value: -457814823
                                    Time: 198
                            h execution
                                    Value: -457814823
                                    Time: 201
                            h2 execution
                                    Value: -457814823
                                    Time: 195
                            

                            La fonction h2 a l'air plus optimisée que les autres de quelques cycles mais c'est pas très marqué non plus. ça fait gagner 3% peut-être ?

                            A noter que si mon tableau est maintenant de 10000 * 1000, je me tape une segmentation fault au niveau du srand(time(NULL)), je penche pour un problème de stack étant donné que ça fait 40 MB allouées sur la stack mais je n'ai pas creusé plus loin..


                            -
                            Edité par potterman28wxcv 28 juin 2019 à 10:35:44

                            • Partager sur Facebook
                            • Partager sur Twitter
                              28 juin 2019 à 18:48:07

                              Bonjour,

                              L'erreur dans mon code est justement d'avoir multiplié les valeurs au lieu de 2 boucles. Car rien ne dit que le produit de 2 int tient dans un int.
                              Les 4 fonctions devraient avoir un code optimisé donnant exactement la même durée, les 2 dernières devraient être égales et mais légèrement différentes des 2 premières pour leur ajouter le bug sur les très grands tableaux. Es-tu sûr d'avoir compilé en Release avec les optimisations en vitesse?

                              • Partager sur Facebook
                              • Partager sur Twitter
                              Bjarne Stroustrup : "C++ has become too expert friendly"
                                28 juin 2019 à 21:29:44

                                Dalfab a écrit:

                                Bonjour,

                                L'erreur dans mon code est justement d'avoir multiplié les valeurs au lieu de 2 boucles. Car rien ne dit que le produit de 2 int tient dans un int.
                                Les 4 fonctions devraient avoir un code optimisé donnant exactement la même durée, les 2 dernières devraient être égales et mais légèrement différentes des 2 premières pour leur ajouter le bug sur les très grands tableaux. Es-tu sûr d'avoir compilé en Release avec les optimisations en vitesse?

                                J'ai compilé en -O3. Pour un utilisateur d'un IDE type Code::Block ça revient effectivement à compiler en Release avec "les optimisations de vitesse".

                                Je ne vois pas de multiplications dans ton code - et quand tu fais ++t tu incrémentes le pointeur t d'une "case" de int, donc tout va bien ?

                                Tu peux tester sur ta machine avec tes propres options de compilation pour voir si t'en viens à la même conclusion que moi

                                -
                                Edité par potterman28wxcv 28 juin 2019 à 21:31:31

                                • Partager sur Facebook
                                • Partager sur Twitter

                                Problème pointeur sur tableau 2D

                                × Après avoir cliqué sur "Répondre" vous serez invité à vous connecter pour que votre message soit publié.
                                • Editeur
                                • Markdown