Pile et listes chaînées

Fermé
Theo_0055 Messages postés 275 Date d'inscription mardi 21 juillet 2020 Statut Membre Dernière intervention 19 janvier 2023 - 1 nov. 2021 à 16:15
[Dal] Messages postés 6198 Date d'inscription mercredi 15 septembre 2004 Statut Contributeur Dernière intervention 13 décembre 2024 - 4 nov. 2021 à 12:02
Bonjour je voulais savoir comment on fait pour empiler une chaine de caractère dans une pile
Exemple: chaine={AGFGDG}
Je veux empiler ceci sur une pile mais je sais pas comment faire, pouvez vous m'aider svp

Je sais comment empiler un caractère mais un bloc contenant une chaine de caractère ,je sais pas

9 réponses

[Dal] Messages postés 6198 Date d'inscription mercredi 15 septembre 2004 Statut Contributeur Dernière intervention 13 décembre 2024 1 096
2 nov. 2021 à 09:36
Bonjour Theo_0055,

Une "pile" peut être implémentée de plusieurs façons en C.

Si tu disposes d'un code que tu as réalisé et qui gère une pile pour un caractère, il est possible que ton code puisse être adapté pour gérer des chaînes de caractères.

Utilises-tu une liste chaînée, un simple tableau, autre chose ?

Dal
0
Theo_0055 Messages postés 275 Date d'inscription mardi 21 juillet 2020 Statut Membre Dernière intervention 19 janvier 2023 1
2 nov. 2021 à 09:46
J’utilise une liste chaîné et une pile

Les caractères et chaînes de caractère sont dans ma liste chaîné et je veux empiler cela sur ma pile
0
[Dal] Messages postés 6198 Date d'inscription mercredi 15 septembre 2004 Statut Contributeur Dernière intervention 13 décembre 2024 1 096
2 nov. 2021 à 11:52
Dans ton code, tu dois donc certainement définir une struct, et avec ce type struct que tu attribues aux maillons de ta liste chaînée, tu dois stocker :
  • un moyen d'accéder à l'élément contenu dans le maillon
  • un pointeur sur l'élément suivant


Peux-tu poster ton type struct avec lequel tu gères une pile de char, stp ?

Tu dois aussi avoir des fonctions de manipulation de la pile, qui te permettent d'ajouter un élément, de retirer, retourner le nombre d'éléments de la pile, etc. Mais voyons déjà quelle tête a ton type.
0
Theo_0055 Messages postés 275 Date d'inscription mardi 21 juillet 2020 Statut Membre Dernière intervention 19 janvier 2023 1
2 nov. 2021 à 12:10
typedef struct Element Element;
struct Element{
    int nombre;
    Element *suivant;
};

typedef struct Pile Pile;
struct Pile{
    Element *sommet;
};

void empiler_char(Pile *pile,char&  carac){
   Element *nouveau = malloc(sizeof(*nouveau));
    if (pile == NULL || nouveau == NULL)
        exit(EXIT_FAILURE);
        
    nouveau->nombre = carac;
    nouveau->suivant = pile->sommet;
    pile->sommet = nouveau;
}

0
Theo_0055 Messages postés 275 Date d'inscription mardi 21 juillet 2020 Statut Membre Dernière intervention 19 janvier 2023 1
2 nov. 2021 à 12:11
Maintenant,je veux créer une fonction void empiler_chaineCarac qui empile une chaine de caractere
0

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

Posez votre question
Theo_0055 Messages postés 275 Date d'inscription mardi 21 juillet 2020 Statut Membre Dernière intervention 19 janvier 2023 1
2 nov. 2021 à 12:58
J’ai une petite piste esceque on doit faire tant que on a pas fini de parcourir la chaîné de caractère,on ajoute le caractère dans la pile en faisant appel à empiler_char?
0
[Dal] Messages postés 6198 Date d'inscription mercredi 15 septembre 2004 Statut Contributeur Dernière intervention 13 décembre 2024 1 096
Modifié le 2 nov. 2021 à 14:03
Salut Theo_0055,

OK, 2 remarques sur ton code avant d'entrer dans le vif du sujet : ton membre nombre est de type int, alors que tu veux y stocker des char ; deuxièmement dans ton prototype
void empiler_char(Pile *pile,char&  carac)
la partie
char&  carac
n'est pas du C (cela ressemble à une référence C++).

Tu peux rendre ton code plus générique en mettant le type géré dans un typedef.

Ton idée dans ce que tu postes est de stocker la donnée dans le maillon, mais en utilisant directement le type char dans les paramètres de ta fonction. En faisant cela, ton code d'ajout devient spécifique aux données traitées.

Une autre approche serait de rendre ton code plus générique pour que ta pile puisse traiter n'importe quel type de données avec un minimum de changements.

typedef char Donnee; 

typedef struct Element Element;
struct Element{
    Donnee donnee;
    Element *suivant;
};

void empiler_donnee(Pile *pile, Donnee donnee){
    if (pile == NULL)
        exit(EXIT_FAILURE);
    Element *nouveau = malloc(sizeof(*nouveau));
    if (nouveau == NULL)
        exit(EXIT_FAILURE);
        
    nouveau->donnee = donnee;
    nouveau->suivant = pile->sommet;
    pile->sommet = nouveau;
}


Ce code devrait gérer une pile de char en copiant le char passé en tant que type Donnee dans la pile.

Ensuite, il suffit de changer
typedef char Donnee; 
en
typedef char * Donnee; 
pour gérer une liste de pointeurs sur char où tu stockes des pointeurs sur char passés à la fonction empiler_donnees().

Cela fonctionne car, dans
empiler_donnee
, l'opérateur d'affectation dans
nouveau->donnee = donnee;
va simplement affecter un pointeur.

Si tu veux que ta liste gère une copie des données passées, stockée sous la forme de tableau de char dans la pile, alors tu peux le faire aussi, mais il faut ruser car l'opérateur d'affectation
=
ne permet pas l'affectation de types tableaux en langage C. En revanche, il peut gérer les struct. Donc, en rusant, tu peux réutiliser le même code en changeant ton type Donnee comme ceci :

#define MAX_LEN 500
typedef struct Donnee Donnee; 
struct Donnee {
    char str[MAX_LEN];
};


Dans
empiler_donnee()
, l'opérateur d'affectation à la ligne
nouveau->donnee = donnee;
va alors copier le contenu de la struct (en faisant une opération équivalente à un memcpy()).
0
Theo_0055 Messages postés 275 Date d'inscription mardi 21 juillet 2020 Statut Membre Dernière intervention 19 janvier 2023 1
2 nov. 2021 à 13:31
1.Pour le char& carac en fait c’était une erreur de frappe c’était char carac tout court sans &

2.Si j’ai bien compris
typedef char Donnee donnee =définition du type Donnee (qui est un char)

3.votre dernier Donnee il est censé gérer les chaînes de caractères c’est ça?

4.J’ai essayé plusieurs fois d’écrire un code pour gérer n’importe quel type de Donnee (char,int,double,..) mais le problème je sais pas comment m’y prendre
Car créer à chaque fois une fonction qui dépile int,une autre des char.. c’est un peu répétitif et j’aimerais créer une seule qui gère tous les types
0
[Dal] Messages postés 6198 Date d'inscription mercredi 15 septembre 2004 Statut Contributeur Dernière intervention 13 décembre 2024 1 096
2 nov. 2021 à 13:54
2.Si j’ai bien compris
typedef char Donnee donnee =définition du type Donnee (qui est un char)


oui

3.votre dernier Donnee il est censé gérer les chaînes de caractères c’est ça?

J'en au proposé deux qui sont susceptibles permettre au code gérant la liste de gérer des chaînes de caractères. Le dernier est l'un d'eux.

4.J’ai essayé plusieurs fois d’écrire un code pour gérer n’importe quel type de Donnee (char,int,double,..) mais le problème je sais pas comment m’y prendre
Car créer à chaque fois une fonction qui dépile int,une autre des char.. c’est un peu répétitif et j’aimerais créer une seule qui gère tous les types


Je viens de t'indiquer une façon de faire, le seul changement à faire étant sur le typedef qui définit le type de tes données.
0
Theo_0055 Messages postés 275 Date d'inscription mardi 21 juillet 2020 Statut Membre Dernière intervention 19 janvier 2023 1 > [Dal] Messages postés 6198 Date d'inscription mercredi 15 septembre 2004 Statut Contributeur Dernière intervention 13 décembre 2024
2 nov. 2021 à 14:03
Par exemple si je met
typedef char Donnee
typedef int Donnee


Ça peut générer des char et des int en même temp

Par exemple si empile_donnee ,on lui donne un int en 2 eme paramètre ça va marcher,de même que pour char?
0
[Dal] Messages postés 6198 Date d'inscription mercredi 15 septembre 2004 Statut Contributeur Dernière intervention 13 décembre 2024 1 096 > Theo_0055 Messages postés 275 Date d'inscription mardi 21 juillet 2020 Statut Membre Dernière intervention 19 janvier 2023
Modifié le 2 nov. 2021 à 14:46
Tu ne peux pas écrire cela, car cela revient à tenter de redéfinir un alias de type. Ma suggestion d'une modification minimale de ton code pour gérer un autre type de données que le char était que tu définisses ton alias de type Donnee avec le type de données que tu veux gérer dans ta pile. Ton code générique gérera ce type de données.

Maintenant tu sembles avoir un besoin différent. Si dans chaque maillon tu veux stocker un char et un int, tu peux créer un type Donnee qui soit une struct avec ces deux membres. Si dans chaque maillon tu veux stocker un char ou un int, tu peux créer une struct qui contient une union dans l'un de ses membres avec ces deux types et l'autre membre qui stocke le type (la façon courante de le faire est avec un enum).

Une autre façon de rendre ta pile générique est de stocker des
void *
dans ta pile et laisser le soin aux fonctions appelantes de passer le pointeur void et le transtyper lorsqu'il est récupéré. Tu avais posté un message où tu posais des questions sur les
void *
et qui a été supprimé (auquel j'avais répondu... ce qui fait que ma réponse a aussi été supprimée...). Cependant, tu ne pourras pas mélanger les types dans un même programme, à moins de stocker aussi dans une struct l'indication du type, car sinon la fonction appelante ne saura pas comment exploiter le pointeur.
0
Theo_0055 Messages postés 275 Date d'inscription mardi 21 juillet 2020 Statut Membre Dernière intervention 19 janvier 2023 1 > [Dal] Messages postés 6198 Date d'inscription mercredi 15 septembre 2004 Statut Contributeur Dernière intervention 13 décembre 2024
2 nov. 2021 à 16:37
Ah bon vous m’avez répondu,pourtant j’ai rien vu.je pensais que ma réponse a été ignoré d’où ma suppression
0
Theo_0055 Messages postés 275 Date d'inscription mardi 21 juillet 2020 Statut Membre Dernière intervention 19 janvier 2023 1 > [Dal] Messages postés 6198 Date d'inscription mercredi 15 septembre 2004 Statut Contributeur Dernière intervention 13 décembre 2024
2 nov. 2021 à 16:44
Par exemple ,esce qu’on peut écrire

typedef void * Donnee; 

typedef struct Element Element;
struct Element{
    Donnee donnee;
    Element *suivant; 

Et on met
 void empiler_donnee(Pile *pile, Donnee donnee){ 






Le void * va pointer sur n’importe quel type de donnée

Bon après vous avez dit que ça peut causer problème si le type n’est pas indiqué
Comment retranstyper?

Le void * ,m’a question est plus une question de curiosité qu’autre chose car en classe on l’a jamais utilisé
0
[Dal] Messages postés 6198 Date d'inscription mercredi 15 septembre 2004 Statut Contributeur Dernière intervention 13 décembre 2024 1 096
Modifié le 2 nov. 2021 à 16:31
Voilà une illustration d'une struct comprenant une union et un membre permettant de conserver le type de la donnée, en utilisant un enum pour codifier les types.

#include <stdlib.h>

enum type_donnee { CHAR, INT, DOUBLE, PCHAR, MAX_TYPES };
union val {
        char c;
        int i;
        double d;
        char * s;
};

typedef struct Donnee Donnee;
struct Donnee {
        union val val;
        enum type_donnee type;
};

typedef struct Element Element;
struct Element{
        Donnee donnee;
        Element *suivant;
};

typedef struct Pile Pile;
struct Pile{
        Element *sommet;
};

Pile * init_pile(void) {
        Pile * p = malloc(sizeof(*p));
        p->sommet = NULL;
        return p;
}

void empiler_donnee(Pile *pile, Donnee donnee){
        if (pile == NULL)
                exit(EXIT_FAILURE);
        Element *nouveau = malloc(sizeof(*nouveau));
        if (nouveau == NULL)
                exit(EXIT_FAILURE);

        nouveau->donnee = donnee;
        nouveau->suivant = pile->sommet;
        pile->sommet = nouveau;
}

int main(void) {
        Pile * p = init_pile();

        Donnee donnee;

        donnee.val.c = 'A'; donnee.type = CHAR;
        empiler_donnee(p, donnee);

        donnee.val.i = 123; donnee.type = INT;
        empiler_donnee(p, donnee);

        donnee.val.d = 123.45; donnee.type = DOUBLE;
        empiler_donnee(p, donnee);

        donnee.val.s = "saperlipopette"; donnee.type = PCHAR;
        empiler_donnee(p, donnee);

        return 0;
}


Lorsque tu dépiles, tu consultes d'abord le type récupéré, et, en fonction du type, tu accèdes à la valeur récupérée à travers l'union récupérée.


Dal
0
Theo_0055 Messages postés 275 Date d'inscription mardi 21 juillet 2020 Statut Membre Dernière intervention 19 janvier 2023 1
Modifié le 2 nov. 2021 à 17:07
Merci j’ai compris c’est plus clair là.

Je vais essayer de finir mon projet d'informatique et j'espère réussir a le finir sans demander de l'aide.
0
Theo_0055 Messages postés 275 Date d'inscription mardi 21 juillet 2020 Statut Membre Dernière intervention 19 janvier 2023 1
2 nov. 2021 à 17:17
Je voulais aussi savoir esceque on pouvait se passer du enum type_Donnee car pour moi union val gère déjà bien les type pour ma part
0
[Dal] Messages postés 6198 Date d'inscription mercredi 15 septembre 2004 Statut Contributeur Dernière intervention 13 décembre 2024 1 096 > Theo_0055 Messages postés 275 Date d'inscription mardi 21 juillet 2020 Statut Membre Dernière intervention 19 janvier 2023
Modifié le 2 nov. 2021 à 17:36
Si tu ne gardes pas trace du type, lorsque tu dépiles, tu ne sais pas comment accéder aux données stockées dans l'union pour qu'elle soient interprétées selon le bon type.

Comme je le disais :

Lorsque tu dépiles, tu consultes d'abord le type récupéré, et, en fonction du type, tu accèdes à la valeur récupérée à travers l'union récupérée.
0
[Dal] Messages postés 6198 Date d'inscription mercredi 15 septembre 2004 Statut Contributeur Dernière intervention 13 décembre 2024 1 096 > [Dal] Messages postés 6198 Date d'inscription mercredi 15 septembre 2004 Statut Contributeur Dernière intervention 13 décembre 2024
2 nov. 2021 à 18:09
Considère le code suivant :

        /* je mets à zéro la struct, car je vais faire des trucs funky */
        Donnee donnee = { 0 };
        char str[] = "saperlipopette";
        donnee.val.s = str;

        /* maintenant, disons que je récupère donnee de la Pile sans 
         * information sur le type, tous ces printf sont du C "valide"
         * mais un seul restitue correctement l'information stockée */
        printf("donnee est-elle une chaîne %s\n", donnee.val.s);
        printf("donnee est-elle un char %c\n", donnee.val.c);
        printf("donnee est-elle un entier %d\n", donnee.val.i);
        printf("donnee est-elle un double %f\n", donnee.val.d);


Comment vais-je l'exploiter ?

Il me faut stocker le type pour garder cette information.

Si le type que je stocke correspond à l'enum PCHAR et que, par convention, PCHAR désigne un pointeur sur char permettant d'accéder à une chaîne C, alors, je pourrais écrire ceci :

        Donnee donnee; 
        char str[] = "saperlipopette";
        donnee.val.s = str;
        donnee.type = PCHAR;

        /* maintenant, disons que je récupère donnee de la Pile avec
         * information sur le type. Je vais pouvoir déterminer comment
         * adapter mon printf selon le cas */
        switch (donnee.type) {
        case PCHAR:
                printf("donnee est une chaîne %s\n", donnee.val.s);
        break;
        case CHAR:
                printf("donnee est un char %c\n", donnee.val.c);
        break;
        case INT:
                printf("donnee est un entier %d\n", donnee.val.i);
        break;
        case DOUBLE:
                printf("donnee est un double %f\n", donnee.val.d);
        break;
        default:
                printf("Erreur : type non géré\n");
        }
0
Theo_0055 Messages postés 275 Date d'inscription mardi 21 juillet 2020 Statut Membre Dernière intervention 19 janvier 2023 1 > [Dal] Messages postés 6198 Date d'inscription mercredi 15 septembre 2004 Statut Contributeur Dernière intervention 13 décembre 2024
2 nov. 2021 à 18:21
Ok tout est clair désormais dans ma tête

Je voulais aussi savoir si j’ai une fonction
 int depiler (Pile * p) 

Le int avec ce que vous m’avez expliqué on peut le remplacer par
Donnee depiler (Pile * p)  
0
Theo_0055 Messages postés 275 Date d'inscription mardi 21 juillet 2020 Statut Membre Dernière intervention 19 janvier 2023 1
2 nov. 2021 à 16:34
Merci je vais essayer de comprendre et je vous refait signe
0