[C] Allocation dynamique - Tableau et structu
Résolu
Hylpoz
-
Hylpoz Messages postés 1 Date d'inscription Statut Membre Dernière intervention -
Hylpoz Messages postés 1 Date d'inscription Statut Membre Dernière intervention -
Bonjour,
J'ai cherche sur le forum les réponses à mes questions, mais certaines restent sans réponses ou un peu floues... :(
Je vous explique mon problème:
Je dois faire un projet un C, dans lequel j'ai décidé d'utiliser une structure d'arbre pour représenter des mots/phrases.
Voici la structure de mes noeuds:
J'appelle "fils" les liens vers la suite de l'arbre.
Voici un exemple d'arbre (fait sous paint :euh: ) pour que vous voyez ce que je veux modéliser:
http://img232.imageshack.us/img232/4151/exemplearbreah3.jpg
Donc en gros chaque noeud peut avoir un nombre variable de fils de 0 à 255.
Voici la fonction que j'utilise pour rajouter un fils et la fonction d'initialisation d'un noeud:
Ce code marche si mes souvenirs d'hier sont bons mais le fait est que j'ai du mal avec les passages de paramètres en langage C...
Alors voici la liste de question auxquelles j'espère vous pourrez répondre :)
Question 3:
Nos professeurs nous ont conseillé d'éviter d'utiliser la fonction realloc().
Donc j'aimerai à partir de malloc() et free() agrandir mon tableau de 1 case et le recopier, et le rendre dans le paramètre "t_Noeud *i_Ptr_noeud".
Que faut-il que je modifie dans la signature de ma fonction pour que cela soit possible?
Question 2:
Dans la fonction void Ajouter_nouvelle_chaine(t_Noeud *i_Ptr_noeud, char i_Car)
je modifie le noeud repéré par le pointeur que je passe en paramètre. Mais ce pointeur est censé être seulement une copie du vrai pointeur (celui de la fonction appelante).
Alors comment ce fait-il que mes modifications soient prises en compte?
Les modifications étant:
-Agrandissement du tableau.
-Ajout d'un nouveau noeud à la fin de ce même tableau
-Incrémentation du champ: Nb_fils
Je me pose la même question lorsque j'initialise mon noeud...
Question 3:
A la fin de mon algorithme, il faut que je libère mon arbre. Dans Mon cas, le code suivant suffit-il?
ou faut-il que je parcours mon arbre complètement et libérer 1 à 1 chaque noeud de l'arbre?
Si c'est le cas, la signature suivante convient-elle? (La fonction étant une fonction récursive) Car la le pointeur sera une recopie du pointeur de la fonction appelante...
Merci à ceux qui auront eu la patience et le courage de lire ce long post...
Si vous avez besoin de plus de précision ou explications n'hésitez pas.
J'ai cherche sur le forum les réponses à mes questions, mais certaines restent sans réponses ou un peu floues... :(
Je vous explique mon problème:
Je dois faire un projet un C, dans lequel j'ai décidé d'utiliser une structure d'arbre pour représenter des mots/phrases.
Voici la structure de mes noeuds:
typedef struct t_Noeud t_Noeud; struct t_Noeud{ char C; //Caractère du noeud unsigned int Nb_fils; t_Noeud* *Fils; //Tableau dynamique de liens vers la suite de l'arbre. };
J'appelle "fils" les liens vers la suite de l'arbre.
Voici un exemple d'arbre (fait sous paint :euh: ) pour que vous voyez ce que je veux modéliser:
http://img232.imageshack.us/img232/4151/exemplearbreah3.jpg
Donc en gros chaque noeud peut avoir un nombre variable de fils de 0 à 255.
Voici la fonction que j'utilise pour rajouter un fils et la fonction d'initialisation d'un noeud:
void Initialiser_Noeud(t_Noeud *i_Ptr_noeud, char i_Car) { i_Ptr_noeud->C = i_Car; i_Ptr_noeud->Nb_fils = 0; i_Ptr_noeud->Fils = NULL; } void Ajouter_nouvelle_chaine(t_Noeud *i_Ptr_noeud, char i_Car) { size_t Taille_alloc_fils = i_Ptr_noeud->Nb_fils + 1; size_t Taille_alloc_noeud = sizeof(t_Noeud); /*Agrandir tableau de "fils de 1 case *fonctionne comme malloc(Taille_alloc_fils) si i_Ptr_noeud->Fils == NULL */ i_Ptr_noeud->Fils = realloc(i_Ptr_noeud->Fils,Taille_alloc_fils); //Ajouter un nouveau noeud en dernière position i_Ptr_noeud->Fils[i_Ptr_noeud->Nb_fils] = malloc(Taille_alloc_noeud); //Initialisation du nouveau noeud. Initialiser_Noeud(i_Ptr_noeud->Fils[i_Ptr_noeud->Nb_fils],i_Car); //Le nombre de fils est incrémenté. i_Ptr_noeud->Nb_fils++; }
Ce code marche si mes souvenirs d'hier sont bons mais le fait est que j'ai du mal avec les passages de paramètres en langage C...
Alors voici la liste de question auxquelles j'espère vous pourrez répondre :)
Question 3:
Nos professeurs nous ont conseillé d'éviter d'utiliser la fonction realloc().
Donc j'aimerai à partir de malloc() et free() agrandir mon tableau de 1 case et le recopier, et le rendre dans le paramètre "t_Noeud *i_Ptr_noeud".
Que faut-il que je modifie dans la signature de ma fonction pour que cela soit possible?
Question 2:
Dans la fonction void Ajouter_nouvelle_chaine(t_Noeud *i_Ptr_noeud, char i_Car)
je modifie le noeud repéré par le pointeur que je passe en paramètre. Mais ce pointeur est censé être seulement une copie du vrai pointeur (celui de la fonction appelante).
Alors comment ce fait-il que mes modifications soient prises en compte?
Les modifications étant:
-Agrandissement du tableau.
-Ajout d'un nouveau noeud à la fin de ce même tableau
-Incrémentation du champ: Nb_fils
Je me pose la même question lorsque j'initialise mon noeud...
Question 3:
A la fin de mon algorithme, il faut que je libère mon arbre. Dans Mon cas, le code suivant suffit-il?
void main() { //Début du programme t_Noeud *Racine = malloc(sizeof(t_Noeud)), *P = NULL; Initialiser_Noeud(Racine,'@'); //Corps du programme //... //... //Fin du programme free(Racine); }
ou faut-il que je parcours mon arbre complètement et libérer 1 à 1 chaque noeud de l'arbre?
Si c'est le cas, la signature suivante convient-elle? (La fonction étant une fonction récursive) Car la le pointeur sera une recopie du pointeur de la fonction appelante...
void Liberer_noeud(t_Noeud *i_Ptr_Noeud);
Merci à ceux qui auront eu la patience et le courage de lire ce long post...
Si vous avez besoin de plus de précision ou explications n'hésitez pas.
A voir également:
- [C] Allocation dynamique - Tableau et structu
- Tableau croisé dynamique - Guide
- Tableau word - Guide
- Exemple tableau croisé dynamique télécharger - Télécharger - Tableur
- Tableau ascii - Guide
- Trier un tableau excel - Guide
4 réponses
size_t Taille_alloc_fils = (i_Ptr_noeud->Nb_fils + 1) * sizeof(t_Noeud*);
tu as raison, c'est moi qui m'étais trompé
Pour ce qui est d'affecter NULL aux pointeurs désalloués, ça n'est demandé ni par la syntaxe, ni par la logique. On entre dans le domaine des goûts et des couleurs. L'aspect pratique, c'est que tu est sûr que tu n'as plus rien à désallouer, et que tu peux tester la valeur d'un pointeur avant de t'en servir, ce qui peut être utile pour le debogage.
Dans ton cas précis, affecter NULL aux fils ne sert à rien, ils ne seront plus accessibles de toutes manières dès que tu auras affecté NULL au parent.
tu as raison, c'est moi qui m'étais trompé
Pour ce qui est d'affecter NULL aux pointeurs désalloués, ça n'est demandé ni par la syntaxe, ni par la logique. On entre dans le domaine des goûts et des couleurs. L'aspect pratique, c'est que tu est sûr que tu n'as plus rien à désallouer, et que tu peux tester la valeur d'un pointeur avant de t'en servir, ce qui peut être utile pour le debogage.
Dans ton cas précis, affecter NULL aux fils ne sert à rien, ils ne seront plus accessibles de toutes manières dès que tu auras affecté NULL au parent.
Bonjour
Remarque préliminaire :
ce ne serait pas plutôt :
Question 1 :
Non, la signature de la fonction n'a pas à changer. Elle a toujours besoind des mêmes paramètres en entrée, ni plus ni moins et elle reste de type void.
Question 2 :
Tu passes une copie d'un pointeur. Mais ce que tu modifies dans ta fonction, ce n'est pas le pointeur, c'est la variable pointée. Or un pointeur et sa copie contiennent l'adresse de la même zone mémoire : toute modification de la zone mémoire pointée par l'un modifie la zone mémoire pointée par l'autre, puisque c'est la même !
Le problème aurait été tout différent si dans ta fonction tu faisais un i_Ptr_noeud=malloc(..) ou realloc(..)
Question 3 :
un Free à la racine de l'arbre ne suffit pas : la fonction free ne connaît rien de ta structure et est donc incapable de parcourir tous les noeuds. Tu es effectivement obligé de les libérer toi-même. Une fonction récursive, qui bien sûr libère les fils avant le noeud parent, est le meilleur moyen de le faire.
La signature que tu proposes me semble tout à fait convenir : là encore, tu ne cherches pas à récupérer une valeur modifiée du pointeur (tu en ferais quoi ?)
Remarque préliminaire :
size_t Taille_alloc_fils = i_Ptr_noeud->Nb_fils + 1;
ce ne serait pas plutôt :
size_t Taille_alloc_fils = (i_Ptr_noeud->Nb_fils + 1) * sizeof(unsigned int);
Question 1 :
Non, la signature de la fonction n'a pas à changer. Elle a toujours besoind des mêmes paramètres en entrée, ni plus ni moins et elle reste de type void.
Question 2 :
Tu passes une copie d'un pointeur. Mais ce que tu modifies dans ta fonction, ce n'est pas le pointeur, c'est la variable pointée. Or un pointeur et sa copie contiennent l'adresse de la même zone mémoire : toute modification de la zone mémoire pointée par l'un modifie la zone mémoire pointée par l'autre, puisque c'est la même !
Le problème aurait été tout différent si dans ta fonction tu faisais un i_Ptr_noeud=malloc(..) ou realloc(..)
Question 3 :
un Free à la racine de l'arbre ne suffit pas : la fonction free ne connaît rien de ta structure et est donc incapable de parcourir tous les noeuds. Tu es effectivement obligé de les libérer toi-même. Une fonction récursive, qui bien sûr libère les fils avant le noeud parent, est le meilleur moyen de le faire.
La signature que tu proposes me semble tout à fait convenir : là encore, tu ne cherches pas à récupérer une valeur modifiée du pointeur (tu en ferais quoi ?)
Bonjour le père, et merci pour tes réponses.
J'ai encore quelques questions pour toi suite à ton intervention...
Merci je vois que j'ai juste mis le nombre de case mémoire que je veux réserver mais pas leur taille...
Je fais un tableau de pointeur en gros, donc
Oui je comprends maintenant, j'ai confondu le pointeur que je passe en paramètre et mon tableau de pointeur sur la suite de l'arbre.
Donc si j'ai compris, puisque je modifie le noeud repéré les paramètres sont bons.
En fait, je pensais que si je passais par recopie le pointeur, la libération n'aurait pas eu lieu...
Une dernière question concernant ma fonction de libération mémoire:
Après la libération d'un noeud, est-il conseillé d'affecter le pointeur à null?
Voila la fonction en question:
J'ai encore quelques questions pour toi suite à ton intervention...
Remarque préliminaire : size_t Taille_alloc_fils = i_Ptr_noeud->Nb_fils + 1; ce ne serait pas plutôt : size_t Taille_alloc_fils = (i_Ptr_noeud->Nb_fils + 1) * sizeof(unsigned int);
Merci je vois que j'ai juste mis le nombre de case mémoire que je veux réserver mais pas leur taille...
Je fais un tableau de pointeur en gros, donc
size_t Taille_alloc_fils = (i_Ptr_noeud->Nb_fils + 1) * sizeof(unsigned int); doit être size_t Taille_alloc_fils = (i_Ptr_noeud->Nb_fils + 1) * sizeof(t_Noeud*); non? Ou est-ce peut être la même chose?
Question 1 : Non, la signature de la fonction n'a pas à changer. Elle a toujours besoin des mêmes paramètres en entrée, ni plus ni moins et elle reste de type void.
Oui je comprends maintenant, j'ai confondu le pointeur que je passe en paramètre et mon tableau de pointeur sur la suite de l'arbre.
Donc si j'ai compris, puisque je modifie le noeud repéré les paramètres sont bons.
Question3: [...]
En fait, je pensais que si je passais par recopie le pointeur, la libération n'aurait pas eu lieu...
Une dernière question concernant ma fonction de libération mémoire:
Après la libération d'un noeud, est-il conseillé d'affecter le pointeur à null?
Voila la fonction en question:
void Liberer_noeud(t_Noeud *i_Ptr_Noeud) { unsigned short i; //libération des noeuds fils for ( i = 0 ; i < i_Ptr_Noeud->Nb_fils ; i++ ) { Liberer_noeud(i_Ptr_Noeud->Fils[i]); i_Ptr_Noeud->Fils[i] = NULL; } free(i_Ptr_Noeud); }