Tableaux à diverses dimensions avec diverses taille

Bonjour,je veux créer non pas un tableau multidimensionnel mais un tableau du genre:

T=[[1,2,3],[4,1],[1,6,9,0,1]]
T est un tableau composé de 3 sous-tableaux avec chacun leur dimensions
le 1er sous tableau est de taille 3,le 2ieme est de taille 2 et le 3ieme de taille 5

Comment m'y prendre,créer un type qui permet de manipuler un tel type de tableau

Ensuite ,j'aimerais créer une fonction qui ajoute un sous-tableau dans T,une autre qui permet de supprimer un sous-tableau...

26 réponses

Résumé de la discussion

Plusieurs échanges portent sur la création d'un tableau composé de sous-tableaux de tailles différentes et sur la manière de représenter et manipuler un tel tableau en C. Les solutions évoquées incluent l'utilisation d'une structure pour chaque sous-tableau avec une taille dynamique et l'allocation via malloc, ou une approche par tableau de pointeurs vers des sous-tableaux. Des débats apparaissent sur l'emploi de typedef versus struct, sur la meilleure forme d'accès : tableau de structures imbriquées ou tableau de pointeurs vers blocs mémoire, avec opérations d'ajout et de suppression. En pratique, une approche courante consiste à représenter T comme un tableau de pointeurs, chaque pointeur référant un tableau de taille variable, ce qui permet d'ajouter ou retirer des sous-tableaux sans réallocation globale.

Bobot (l’IA à votre service)
  1. Merci pour votre aide,je vais en finir là,j'ai passé trop de temps su cette exo

    Merci encore
    1. Contributeur
      de rien, j'espère que tu auras appris 2 ou 3 trucs qui te serviront :-)

      bon courage pour la suite !
  2. Avant de répondre a votre question ,j'ai remarqué que lorsque je veux tester votre realloc ca marche pas

    #include <stdio.h>
    #include <stdlib.h>
    
    typedef struct tableau {
        int taille;
        int *tab;
        int T_MAX;
    }tableau;
    
    
    
    
    
    
    tableau creer_tab_vide(){
     tableau t;
     t.taille = 0;
     t.T_MAX=10;
     t.tab = malloc(10* sizeof(int));
     return t;
        
        
    }
    tableau ajouter_entier(tableau t,int n){
        int * temp;
         size_t new_T_MAX = 2 * t.T_MAX * sizeof(int);
         temp=realloc(t.tab, new_T_MAX);
         if (temp == NULL) {
              printf("Reallocation impossible : impossible d'ajouter un entier\n");
              return t;
          } else {
              t.tab = temp;
              t.T_MAX =  new_T_MAX;
          }
    
        t.taille=t.taille+1;
        int dernier_indice=t.taille-1;
        
        t.tab[dernier_indice]=n;
        return t;
        
    }
    
    void afficher_tableau(tableau T){
     int i;
     printf(" [");
     for (i = 0; i < T.taille; i++){ 
      
      printf("%d  ",T.tab[i]);
     } 
     printf("]\n");
    }
    
    
    int main(void){
        
        tableau t;
       t=creer_tab_vide();
        t=ajouter_entier(t,1);
        t=ajouter_entier(t,2);
        t=ajouter_entier(t,3);
        t=ajouter_entier(t,4);
        t=ajouter_entier(t,-1);
        t=ajouter_entier(t,6);
        t=ajouter_entier(t,7);
        t=ajouter_entier(t,8);
        t=ajouter_entier(t,-1);
       t=ajouter_entier(t,19);
        afficher_tableau(t);
       return 0;
    }
    
    
    
    
    
    
    


    Ca m'affiche Reallocation impossible : impossible d'ajouter un entier et s'arrete au 2ieme -1 au dela c'est impossible

    Ca marche que a petite échelle
    1. Contributeur
      Mon code ici https://forums.commentcamarche.net/forum/affich-37585534-tableaux-a-diverses-dimensions-avec-diverses-taille?page=2#38 visait à te montrer comment utiliser realloc() dans la partie où tu décides d'augmenter la mémoire dans ton message immédiatement précédent https://forums.commentcamarche.net/forum/affich-37585534-tableaux-a-diverses-dimensions-avec-diverses-taille?page=2#37

      je me suis concentré sur l'usage de realloc() pour bien t'expliquer son fonctionnement, pas sur le reste du code de la fonction.

      Tu dois donc insérer ce code dans le tien, et non pas supprimer la partie de ton code où tu décides si tu as besoin de réallouer ou pas.

      Là, dans ce que tu postes, tu doubles ma mémoire à chaque fois que tu ajoutes un élément (et non pas à chaque fois que tu va dépasser la capacité en éléments T_MAX).
    2. Contributeur
      @[Dal]Après tests, il y a bien un autre bogue, qui est dans le bout de code que j'ai posté et qui devrait être corrigé comme ceci :

           size_t new_T_MAX = 2 * t.T_MAX;
           temp=realloc(t.tab, new_T_MAX * sizeof(int));
           if (temp == NULL) {
                printf("Reallocation impossible : impossible d'ajouter un entier\n");
                return t;
            } else {
                t.tab = temp;
                t.T_MAX =  new_T_MAX;
            }
      


      car T_MAX contient le nombre d'éléments, pas leur taille occupée en mémoire. Cela permet au doublement d'aller moins vite et de se baser correctement sur le nombre d'éléments (lignes 1 et 2 modifiées ci-dessus).

      N'oublie pas de mettre ceci dans ton
      if( t.taille==t.T_MAX) {
      pour ne doubler que lorsque tu en as vraiment besoin.
  3. je veux pas vous fatigué ce sera ma dernière question et j'essayerais de faire le reste moi meme

    #include <stdlib.h>
    
    struct tableau {
        int taille;
        int *tab;
    };
    
    int main(void) {
            int nb_de_sous_tableaux = 3;
    
            struct tableau ** mon_tableau = malloc(sizeof(struct tableau *) * nb_de_sous_tableaux);
            for (int i = 0; i < nb_de_sous_tableaux; i++) {
                    mon_tableau[i] = malloc(sizeof(struct tableau));
            }
    
            mon_tableau[0]->taille = 3;
            mon_tableau[0]->tab = malloc(sizeof(int) * 3);
            mon_tableau[0]->tab[0] = 1;
            mon_tableau[0]->tab[1] = 2;
            mon_tableau[0]->tab[2] = 3;
    
            free(mon_tableau[0]->tab);
    
            for (int i = 0; i < nb_de_sous_tableaux; i++) {
                    free(mon_tableau[i]);
            }
            free(mon_tableau);
    
            return 0;
    }
    
    
    


    Votre code là est trés interessant et j'ai tout compris,la partie là plus particuliérement:

     mon_tableau[0]->taille = 3;
            mon_tableau[0]->tab = malloc(sizeof(int) * 3);
            mon_tableau[0]->tab[0] = 1;
            mon_tableau[0]->tab[1] = 2;
            mon_tableau[0]->tab[2] = 3;
    
            free(mon_tableau[0]->tab);
    
    
    
    


    Ici vous savez d'avance ce qu'il faut mettre1,2,3..
    J'ai essayé de généraliser tous ca en faisant

    compteur
    Parcourir le tableau
    mon_tableau[0]->taille =compteur
    Dans mon code le compteur compte les éléments a mettre dans chaque tab et il marche j'ai vérifié
    Aprés j'ai fait
    Pour j allant de 0 au nombre de sous tableaux que je veux
    Pour k allant de 0 au nombre d'elements que je veux dans mon tableau(donné par mon compteur)
    mon_tableau[j]->tab[k] = T.tab[i];

    Ca marche pas trés bien
    CE que j'essaye de fairec'est si j'ai T=[1,2,3,4,5,-1,2,3] avoir:
    mon_tableau[0]->taille = 5;
    mon_tableau[0]->tab = malloc(sizeof(int) * 5);
    mon_tableau[0]->tab[0] = T[0];
    mon_tableau[0]->tab[0] = T[1];
    mon_tableau[0]->tab[0] = T[2];
    mon_tableau[0]->tab[0] = T[3];
    mon_tableau[0]->tab[0] = T[4];

    mon_tableau[0]->tab = malloc(sizeof(int) * 2);
    mon_tableau[1]->tab = malloc(sizeof(int) * 2);
    mon_tableau[0]->tab[1] = T[6];
    mon_tableau[0]->tab[1] = T[7];

    Ma derniere question et c'est fini pour mon sujet
    1. Contributeur
      J'ai édité mon message où j'écrivais (j'ignore si tu l'as vu)

      Ce code n'est prévu que pour des tableaux 2D où le nombre de colonnes pour chaque ligne est le même et est connu à l'avance.
      (...)


      car je me suis trompé, le code en question traite bien le cas de figure de sous-tableaux hétérogènes. Désolé pour cette confusion.

      Je pense que sans ton code qui "généralise", je ne peux pas comprendre la nature exacte de ton problème.

      Cependant, dans le principe, tu dois parcourir au préalable ton tableau fourni en entrée, pour déterminer dans un premier temps nb_de_sous_tableaux.

      Ensuite, tu peux faire ton allocation de mon_tableau avec malloc().

      Ensuite, tu dois parcourir, pour chaque sous tableau, ton tableau fourni en entrée, pour déterminer combien d'éléments chaque sous-tableau compte, et te servir de cette information pour fixer .taille et faire ton malloc() sur le pointeur .tab dans la struct
  4. Si j'ai lu lma doc mais l'exemple je l'ai pas compris du coup j'ai regardé sur ce site mlà:https://rperrot.developpez.com/articles/c/allocationC/ au niveau du 2)Là il explique bien mieux les choses et j'ai appliqué le même principe mais apparemment c'est pas comme ca



    Bref merci pour votre aide,je vais regardé plus de vidéo sur le C pour mieux comprendre
    les choses

    Merci d'avoir été patient avec moi
    1. Contributeur
      tu vois donc bien que dans le 2ème bloc de code le contenu de temp, s'il ne contient pas NULL, est affecté à tabentier et que s'il contient NULL, l'erreur est gérée par une sortie du programme (ce qui est une des 3 issues que j'ai mentionnées).

      Tu me postes donc ta source pour ton code mais on voit bien que tu ne l'appliquais pas.

      je vais regardé plus de vidéo sur le C pour mieux comprendre
      les choses


      Je te le déconseille. Les vidéos sont peu pratiques, c'est une support linéaire qui te fait perdre du temps; dont la qualité est très variable.

      Apprend à lire, comprendre et appliquer les documentations officielles des fonctions de la bibliothèque standard (pages de manuel sur Linux, sites https://www.cplusplus.com/reference/ ou https://en.cppreference.com/w/c et des supports de cours ou manuels dont la qualité est reconnue. Tu pourrais aussi investir quelques euros et acquérir :
      • le K&R pour comprendre d'où vient le C et le style de programmation et conventions qui ont formé les programmeurs C depuis des lustres
      • et un ouvrage récent prenant en compte les standards plus récents, comme : "21st Century C" de Ben Klemens et apprendre à utiliser des outils contemporains utilisés pour rendre la vie plus simple aux programmeurs C.
  5. Voici ce que j'ai fait pour éviter les fuites mémoires

    temp = realloc (tabentier, 4 * sizeof(int) );

    tableau ajouter_entier(tableau t,int n){
        int * temp;
        if( t.taille==t.T_MAX){
             temp=realloc(t.tab,2*sizeof(int));
             if ( temp == NULL ){
                  printf("Reallocation impossible");
                  free(t);
              }
        }
    
        t.taille=t.taille+1;
        int dernier_indice=t.taille-1;
        
        t.tab[dernier_indice]=n;
        return t;
        
    }
    
    
    
    
    
    
    1. Contributeur
      Tu n'as pas bien regardé dans la doc comment fonctionns realloc() et tu ne conserves pas la nouvelles valeur de T_MAX

      Cela serait plutôt :

               size_t new_T_MAX = 2 * t.T_MAX * sizeof(int)
               temp=realloc(t.tab, new_T_MAX);
               if (temp == NULL) {
                    printf("Reallocation impossible : impossible d'ajouter un entier\n");
                    return t;
                } else {
                    t.tab = temp;
                    T.T_MAX =  new_T_MAX;
                }
      


      Ce n'est très efficace, car "tableau" n'est, en fait, pas un tableau mais une struct, et lorsque celle-ci est passée en paramètre elle est copiée, et copiée de nouveau avec le return. En principe tu devrais passer un pointeur sur struct.

      Enfin, c'est toi qui vois.

      Encore une fois ces typedef ne servent à rien d'autre qu'à induire en erreur.
    2. Contributeur
      @[Dal]En fait, il y a beaucoup de choses à dire sur tes quelques lignes de code ci-dessus. J'ai voulu faire court en postant un code corrigé, mais je crains que cela ne suffise pas à ta compréhension vu ce que tu as posté.

      1.

      realloc()
      ne modifie pas le pointeur passé en 1er paramètre dans la parenthèse car ce n'est pas ce que fait cette fonction selon la documentation : elle retourne le pointeur vers la zone mémoire redimensionnée. Il lui est impossible de modifier le pointeur passé en premier paramètre, car pour pouvoir le modifier, il lui faudrait l'adresse du pointeur, et le prototype ne le prévoit pas..

      Tu dois donc affecter
      temp
      à
      t.tab
      si la réallocation a réussi.

      2.

      Si la réallocation a échoué, cela n'a aucun sens :
      • de faire un
        free(t)
        car le
        t
        passé est une struct (encore une fois tu oublies ce que c'est à cause du typedef, ce n'est pas un pointeur sur une adresse mémoire allouée avec malloc()),
      • ni de faire aucun autre
        free()
        de quoi que ce soit,
      • et qui plus est en permettant à ta fonction de continuer à écrire dans une zone mémoire non disponible au programme puisque tu n'arrêtes pas son exécution qui se poursuit après le
        free()
        .


      Le tout est assez décourageant, et c'est un euphémisme :-(

      Si la réallocation échoue, cela signifie seulement que tu ne peux pas étendre la zone mémoire, mais la zone actuelle est toujours là et utilisable par le programme. En tant que concepteur du programme, tu peux décider ce qu'il va faire à ce moment face à cette erreur (à part afficher l'erreur). Par exemple :
      • abandonner l'opération d'ajout en cours avec un message d'erreur et demander à l'utilisateur de ressayer après avoir libéré de la mémoire
      • autre chose de créatif
      • arrêter le programme


      Tu dois décider quoi faire et le faire. Pas libérer des trucs au hasard, ni permettre l'exécution de ta fonction alors que tu sais qu'elle n'est pas en mesure de s'exécuter correctement.

      3.

      Tu écrivais ci-dessus

      Voici ce que j'ai fait pour éviter les fuites mémoires

      temp = realloc (tabentier, 4 * sizeof(int) );

      tableau ajouter_entier(tableau t,int n){
      int * temp;
      if( t.taille==t.T_MAX){
      temp=realloc(t.tab,2*sizeof(int));


      alors que dans https://forums.commentcamarche.net/forum/affich-37585534-tableaux-a-diverses-dimensions-avec-diverses-taille#34 tu écrivais :

      finalement c'est bon probleme résolu j'ai modifié

      t.tab=realloc(t.tab,2*t.T_MAX*sizeof(int));


      La bonne taille est la 3ème, que j'ai mise dans le code corrigé. Ne me fait pas une 4ème ou 5ème version avec encore une taille différente dans un autre post, cela est fatiguant.

      2*sizeof(int)
      ou 4 fois, ne double pas la taille de ton tableau (qui peut en stocker 9 au début). Cela affecte 2 (ou 4 fois) la taille en octets occupée par un int en mémoire sur ta machine, c'est à dire de quoi stocker 2 ou 4 int et c'est tout. En somme tu réduis ta mémoire au premier appel à realloc() et ton programme va :
      • perdre des données
      • planter lorsqu'il va tenter de lire les éléments situés au-delà du 2ème (ou 4ème) élément, car cette mémoire n'est plus accessible au programme


      C'est tout, je crois, pour ce soir.
  6. Maintenant je vais essayer d'appliquer le même principe sur tableaux avec des sous_tableau et je reviens plus tard

    Aussi esceque la methode de réallocation que j'ai utilisé est compliqué,y avait il plus simple?
    1. Contributeur
      tu dois mettre à jour T_MAX avec la nouvelle valeur.

      le realloc() doit se faire avec un pointeur intermédiaire, au cas où realloc() échoue faute de mémoire (vois la doc dont j'ai posté le lien et l'exemple de celle ci).
  7. finalement c'est bon probleme résolu j'ai modifié
    t.tab=realloc(t.tab,2*t.T_MAX*sizeof(int));
    1. Non c'est mon 2ieme compte que j'utilise pas beaucoup,ah j'ai écris mon message avec ce compte sans faire exprès désolé
      Mon vrai compte est leoliom

      Pour résoudre ce problème,j'ai modifié le code en faisant
      typedef struct tableau {
          int taille;
          int *tab;
          int T_MAX;
      }tableau;
      
      
      


      tableau creer_tab_vide(){
          tableau t;
       t.taille = 0;
       t.T_MAX=10;
       t.tab = malloc(9* sizeof(int));
       return t;
          
          
      }
      
      tableau ajouter_entier(tableau t,int n){
          if( t.taille==t.T_MAX)
               t.tab=realloc(t.tab,2*sizeof(int));
          t.taille=t.taille+1;
          int dernier_indice=t.taille-1;
          
          t.tab[dernier_indice]=n;
          return t;
          
      }
      
      


      Mais bizarrement à un moment il y a un nombre bizarre


      Ai-je mal uttilisé realloc pourtant j'ai lu le site que vous m'avez donné
      1. Je pense qu'il faut que je sache manipuler correctement d'abord des tableaux simples avant de faire les tableaux un peu plus compliqué

        Pour les tableau simple j'ai fait ceci et ca a l'air de marcher

        #include <stdio.h>
        typedef struct tableau {
            int taille;
            int *tab;
        }tableau;
        
        
        
        tableau creer_tab_vide(){
            tableau t;
         t.taille = 0;
         t.tab = malloc(9* sizeof(int));
         return t;
            
            
        }
        
        tableau ajouter_entier(tableau t,int n){
            t.taille=t.taille+1;
            int dernier_indice=t.taille-1;
            
            t.tab[dernier_indice]=n;
            return t;
            
        }
        
        tableau creer_tab_vide(){
            tableau t;
         t.taille = 0;
         t.tab = malloc(9* sizeof(int));
         return t;
            
            
        }
        
        tableau ajouter_entier(tableau t,int n){
            t.taille=t.taille+1;
            int dernier_indice=t.taille-1;
            
            t.tab[dernier_indice]=n;
            return t;
            
        }
        
        int main(void){
            tableau t;
            t=creer_tab_vide();
            t=ajouter_entier(t,1);
            t=ajouter_entier(t,2);
            t=ajouter_entier(t,3);
            t=ajouter_entier(t,4);
            t=ajouter_entier(t,-1);
            t=ajouter_entier(t,6);
            t=ajouter_entier(t,7);
            t=ajouter_entier(t,8);
            t=ajouter_entier(t,-1);
            afficher_tableau(t);
           return 0;
        }
        
        


        Seul bémol dans creer tableau vide j'ai mis le nombre 9 car je sais que dans le main mon tableau est de taille 9
        Comment faire pour connaitre d'avance le nombre d'espace qu'on doit stocker
        ou sinon si on veut ajouter un entier,je veux que la taille augmente de 1 pour mettre l'entier(reservation dynamique)

        Une fois que j'aurais compris le fonctionnement des tableaux simples,je pourrais revenir a mon exo et appliquer vos conseils
        1. Contributeur
          dans creer tableau vide j'ai mis le nombre 9 car je sais que dans le main mon tableau est de taille 9
          Comment faire pour connaitre d'avance le nombre d'espace qu'on doit stocker


          Puisque tu disposes de cette information dans main, tu devrais la passer en paramètre de ta fonction, non ?

          ou sinon si on veut ajouter un entier,je veux que la taille augmente de 1 pour mettre l'entier(reservation dynamique)

          Si main ne sait pas à l'avance, cela peut se justifier.

          Tu peux alors faire des realloc() en augmentant la capacité mémoire réservée lorsque tu approches de la saturation.

          https://www.cplusplus.com/reference/cstdlib/realloc/

          une stratégie classique est de procéder par doublements successifs de la capacité, pour limiter le nombre d'appels système générés par realloc(), plutôt que d'augmenter par unités.

          Heu, juste pour mon information Theo_0055 == leoliom ou j'ai affaire à deux personnes différentes ?
      2. En fait vous,vous avez défini un type double pointeur sur un tableau appelé TABLEAU

        Le problème c’est que si je fais return mon_tableau dans la fonction que j’ai écris tout à l’heure ça me renvoie un pointeur et moi je peux pas ça mais je veux qu’il me renvoie un tableau multidimensionnel avec des sous tableaux de tailles différentes

        En fait je veux que dans mon main il y ait ceci :

        Etc
        tableau t=[1,2,3,-1,4,5,6,7,8,-1,4,2,-1]
        TABLEAU T=transforme(t);
        afficher_tableau(T);

        Et je veux que ma console me renvoie
        [[1,2,3],[4,5,6,7,8],[4,2]]

        A peu près c’est ça que je cherche à faire
        1. Contributeur
          En fait vous,vous avez défini un type double pointeur sur un tableau appelé TABLEAU

          Soyons précis stp. TABLEAU est un pointeur sur un pointeur sur struct. N'oublie pas que ce que tu veux appeler "tableau" avec ton typedef n'est pas de type tableau en C (array en anglais).

          Le problème c’est que si je fais return mon_tableau dans la fonction que j’ai écris tout à l’heure ça me renvoie un pointeur et moi je peux pas ça mais je veux qu’il me renvoie un tableau multidimensionnel avec des sous tableaux de tailles différentes

          Une fonction ne peut pas retourner un tableau en C (qu'il soit à une dimension ou deux). Tu peux, par contre, retourner un pointeur vers un emplacement d'une zone mémoire allouée permettant d'accéder à des données d'un certain type accessibles avec l'opérateur crochets
          []
          ce qui semblait te convenir tout à l'heure... tu as changé d'avis ?

          tableau t=[1,2,3,-1,4,5,6,7,8,-1,4,2,-1] 


          ceci n'est pas du C valide et ce n'est pas le type "tableau" tel que définit dans ton code avec le typedef auquel correspond ce qui suit, mais juste un tableau d'int

          int t[] = { 1, 2, 3, -1, 4, 5, 6, 7, 8, -1, 4, 2, -1 };


          (pour mémoire, le typedef définit avec le nom "tableau" dans ton code est le
          struct tableau
          qui te permet d'imbriquer des "tableaux" à dimensions variables dans TABLEAU, il ne faut pas tout mélanger stp ... voilà, en fait une illustration du danger des typedef ... tu ne sais même plus ce que tu tapes !)

          Ensuite, lorsque tu passes
          t
          en paramètre de la fonction
          transforme()
          , la fonction en question n'a aucun moyen de savoir quel est le nombre d'éléments du tableau passé. Tu dois passer cette information en paramètre, sinon elle n'est pas accessible à la fonction
          transforme()
          , qui reçoit juste un pointeur sur le premier élément int et perd l'information sur la taille du tableau.

          par exemple, l'appel pourrait se faire comme ceci :

          TABLEAU T = transforme(t, sizeof(t) / sizeof(int)); 


          et le prototype de la fonction
          transforme()
          devrait alors être quelque chose comme :

          TABLEAU transforme(int * t, size_t nb_elements);
        2. Contributeur
          @[Dal]il y a un topic sur SO sur la question "Returning an array using C" :

          https://stackoverflow.com/questions/11656532/returning-an-array-using-c

          la réponse courte est "You can't return arrays from functions in C." comme je te le disais

          après, si tu veux entrer dans le détail de choses, tu peux lire toutes les contributions proposant différentes solutions, sachant que retourner un pointeur vers une zone mémoire allouée dans la fonction est l'une d'elle classique et que c'est celle que tu mets en oeuvre
      3. desolé j'avais oublie de mettre l e typedef
        1. Contributeur
          Dans ce cas tu peux définir :

          typedef tableau ** TABLEAU;


          Mais c'est une très mauvaise pratique que de camoufler un type pointeur dans un typedef.

          En utilisant les 2 typedef, si tu veux / dois faire cette atrocité en dépit du bon sens, mon code précédent peut s'écrire comme ceci :

          #include <stdlib.h>
          
          struct tableau {
              int taille;
              int *tab;
          };
          typedef struct tableau tableau;
          
          typedef tableau ** TABLEAU;
          
          int main(void) {
                  int nb_de_sous_tableaux = 3;
          
                  TABLEAU mon_tableau = malloc(sizeof(tableau *) * nb_de_sous_tableaux);
                  for (int i = 0; i < nb_de_sous_tableaux; i++) {
                          mon_tableau[i] = malloc(sizeof(tableau));
                  }
          
                  mon_tableau[0]->taille = 3;
                  mon_tableau[0]->tab = malloc(sizeof(int) * 3);
                  mon_tableau[0]->tab[0] = 1;
                  mon_tableau[0]->tab[1] = 2;
                  mon_tableau[0]->tab[2] = 3;
          
                  free(mon_tableau[0]->tab);
          
                  for (int i = 0; i < nb_de_sous_tableaux; i++) {
                          free(mon_tableau[i]);
                  }
                  free(mon_tableau);
          
                  return 0;
          }


          C'est "mal" de cacher un pointeur (et là qui plus est un pointeur sur un pointeur) parce que le typedef occulte une information importante et que le risque est que demain toi ou une autre personne reprenant ton code ne le comprenne pas et déréférence un pointeur non initialisé ou autres joyeusetés.

          C'est le genre de trucs qui fait hurler Linus Tolvards si un contributeur au noyau Linux s'amuse à faire cela (et ce n'est pas le seul).

          https://www.kernel.org/doc/html/v4.10/process/coding-style.html#typedefs
      4. Pour le 1 et 2 j'ai compris et je vois ce que vous voulez dire/

        Pour le 3. En fait je veux définir un type TABLEAU .Ce type sera composé de tableau de type tableau
        Esce que vous voyez ce que je eux dire?
        TABLEAU c'est comme un énorme tableau et dans ce tableau il ya dedans des tableaux(sous_tableau) de tailles différentes)

        A un moment j'avais pensé a faire
        typedef struct TABLEAU TABLEAU{
              tableau *tab
              int taille;
        }
        
        


        Mais le problème c'est que si je fais ca je pourrais pas utiliser le double pointeur mon_tableau et je pourrais pas faire les mêmes opérations de ce dernier
        1.  TABLEAU struct tableau ** mon_tableau = malloc(sizeof(struct tableau *) * nb_de_sous_tableaux);
          
          

          Ceci renvoie une erreur
          1. Contributeur
            1.

            typedef sert à définir un alias de type. Il n'est pas obligatoire de définir un typedef pour utiliser un type struct, et tu peux faire sans, comme je l'ai montré dans mon code d'exemple en https://forums.commentcamarche.net/forum/affich-37585534-tableaux-a-diverses-dimensions-avec-diverses-taille#12 mais certaines personnes préfèrent le faire pour éviter d'avoir à taper
            struct truc ma_structure;
            pour déclarer une variable, ils définissent un alias de ce type sous un nom "truc" pour pouvoir juste taper
            truc ma_structure;
            pour faire la même chose.

            Comme tu veux manifestement utiliser ce type d'écriture (personnellement je ne suis pas fan), tu dois utiliser des typedef, et il faut les définir et utiliser correctement.

            La syntaxe est :

            typedef <type existant> <alias du type existant>;


            et ensuite, tu peux utiliser "alias du type existant" à la place de "type existant"

            2.

            Dans ce que tu postes, tu fais ceci :

            typedef struct tableau {
                int taille;
                int *tab;
            }tableau;
            • après
              typedef
              tu as ton type
              struct tableau { int taille; int *tab; }
              qui est le "type existant" (qui est lui-même défini de façon compacte dans le typedef lui-même)
            • et après l'accolade fermante tu as l' "alias du type existant" qui est défini comme étant "tableau"


            Cette construction est conforme à la syntaxe de typedef, sous une forme compacte.

            Personnellement, je n'ai pas trop cette façon de faire, style couteaux suisses, car elle mélange trop de choses et les débutants en C ne comprennent pas, en général ce qu'ils font.

            C'est plus clair, à mon sens de faire :

            struct tableau {
                int taille;
                int *tab;
            };
            typedef struct tableau tableau;
            


            Les deux sont équivalents, et te permettent désormais d'écrire :
            tableau mon_tableau
            à la place de
            struct tableau mon_tableau
            .

            3.

            La suite de ce que tu définis, en revanche, n'a pas de sens et donne une erreur de compilation, car tu respectes pas la syntaxe de typedef :

            typedef struct tableau TABLEAU TABLEAU;


            Ceci ne compile pas chez moi et renvoie :

            $ gcc -Wall -Wextra 37585534.c 
            37585534.c:15:32: error: expected ‘=’, ‘,’, ‘;’, ‘asm’ or ‘__attribute__’ before ‘TABLEAU’
            typedef struct tableau TABLEAU TABLEAU;
            ^~~~~~~


            Que veux-tu faire avec ce second typedef que tu veux appeler TABLEAU alors que tu as déjà un typedef pour la
            struct tableau
            que tu as appelé
            tableau
            ?

            TABLEAU struct tableau ** mon_tableau
            ne peut pas fonctionner non plus, même si tu avais définit correctement un typedef dénommé TABLEAU, car la déclaration est syntaxiquement incorrecte. Soit tu utilises le type
            struct tableau
            soit tu utilises un alias de ce type, mais pas les deux en même temps.

            C'est comme si tu écrivais :
            int int un_entier;
            , ou
            float int un_nombre;
            le compilateur ne saurait pas quoi en faire...

            En revanche
            tableau ** mon_tableau
            ou
            struct tableau ** mon_tableau
            (comme je l'avais écrit) devraient ne pas renvoyer d'erreurs.
          2. Contributeur
            @[Dal]Je ne suis pas sûr que tu sois allé revoir ton cours ou manuel sur les struct comme je te conseillais de le faire, alors voilà quelques précisions pouvant être utiles à ta compréhension :

            Quand tu écris :

            struct tableau {
                int taille;
                int *tab;
            };
            • struct
              est un mot clef du langage C, il permet ici au compilateur de comprendre que tu veux définir un type composite struct
            • tableau
              est étiquette du type struct, elle identifie le type struct créé
            • le contenu des accolades définit les éléments du type composite
            • après l'accolade fermante, tu mets un
              ;
              car c'est une instruction que tu viens d'écrire et tu la termines


            En faisant cela, tu n'as pas défini un type
            tableau
            ("tableau" est juste une étiquette, pas un type), tu as défini un type
            struct tableau
            . Pour désigner et utiliser ce type tu dois taper
            struct tableau
            .

            Pour que "tableau" devienne un type à lui seul, tu dois créer un alias sur le type
            struct tableau
            au moyen de
            typedef
            .

            Je ne peux pas expliquer plus clairement :-)
        2. Bonjour j'ai écrit une fonctionne qui ne retourne qu'une erreur,a savoir le return mon_tableau
          mon_tableau est un pointeur or moi je veux renvoyer un type TABLEAU mais ca marche pas et je vois pas comment faire.Comment faire pour que le pointeur mon_tableau soit du type TABLEAU

          #include <stdbool.h>
          #include <stdlib.h>
          #include <stdio.h>
          typedef struct tableau {
              int taille;
              int *tab;
          }tableau;
          
          
          typedef struct tableau TABLEAU TABLEAU;
          
          int compte_moins_1(tableau T){
            int nb=0;
            int i;
            for(i=0;i<T.taille;i++){
              if(T.tab[i]==-1)
                nb++;
            }
            return nb;
          }
          
          TABLEAU transforme(tableau T){
              int nb_de_sous_tableaux=compte_moins_1(T) ;
              TABLEAU struct tableau ** mon_tableau = malloc(sizeof(struct tableau *) * nb_de_sous_tableaux);
              int i,compteur;
              
              bool debut_moins1=true;
              for(i=0;i<T.taille;i++){
                  if(T.tab[i]!=-1){
                      if(debut_moins1){
                          if (i>=1){
                              int j;
                              for (j= 0; i < nb_de_sous_tableaux; i++) {
                                  mon_tableau[i] = malloc(sizeof(struct tableau));
                              }
                              int k,l;
                              for(k=0;k < nb_de_sous_tableaux;k++){
                                  for(l=0;l < nb_de_sous_tableaux;k++){
                                      mon_tableau[k]->taille = compteur;
                                      mon_tableau[k]->tab = malloc(sizeof(int) * compteur);
                                      mon_tableau[k]->tab[l] = T.tab[i];
                                  }
                              }
                              
                              
                          }
                          compteur=1;
                            
                          debut_moins1=false;
                      }
                      else{
                          int k,l;
                         for(k=0;k < nb_de_sous_tableaux;k++){
                              for(l=0;l < nb_de_sous_tableaux;k++){
                                  mon_tableau[k]->taille = compteur;
                                  mon_tableau[k]->tab = malloc(sizeof(int) * compteur);
                                  mon_tableau[k]->tab[l] = T.tab[i];
                              }
                          }
                        compteur+=1;
                      }
                  }
                  else
                      debut_moins1=true;
              }
              return mon_tableau;
          }
          
          1. Non j’ai dit que la partie 1 de mon exo les sous tableaux ont des tailles différentes et pouf la partie 2 la taille
            Pour l’instant,je préfère qu’on traite d’abord la partie 1 de mon exo

            Non votre code marche,je voulais dire que si j’essaye de l’adapter à ma façon de sorte qu’il fasse ce que j’attend ca marche pas

            Je vais essayer de voir ce qui cloche dans mon algo et code et après plus tard je posterais ce que j’ai fait
            1. Oui c’est plus clair
              Mais j’ai essayé d’utiliser votre code pour répondre à la question partie 1 de mon exo(taille sous tableau différente) mais j’arrive pas ,le compilateur me renvoie que des erreurs

              Esceque l’algorithme que j’ai mis tout à l’heure à 12h15 est correct?
              1. Contributeur
                Si tu veux dire celui-ci à 12:35 : https://forums.commentcamarche.net/forum/affich-37585534-tableaux-a-diverses-dimensions-avec-diverses-taille#13

                non, il n'est pas "correct".

                Je ne vois pas comment tu alloues la mémoire, mais en tout cas tes indices ne sont pas consécutifs. De plus, les "sous-tableaux" ont une taille fixe et je ne sais pas ce que tu veux dire par la partie 1 de ton exo.

                j’ai essayé d’utiliser votre code pour répondre à la question partie 1 de mon exo(taille sous tableau différente) mais j’arrive pas ,le compilateur me renvoie que des erreurs

                Mon code en https://forums.commentcamarche.net/forum/affich-37585534-tableaux-a-diverses-dimensions-avec-diverses-taille#14 compile très bien et sans avertissements ni erreurs avec gcc version 8.3.0


            2. int (*arr)[col] = calloc(row, sizeof *arr);


              Le crochet [col] est censé faire quoi
              C'est quoi cette notation [][],j'en avais jamais vu encore
              1. Contributeur
                Alors, voilà quelques précisions.

                col
                est une variable du programme contenant une valeur entière, dans mon exemple un 4. Dans
                row
                , je mets le nombre de lignes souhaitées.

                dans
                int (*arr)[col] = calloc(row, sizeof *arr);
                , la partie à gauche du signe égal déclare une variable
                arr
                en tant que pointeur sur un tableau de
                col
                int.

                Ce type de déclaration est possible en langage C depuis le standard C99, où on peut utiliser la notation VLA pour spécifier à l'exécution la taille d'un tableau. C'est juste la notation VLA qui est utilisée dans mon exemple et le tableau n'est pas un tableau VLA. En effet, la mémoire n'est pas affectée sur la pile, mais sur le tas, avec calloc().
                On aurait aussi pu utiliser malloc().

                Comme on alloue à ce pointeur un espace mémoire de la taille occupée par les données pointées par le tableau multiplié par autant que fois que l'on veut de lignes (cf. doc de calloc()), on obtient un espace mémoire contigu qui permet de stocker col x row int (initialisé à 0 par calloc() ou avec un contenu arbitraire si on utilise malloc()).

                []
                est un opérateur en C. L'opérateur crochets permet d'accéder à la donnée existante à un emplacement mémoire augmenté de l'indice qui figure entre crochets (fois la taille de l'objet stocké), autrement dit, il facilite l'accès au contenu d'un tableau, par exemple :

                int arr[5] = { 0, 1, 2, 3, 4 };
                printf("Le 3ème élément de arr est : %d\n", arr[2]);


                Ce code affichera : 2, car l'opérateur crochets aura permis d'accéder à l'int stocké à l'adresse de arr + (2 x la taille d'un int).

                Cet opérateur peut être combiné pour simuler un tableau 2D sous réserve que la dimension d'une ligne soit connue, ce qui permet de faciliter l'accès à un élément figurant à une ligne et colonne précise, par exemple :
                int arr[2][5] = {
                    { 0, 1, 2, 3, 4},
                    { 5, 6, 7, 8, 9}
                };
                printf("L'élément présent en 2ème ligne, 3ème colonne est : %d\n",
                    arr[1][2]);


                Ce code affichera : 7

                La déclaration que je propose permet d'effectuer une réservation, lors de l'exécution du programme, de l'espace mémoire nécessaire au stockage d'un tableau 2D d'une taille connue à l'exécution, tout en conservant la possibilité d'adresser son contenu avec les opérateurs crochets combinés.

                Est-ce plus clair ?
            3. En fait mon exo c'est 2 partie

              1er partie:tableau composé de sous tableau de taille différente

              2ieme partie:tableau composé de sous tableau de même taille

              les lignes et colonnes de votre code ca veut dire on a combien de sous-tableau
              3 ligne et 4 colonnes veut dire 3 sous tableau avec dedans chacun 4 éléments?
              1. Bonjour je me suis dit que typedef c'etait pas nécessaire vu que je voulais pas renommer mon type.Mais maintenant je vois pourquoi a chaque fois on met typedef ok

                En fait les T,T1 c'etait juste des exemples pour vous dire que je veux que T soit de type tableau et T1 de type mon_tableau

                D'accord je vais donner le but de l'exercice
                En fait mon exercice me donne T=[1,2,3,-1,4,8,9,-1,6,1,4,-1]
                On me demande de transforme T de sorte à avoir T'=[[1,2,3],[4,8,9],[6,1,4]]
                Donc on tient pas compte des -1
                Pour pouvoir y parvenir je me suis dis qu'il faut que j'ai un type tableau(unidimensionnel comme T),un type mon_tableau(comme celui de T' de l'exo)
                Je me suis dit qu'il faut aussi que je crée une fonction creer un tableau vide et ajoute un sous tableau à la fin un tableau du même type que le tableau T' de mon exo

                l'algorithme que j'ai en tête en me basant sur le tableau donné dans mon exo est le suivant:

                transforme(tableau T)
                Pour i allant de 0 à T.taille-1
                Trouver les indices où se trouve -1

                mon_tableau[0]->taille=4( 1er indice ou se trouve le -1)
                //Aprés ca on remet le compteur de -1 à 0
                //De base je voulais faire créer un tableau T' du type mon_tableau
                //Créer un tableau du type tableau(unidimensionnel avec 1,2,3)=>T1=[1,2,3]
                //Ensuite faire appel a ma fonction ajout pour ajouter T1 dans T'=>T'=[[1,2,3]]
                //Mais je vois qu'on pouvait faire autrement comme ce que vous avez proposé
                mon_tableau[0]->tab[0]=1
                mon_tableau[0]->tab[1]=2
                mon_tableau[0]->tab[3]=3

                //On compte les éléments avant le trouver le second -1
                mon_tableau[1]->taille=3
                mon_tableau[1]->tab[0]=4
                mon_tableau[1]->tab[1]=8
                mon_tableau[1]->tab[3]=9

                //Idem
                mon_tableau[2]->taille=3
                mon_tableau[2]->tab[0]=6
                mon_tableau[2]->tab[1]=1
                mon_tableau[2]->tab[3]=4
                1. Contributeur
                  Je n'ai pas le temps de regarder tout de suite en détails, mais lorsque tu dis ceci :
                  D'accord je vais donner le but de l'exercice
                  En fait mon exercice me donne T=[1,2,3,-1,4,8,9,-1,6,1,4,-1]
                  On me demande de transforme T de sorte à avoir T'=[[1,2,3],[4,8,9],[6,1,4]]
                  Donc on tient pas compte des -1


                  Tu dis quelque chose de différent du problème initial que tu posais, qui était de pouvoir structurer en mémoire des données (int) avec des dimensions variables. Là, tu un tableau de 3x3 et pas ce que postais au début, qui était : [[1,2,3],[4,1],[1,6,9,0,1]].

                  Avec un tableau de 3x3, tu peux représenter tes données dans un espace contigu de mémoire et y accéder avec la notation [][].

                  Par exemple :

                  #include <stdio.h>
                  #include <stdlib.h>
                   
                  int main(void) {
                      int row = 3, col = 4, i, j, count;
                   
                      int (*arr)[col] = calloc(row, sizeof *arr);
                       
                      count = 0;
                      for (i = 0; i < row; i++)
                          for (j = 0; j < col; j++)
                              arr[i][j] = ++count;
                   
                      for (i = 0; i < row; i++)
                          for (j = 0; j < col; j++)
                              printf("%d ", arr[i][j]);
                   
                      free(arr);
                       
                      return 0;
                  }


                  Tu dois juste déterminer le nombre de lignes et de colonnes souhaitées, et réserver l'espace mémoire pour le tableau à 2 dimensions avec le prototype adéquat, comme ci-dessus, et tu peux y accéder aux données avec la notation crochets comme dans l'exemple ci-dessus pour le remplir avec les données provenant de ton tableau plat à 1D.

                  Ton idée d'utiliser une struct n'est pas nécessaire, puisque le langage te permet de faire plus naturellement ou sous la forme d'un vrai tableau C adressable en 2D, et non pas d'un tableau de struct.

                  Dal
              • 1
              • 2