Tableaux à diverses dimensions avec diverses taille

Fermé
leoliom Messages postés 171 Date d'inscription jeudi 21 juillet 2016 Statut Membre Dernière intervention 20 février 2024 - 3 mai 2022 à 16:30
leoliom Messages postés 171 Date d'inscription jeudi 21 juillet 2016 Statut Membre Dernière intervention 20 février 2024 - 9 mai 2022 à 05:22
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

leoliom Messages postés 171 Date d'inscription jeudi 21 juillet 2016 Statut Membre Dernière intervention 20 février 2024 2
7 mai 2022 à 13:39
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;
    
}





0
[Dal] Messages postés 6194 Date d'inscription mercredi 15 septembre 2004 Statut Contributeur Dernière intervention 11 octobre 2024 1 092
8 mai 2022 à 00:52
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.
0
[Dal] Messages postés 6194 Date d'inscription mercredi 15 septembre 2004 Statut Contributeur Dernière intervention 11 octobre 2024 1 092 > [Dal] Messages postés 6194 Date d'inscription mercredi 15 septembre 2004 Statut Contributeur Dernière intervention 11 octobre 2024
Modifié le 8 mai 2022 à 04:15
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.
0
leoliom Messages postés 171 Date d'inscription jeudi 21 juillet 2016 Statut Membre Dernière intervention 20 février 2024 2
Modifié le 8 mai 2022 à 10:12
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
0
[Dal] Messages postés 6194 Date d'inscription mercredi 15 septembre 2004 Statut Contributeur Dernière intervention 11 octobre 2024 1 092
Modifié le 8 mai 2022 à 13:02
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.
0
leoliom Messages postés 171 Date d'inscription jeudi 21 juillet 2016 Statut Membre Dernière intervention 20 février 2024 2
8 mai 2022 à 10:24
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
0
[Dal] Messages postés 6194 Date d'inscription mercredi 15 septembre 2004 Statut Contributeur Dernière intervention 11 octobre 2024 1 092
Modifié le 8 mai 2022 à 13:40
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
0
leoliom Messages postés 171 Date d'inscription jeudi 21 juillet 2016 Statut Membre Dernière intervention 20 février 2024 2
8 mai 2022 à 14:46
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
0
[Dal] Messages postés 6194 Date d'inscription mercredi 15 septembre 2004 Statut Contributeur Dernière intervention 11 octobre 2024 1 092
Modifié le 8 mai 2022 à 16:01
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).
0
[Dal] Messages postés 6194 Date d'inscription mercredi 15 septembre 2004 Statut Contributeur Dernière intervention 11 octobre 2024 1 092 > [Dal] Messages postés 6194 Date d'inscription mercredi 15 septembre 2004 Statut Contributeur Dernière intervention 11 octobre 2024
Modifié le 8 mai 2022 à 16:17
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.
0

Vous n’avez pas trouvé la réponse que vous recherchez ?

Posez votre question
leoliom Messages postés 171 Date d'inscription jeudi 21 juillet 2016 Statut Membre Dernière intervention 20 février 2024 2
8 mai 2022 à 18:21
Merci pour votre aide,je vais en finir là,j'ai passé trop de temps su cette exo

Merci encore
0
[Dal] Messages postés 6194 Date d'inscription mercredi 15 septembre 2004 Statut Contributeur Dernière intervention 11 octobre 2024 1 092
8 mai 2022 à 23:28
de rien, j'espère que tu auras appris 2 ou 3 trucs qui te serviront :-)

bon courage pour la suite !
0
leoliom Messages postés 171 Date d'inscription jeudi 21 juillet 2016 Statut Membre Dernière intervention 20 février 2024 2
9 mai 2022 à 05:22
Oui j’ai appris beaucoup de chose merci encore❤️
0