Tableaux à diverses dimensions avec diverses taille
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
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.
-
Oui j’ai appris beaucoup de chose merci encore❤️
-
Merci pour votre aide,je vais en finir là,j'ai passé trop de temps su cette exo
Merci encore -
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-
ContributeurMon 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). -
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 tonif( t.taille==t.T_MAX) {pour ne doubler que lorsque tu en as vraiment besoin.
-
-
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-
ContributeurJ'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
-
-
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-
Contributeurtu 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.
-
-
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; }-
ContributeurTu 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. -
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 affectertemp
à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 let
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. - de faire un
-
-
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? -
finalement c'est bon probleme résolu j'ai modifié
t.tab=realloc(t.tab,2*t.T_MAX*sizeof(int));
-
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 faisanttypedef 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é -
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-
Contributeurdans 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 ?
-
-
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-
ContributeurEn 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 lestruct 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 passest
en paramètre de la fonctiontransforme()
, 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 fonctiontransforme()
, 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 fonctiontransforme()
devrait alors être quelque chose comme :
TABLEAU transforme(int * t, size_t nb_elements);
-
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
-
-
desolé j'avais oublie de mettre l e typedef
-
ContributeurDans 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
-
-
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 fairetypedef 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 -
TABLEAU struct tableau ** mon_tableau = malloc(sizeof(struct tableau *) * nb_de_sous_tableaux);
Ceci renvoie une erreur-
Contributeur1.
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 à taperstruct truc ma_structure;
pour déclarer une variable, ils définissent un alias de ce type sous un nom "truc" pour pouvoir juste tapertruc 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 typestruct 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 destruct 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 lastruct 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 typestruct 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;
, oufloat int un_nombre;
le compilateur ne saurait pas quoi en faire...
En revanchetableau ** mon_tableau
oustruct tableau ** mon_tableau
(comme je l'avais écrit) devraient ne pas renvoyer d'erreurs. - après
-
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 typetableau
("tableau" est juste une étiquette, pas un type), tu as défini un typestruct tableau
. Pour désigner et utiliser ce type tu dois taperstruct tableau
.
Pour que "tableau" devienne un type à lui seul, tu dois créer un alias sur le typestruct tableau
au moyen detypedef
.
Je ne peux pas expliquer plus clairement :-) -
-
-
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; } -
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 -
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?-
ContributeurSi 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
-
-
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-
ContributeurAlors, voilà quelques précisions.
col
est une variable du programme contenant une valeur entière, dans mon exemple un 4. Dansrow
, je mets le nombre de lignes souhaitées.
dansint (*arr)[col] = calloc(row, sizeof *arr);
, la partie à gauche du signe égal déclare une variablearr
en tant que pointeur sur un tableau decol
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 ?
-
-
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? -
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-
ContributeurJe 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