Partage
  • Partager sur Facebook
  • Partager sur Twitter

Déclaration d'un tableau de pointeurs avec malloc.

Sujet résolu
    3 décembre 2021 à 13:54:15

    Bonjour,

    Je cherche à créer un tableau de pointeurs (en C) avec malloc().

    J'utilise la syntaxe :

    int **mon_tableau = malloc(sizeof(int*));

    Mais j'ai trouvé sur internet une syntaxe différente :

    int **mon_tableau = (int **)malloc(sizeof(int*));

    La différence étant dans la présence du "(int **)" avant malloc.

    Auriez-vous une idée de ce que ca peut changer ?

    Merci de votre aide,


    -
    Edité par Paresseux121 3 décembre 2021 à 13:54:34

    • Partager sur Facebook
    • Partager sur Twitter
      3 décembre 2021 à 13:58:03

      Salut,

      ça ne change rien, c'est un cast explicite. C'est pour que ce soit compatible en C++.

      malloc renvoie void*, et tu peux ranger ça dans n'importe quel type de pointeur en C directement.

      En C++, il faut être explicite (mais en C++ on évite malloc normalement).

      • Partager sur Facebook
      • Partager sur Twitter

      Recueil de code C et C++  http://fvirtman.free.fr/recueil/index.html

        3 décembre 2021 à 14:04:32

        Je confirme, ça ne change rien. En C il faut utiliser la première syntaxe :

        int** mon_tableau = malloc(sizeof(int*));



        • Partager sur Facebook
        • Partager sur Twitter
        ...
          3 décembre 2021 à 14:10:26

          D'accord, merci du renseignement ! :)
          • Partager sur Facebook
          • Partager sur Twitter
            3 décembre 2021 à 14:15:25

            J'ajoute juste que la seconde syntaxe n'est vraiment celle du C++.
            int** mon_tableau = (int**)malloc(sizeof(int*));     // Ça ça marche en C et C++, ça serait pour du code à utiliser dans les 2 langages
            
            auto  mon_tableau = static_cast<int**>(malloc(sizeof(int*)));  // Ça c'est avec un cast C++
            
            int** mon_tableau = malloc(sizeof(int*));     // Ça c'est ce qu'il faut faire en C
            • Partager sur Facebook
            • Partager sur Twitter

            En recherche d'emploi.

              3 décembre 2021 à 14:18:33

              En effet, c'est bon à savoir, ca peut en aider plus d'un !

              (psss.. ou est passé la bouton pour mettre le sujet en "résolu" ? je ne vois rien)

              • Partager sur Facebook
              • Partager sur Twitter
                3 décembre 2021 à 15:25:06

                Dalfab a écrit:

                J'ajoute juste que la seconde syntaxe n'est vraiment celle du C++.

                int** mon_tableau = (int**)malloc(sizeof(int*));     // Ça ça marche en C et C++, ça serait pour du code à utiliser dans les 2 langages
                
                auto  mon_tableau = static_cast<int**>(malloc(sizeof(int*)));  // Ça c'est avec un cast C++
                
                int** mon_tableau = malloc(sizeof(int*));     // Ça c'est ce qu'il faut faire en C


                Alors, celui qui utilise malloc en C++ ancien mérite déjà des coups de fouet.

                Mais celui qui utilise du C++ moderne avec des static_cast, des auto, et des malloc, la il mérite un supplice plus important !

                • Partager sur Facebook
                • Partager sur Twitter

                Recueil de code C et C++  http://fvirtman.free.fr/recueil/index.html

                  3 décembre 2021 à 16:54:12

                  Salut Paresseux121,

                  Comme ton titre est "Déclaration d'un tableau de pointeurs avec malloc" je pense qu'il est utile de préciser que :

                  int ** mon_tableau = malloc(sizeof(int *));
                  

                  ne déclare pas un type tableau de pointeurs, mais un type pointeur sur un pointeur sur int, et que malloc, ici, n'alloue de la mémoire que pour stocker l'adresse d'un seul pointeur sur int, ce qui ne permet pas de s'en servir avec l'opérateur [] pour itérer dans une liste de pointeurs sur int sur une zone contiguë de mémoire comme s'il s'agissait d'un tableau.

                  • Partager sur Facebook
                  • Partager sur Twitter
                    3 décembre 2021 à 17:57:01

                    Salut Dlks,

                    C'est vachement intéressant ! Moi qui était entrain de continuer mon programme en me rendant compte que ce dernier plantait lorsque à certains moment l'opérateur"[]" faisait planter mon programme -_-

                    J'ai du mal à expliquer, mais je compte faire comme dans cet exemple, avec ce fameux tableau de pointeurs qui permet enfait de se "faire passer" pour un tableau à double entrée, car il redirige vers un tableau plus grand qui va stoquer toutes nos valeurs.

                    Du coup, dans ce cas quelle déclaration est-il préférable de faire pour que tout fonctionne ?

                    Merci de ton aide,

                    • Partager sur Facebook
                    • Partager sur Twitter
                      3 décembre 2021 à 18:46:22

                      Ton exemple est un peu particulier "Allocation avec seulement deux malloc".

                      Essais déjà de faire un tableau de tableau (tableau à 2 dimensions) d'entier alloué avec malloc "de façon classique" et montre nous le code. 

                      (Si tu veux faire comme l'exemple, il donne la solution, hormis qu'il ne faut pas les casts).  

                      • Partager sur Facebook
                      • Partager sur Twitter
                      ...
                        3 décembre 2021 à 19:14:03

                        @Paresseux121 :

                        Si tu veux stocker plus d'un pointeur sur int, tu dois réserver autant d'espace que nécessaire pour stocker le nombre de pointeurs sur int que tu veux stocker. par exemple, pour en stocker 10 :

                        int ** mon_tableau = malloc(sizeof(int *) * 10);
                        

                        A condition d'y avoir mis des adresses pointant sur quelque chose d'existant, en faisant mon_tableau[4] tu accéderas à un pointeur sur int que tu pourras déréférencer pour accéder un int. Ce tableau sera à une seule dimension, qui permet d'accéder à un pointeur sur int.

                        Maintenant, ton lien dans ton dernier message suggère que tu recherches une méthode pour créer une sorte de tableau dynamique à deux dimensions de int, alloué dynamiquement avec malloc, est-ce ce que tu veux faire ?

                        Le problème avec la méthode fournie sur ce lien (les deux) est que le tableau créé ne va pas contenir les éléments dans une zone contiguë de mémoire, car il alloue d'abord la mémoire pour le nombre de lignes du tableau (un malloc pour stocker nb_de_lignes pointeurs), puis le nombre de colonnes (avec un seul malloc ou avec nb_de_lignes appels à malloc pour stocker le nombres de colonnes de int nécessaire). En faisant cela, tu ne pourras pas utiliser le "tableau" avec un memcpy() dessus pour en faire une copie, ni l'initialiser avec memset().

                        Pour obtenir quelque chose qui ressemble à un tableau, tu peux déclarer :

                        int (*tableau2D)[colonnes] = malloc(lignes * sizeof(*tableau2D));
                        

                        Par exemple :

                        #include <stdio.h>
                        #include <stdlib.h>
                        #include <string.h>
                        
                        int main(void)
                        {
                                size_t colonnes = 5;
                                size_t lignes = 2;
                                int truc = 0;
                        
                                int (*tableau2D_dyn)[colonnes] = malloc(lignes * sizeof(*tableau2D_dyn));
                                for (size_t i = 0; i < lignes; i++)
                                        for (size_t j = 0; j < colonnes; j++)
                                                tableau2D_dyn[i][j] = truc++;
                        
                                int tableau_statique[2][5];
                                memcpy(tableau_statique, tableau2D_dyn, lignes * colonnes * sizeof(int));
                        
                                free(tableau2D_dyn);
                        
                                for (size_t i = 0; i < lignes; i++) {
                                        for (size_t j = 0; j < colonnes; j++)
                                                printf("%d\t", tableau_statique[i][j]);
                                        printf("\n");
                                }
                        
                            return 0;
                        }
                        

                        -
                        Edité par Dlks 3 décembre 2021 à 19:15:39

                        • Partager sur Facebook
                        • Partager sur Twitter
                          3 décembre 2021 à 19:14:22

                          Hello,

                          Juste pour information: tu parles de créer une matrice avec seulement deux malloc, mais il y a aussi moyen de le faire avec un seul malloc.... (bon, ça s'utilise aussi un peu différement qu'avec un adressage [x][y])

                          -
                          Edité par edgarjacobs 3 décembre 2021 à 19:22:14

                          • Partager sur Facebook
                          • Partager sur Twitter

                          On écrit "j'ai tort", pas "tord" qui est le verbe "tordre" à la 3ème personne de l'indicatif présent

                            3 décembre 2021 à 19:59:47

                            Si on a nbLignes lignes et nbColonnes, on peut faire:
                            int *tableau = malloc(nbLignes * nbColonnes * sizeof(int));
                            et on accède à la position [i][j] comme suit:
                            valeur = tableau[nbColonnes * i + j];

                            Pour un tableau à 4 dimensions dont les dimensions sont d1, d2, d3,d4
                            Si on veut accéder à la position [i1][i2][i3][i4[:
                            valeur = tableau[d2*d3*d4*i1 + d3*d4*i2 + d4*i3 + i4];
                            Ça prend moins de mémoire mais ça prend plus de calculs pour accéder à une position.

                            -
                            Edité par PierrotLeFou 3 décembre 2021 à 20:13:19

                            • Partager sur Facebook
                            • Partager sur Twitter

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

                              4 décembre 2021 à 15:30:18


                              Re tout le monde,

                              merci de votre aide !


                              rouIoude a écrit:

                              Ton exemple est un peu particulier "Allocation avec seulement deux malloc".

                              Essais déjà de faire un tableau de tableau (tableau à 2 dimensions) d'entier alloué avec malloc "de façon classique" et montre nous le code. 

                              (Si tu veux faire comme l'exemple, il donne la solution, hormis qu'il ne faut pas les casts).  


                              @rouIoude C'est justement ma question, c'est ca que je cherchais à créer. Un tableau à double entrée alloué avec malloc().

                              C'est à ce moment-là que j'ai trouvé une solution qui se trouvait dans le lien que j'ai envoyé précedemment, et que je vous ai demandé de l'aide.

                              Dlks a écrit:

                              @Paresseux121 :

                              Si tu veux stocker plus d'un pointeur sur int, tu dois réserver autant d'espace que nécessaire pour stocker le nombre de pointeurs sur int que tu veux stocker. par exemple, pour en stocker 10 :

                              int ** mon_tableau = malloc(sizeof(int *) * 10);
                              

                              A condition d'y avoir mis des adresses pointant sur quelque chose d'existant, en faisant mon_tableau[4] tu accéderas à un pointeur sur int que tu pourras déréférencer pour accéder un int. Ce tableau sera à une seule dimension, qui permet d'accéder à un pointeur sur int.

                              Maintenant, ton lien dans ton dernier message suggère que tu recherches une méthode pour créer une sorte de tableau dynamique à deux dimensions de int, alloué dynamiquement avec malloc, est-ce ce que tu veux faire ?

                              Le problème avec la méthode fournie sur ce lien (les deux) est que le tableau créé ne va pas contenir les éléments dans une zone contiguë de mémoire, car il alloue d'abord la mémoire pour le nombre de lignes du tableau (un malloc pour stocker nb_de_lignes pointeurs), puis le nombre de colonnes (avec un seul malloc ou avec nb_de_lignes appels à malloc pour stocker le nombres de colonnes de int nécessaire). En faisant cela, tu ne pourras pas utiliser le "tableau" avec un memcpy() dessus pour en faire une copie, ni l'initialiser avec memset().

                              Pour obtenir quelque chose qui ressemble à un tableau, tu peux déclarer :

                              int (*tableau2D)[colonnes] = malloc(lignes * sizeof(*tableau2D));

                               @Dlks C'est une méthode qui correspond bien à mon usage d'un tableau à double entrée !

                              Tes explications sont très utiles, cependant comment fait-on pour passer le tableau alloué avec malloc() dans une fonction ?

                              (excuse-moi si ca se trouve c'est vachement évient mais je suis passé à côté malgré les tests de mon côté ^^)

                              PierrotLeFou a écrit:

                              Si on a nbLignes lignes et nbColonnes, on peut faire:
                              int *tableau = malloc(nbLignes * nbColonnes * sizeof(int));
                              et on accède à la position [i][j] comme suit:
                              valeur = tableau[nbColonnes * i + j];

                              Pour un tableau à 4 dimensions dont les dimensions sont d1, d2, d3,d4
                              Si on veut accéder à la position [i1][i2][i3][i4[:
                              valeur = tableau[d2*d3*d4*i1 + d3*d4*i2 + d4*i3 + i4];
                              Ça prend moins de mémoire mais ça prend plus de calculs pour accéder à une position.

                              -
                              Edité par PierrotLeFou il y a environ 18 heures

                               C'est aussi quelque chose de possible, mais je l'utiliserai pas malheureusement si il existe plus obtimisé aux niveau des instructions processeur :)





                              -
                              Edité par Paresseux121 4 décembre 2021 à 15:30:54

                              • Partager sur Facebook
                              • Partager sur Twitter
                                4 décembre 2021 à 16:30:44

                                Salut Paresseux121,

                                Une façon de le faire tout en préservant une certaine flexibilité à ton code et en permettant l'usage de la notation [x][y] dans la fonction est de déclarer ton prototype de fonction avec la notation VLA permise par le C99 :

                                #include <stdio.h>
                                #include <stdlib.h>
                                #include <string.h>
                                
                                void print_array(size_t lignes, size_t colonnes, int array[][colonnes]) {
                                        for (size_t i = 0; i < lignes; i++) {
                                                for (size_t j = 0; j < colonnes; j++)
                                                        printf("%d\t", array[i][j]);
                                                printf("\n");
                                        }
                                }
                                
                                int main(void)
                                {
                                        size_t colonnes = 5;
                                        size_t lignes = 2;
                                        int truc = 0;
                                
                                        int (*tableau2D_dyn)[colonnes] = malloc(lignes * sizeof(*tableau2D_dyn));
                                        for (size_t i = 0; i < lignes; i++)
                                                for (size_t j = 0; j < colonnes; j++)
                                                        tableau2D_dyn[i][j] = truc++;
                                
                                        printf("Contenu de tableau2D_dyn :\n");
                                        print_array(lignes, colonnes, tableau2D_dyn);
                                
                                        int tableau_statique[2][5];
                                        memcpy(tableau_statique, tableau2D_dyn, lignes * colonnes * sizeof(int));
                                
                                        free(tableau2D_dyn);
                                
                                        printf("Contenu de tableau_statique :\n");
                                        print_array(lignes, colonnes, tableau_statique);
                                
                                    return 0;
                                }
                                

                                Ce prototype fonctionne que le tableau 2D soit alloué dynamiquement ou statiquement et quelle que soit la dimension du tableau :

                                $ gcc -Wall -Werror temp.c 
                                $ ./a.out 
                                Contenu de tableau2D_dyn :
                                0	1	2	3	4	
                                5	6	7	8	9	
                                Contenu de tableau_statique :
                                0	1	2	3	4	
                                5	6	7	8	9	
                                $ 
                                

                                Ce code, ainsi que mon précédent code, suppose que tu puisses utiliser un compilateur respectant la norme C99.

                                -
                                Edité par Dlks 4 décembre 2021 à 16:31:47

                                • Partager sur Facebook
                                • Partager sur Twitter
                                  4 décembre 2021 à 16:31:44

                                  Voici ma petite recette. Je n'ai pas mis la vérification de la réservation avec malloc.
                                  int **tableau = malloc(nbLignes * sizeof(int *));
                                  for(int i=0; i < nbLignes; i++) {
                                      tableau[i] = malloc(nbColonnes * sizeof(int));
                                  }
                                  Tu peux faire ensuite:
                                  tableau[i][j] = valeur;
                                  Pour passer un tel tableau à une fonction, il doit être déclaré int **tableau dans le prototype.
                                  Et tu devras passer les deux dimensions à la fonction.

                                  Pour rendre le code plus lisible, j'utilise une fonction qui appelle malloc:
                                  void *getArea(char *name, int size) {   // name est une chaîne donnant généralement le nom de la fonction appelante.
                                      void *area = malloc(size);
                                      if(area) return area;
                                      perror(name);   // requiere errno.h ou stdlib.h
                                      printf("Required: %d\n", size);
                                      exit(EXIT_FAILURE);   // requière stdlib.h
                                  }
                                  Ici on pourrait l'appeler comme suit:
                                  int **tableau = getArea("main", nbLignes*sizeof(int *));

                                  -
                                  Edité par PierrotLeFou 4 décembre 2021 à 16:46:54

                                  • Partager sur Facebook
                                  • Partager sur Twitter

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

                                    4 décembre 2021 à 18:13:09

                                    Paresseux121 a écrit:

                                    @rouIoude C'est justement ma question, c'est ca que je cherchais à créer. Un tableau à double entrée alloué avec malloc().

                                    C'est à ce moment-là que j'ai trouvé une solution qui se trouvait dans le lien que j'ai envoyé précedemment, et que je vous ai demandé de l'aide.

                                    Et alors ?

                                    La solution du lien ne te convient pas ? Ou est-ce autre chose ? 

                                    Poste ton code, ça sera plus facile pour te guider et on comprendra mieux ce que tu ne comprends pas.

                                    • Partager sur Facebook
                                    • Partager sur Twitter
                                    ...
                                      5 décembre 2021 à 3:05:09

                                      Tant qu'on a affaire à des pointeurs on peut tricher le compilateur sur le type véritable du pointeur.
                                      Voici un exemple d'une fonction récursive qui permet d'alouer de la mémoire pour un tableau de n'importe quelles dimensions.
                                      Ça coûte cher de mémoire mais c'est assez rapide.
                                      -
                                      #include <stdio.h>
                                      #include <stdlib.h>
                                      typedef int type;
                                      void *getArea(char *name, int size) {
                                          void *area = malloc(size);
                                          if(area) return area;
                                          perror(name);
                                          printf("Required: %d\n", size);
                                          exit(EXIT_FAILURE);
                                      }
                                      type **hyperMatrix(int *dimensions, int nDim) {
                                          if(nDim <= 1) {
                                              type**matrix = getArea("hyperMatrix", *dimensions * sizeof(type));
                                              return matrix;
                                          } else {
                                              type **matrix = getArea("hyperMatrix", *dimensions * sizeof(type*));
                                              for(int i = 0; i < *dimensions; i++) {
                                                  matrix[i] = (type*) hyperMatrix(dimensions+1, nDim - 1);
                                              }
                                              return matrix;
                                          }
                                      }
                                      int main(void) {
                                          int adim[4] = {10, 10, 10, 10};
                                          type ****matrice = (type****) hyperMatrix(adim, 4);
                                          for(int i = 0; i < adim[0]; i++) {
                                              for(int j = 0; j < adim[1]; j++) {
                                                  for(int k = 0; k < adim[2]; k++) {
                                                      for(int l = 0; l < adim[3]; l++) {
                                                          matrice[i][j][k][l] = 0;
                                                      } // l
                                                  } // k
                                              } // j
                                          } // i
                                          printf("Initialisation complétée\n");
                                          return 0;
                                      }

                                      -
                                      Edité par PierrotLeFou 5 décembre 2021 à 3:42:43

                                      • Partager sur Facebook
                                      • Partager sur Twitter

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

                                        6 décembre 2021 à 9:31:09

                                        Paresseux121 a écrit:


                                        Re tout le monde,

                                        merci de votre aide !


                                        rouIoude a écrit:

                                        Ton exemple est un peu particulier "Allocation avec seulement deux malloc".

                                        Essais déjà de faire un tableau de tableau (tableau à 2 dimensions) d'entier alloué avec malloc "de façon classique" et montre nous le code. 

                                        (Si tu veux faire comme l'exemple, il donne la solution, hormis qu'il ne faut pas les casts).  


                                        @rouIoude C'est justement ma question, c'est ca que je cherchais à créer. Un tableau à double entrée alloué avec malloc().

                                        C'est à ce moment-là que j'ai trouvé une solution qui se trouvait dans le lien que j'ai envoyé précedemment, et que je vous ai demandé de l'aide.

                                        Bonjour,

                                        Alors première chose : les tableaux «multidimensionnels» n'existent pas en C. Tu auras toujours à faire à des tableaux de tableaux de tableaux de … d'éléments de type T.

                                        Il y a en gros 2 familles de  méthodes différentes qui ont chacune leurs avantages et inconvénients. En 2d cela donnerait :

                                        • Le classique tableau de tableau.

                                        Ici tu considères un tableau 2D comme un tableau de pointeurs chacun pointant vers un tableau. Le premier tableau contient des pointeurs sur des tableaux qui représentent les lignes, chaque tableau ligne contenant autant d'éléments que de colonnes.

                                        C'est le plus classique, on le retrouve souvent.

                                        int **array = malloc( nb_lignes * ( sizeof *array ) );
                                        
                                        for(size_t i=0; i<nb_lignes ; i++)
                                            array[i] = malloc( nb_cols * sizeof( *array[0] ) );
                                        
                                        for(size_t i=0; i<nb_lignes; i++)
                                            for(size_t j=0; j<nb_cols; j++)
                                                array[i][j] = blablabla;

                                        Il y a plusieurs inconvénients : la non localité des données qui pourront se retrouver dispersées en mémoire ce qui va empêcher d'avoir le gain de la mise en cache ;  il y a beaucoup de malloc ce qui sur les petites plateformes est rédhibitoire ou ce qui rend les libérations mémoire plus fastidieuses (à chaque malloc son free).

                                         Un avantage est qu'il permet d'avoir des lignes de longueurs différentes. Par exemple un tableau de Pascal sera un peu plus compact. Tu peux également facilement le redimensionner.

                                        • Le pointeur sur un tableau

                                        Ici tout est plus simple :

                                        int (*array)[nb_lig][nb_col] = malloc( sizeof *array );

                                        Tu alloues toute la mémoire d'un coup, il y aura localité. Un malloc signifie un free …

                                        Un inconvénient : la lourdeur d'écriture. Comme array est maintenant un pointeur sur un tableau il va toujours falloir le déréférencer :

                                        ...
                                           for(size_t i=0; i<nb_lig; i++) {
                                                for(size_t j=0; j<nb_col; j++) {
                                                    printf("%d ", (*array)[i][j]);
                                                }
                                                putchar('\n');
                                            }
                                        ...

                                        Le redimensionnement n'est pas facile.

                                        Le lien que tu nous a donné est en fait ce qui se faisait avant C99 (il y a donc plus de 22 ans maintenant). 

                                        • Partager sur Facebook
                                        • Partager sur Twitter
                                          7 décembre 2021 à 21:34:34

                                          Bonsoir,

                                          Merci ! Toutes vos idées sont intéressantes.

                                          A présent j'ai compris comment fonctionnais tout ca et j'ai pu l'inclure dans mon programme (n'hésitez pas si vous voulez le voir).

                                          Mon problème est donc résolu.

                                          Encore une fois (je ne le dirai jamais assez lol) merci, de vous êtes donné la peine de rédiger des gros pavés pour m'aider :p

                                          • Partager sur Facebook
                                          • Partager sur Twitter

                                          Déclaration d'un tableau de pointeurs avec malloc.

                                          × 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