Pile et listes chaînées

Theo_0055 Messages postés 273 Date d'inscription   Statut Membre Dernière intervention   -  
[Dal] Messages postés 6122 Date d'inscription   Statut Contributeur Dernière intervention   -
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

  1. [Dal] Messages postés 6122 Date d'inscription   Statut Contributeur Dernière intervention   1 108
     
    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
  2. Theo_0055 Messages postés 273 Date d'inscription   Statut Membre Dernière intervention   1
     
    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
    1. [Dal] Messages postés 6122 Date d'inscription   Statut Contributeur Dernière intervention   1 108
       
      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
  3. Theo_0055 Messages postés 273 Date d'inscription   Statut Membre Dernière intervention   1
     
    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
  4. Theo_0055 Messages postés 273 Date d'inscription   Statut Membre Dernière intervention   1
     
    Maintenant,je veux créer une fonction void empiler_chaineCarac qui empile une chaine de caractere
    0
  5. Vous n’avez pas trouvé la réponse que vous recherchez ?

    Posez votre question
  6. Theo_0055 Messages postés 273 Date d'inscription   Statut Membre Dernière intervention   1
     
    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
  7. [Dal] Messages postés 6122 Date d'inscription   Statut Contributeur Dernière intervention   1 108
     
    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
  8. Theo_0055 Messages postés 273 Date d'inscription   Statut Membre Dernière intervention   1
     
    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
    1. [Dal] Messages postés 6122 Date d'inscription   Statut Contributeur Dernière intervention   1 108
       
      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
      1. Theo_0055 Messages postés 273 Date d'inscription   Statut Membre Dernière intervention   1 > [Dal] Messages postés 6122 Date d'inscription   Statut Contributeur Dernière intervention  
         
        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
      2. [Dal] Messages postés 6122 Date d'inscription   Statut Contributeur Dernière intervention   1 108 > Theo_0055 Messages postés 273 Date d'inscription   Statut Membre Dernière intervention  
         
        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
      3. Theo_0055 Messages postés 273 Date d'inscription   Statut Membre Dernière intervention   1 > [Dal] Messages postés 6122 Date d'inscription   Statut Contributeur Dernière intervention  
         
        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
      4. Theo_0055 Messages postés 273 Date d'inscription   Statut Membre Dernière intervention   1 > [Dal] Messages postés 6122 Date d'inscription   Statut Contributeur Dernière intervention  
         
        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
  9. [Dal] Messages postés 6122 Date d'inscription   Statut Contributeur Dernière intervention   1 108
     
    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
    1. Theo_0055 Messages postés 273 Date d'inscription   Statut Membre Dernière intervention   1
       
      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
    2. Theo_0055 Messages postés 273 Date d'inscription   Statut Membre Dernière intervention   1
       
      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
    3. [Dal] Messages postés 6122 Date d'inscription   Statut Contributeur Dernière intervention   1 108 > Theo_0055 Messages postés 273 Date d'inscription   Statut Membre Dernière intervention  
       
      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
    4. [Dal] Messages postés 6122 Date d'inscription   Statut Contributeur Dernière intervention   1 108 > [Dal] Messages postés 6122 Date d'inscription   Statut Contributeur Dernière intervention  
       
      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
    5. Theo_0055 Messages postés 273 Date d'inscription   Statut Membre Dernière intervention   1 > [Dal] Messages postés 6122 Date d'inscription   Statut Contributeur Dernière intervention  
       
      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
  10. Theo_0055 Messages postés 273 Date d'inscription   Statut Membre Dernière intervention   1
     
    Merci je vais essayer de comprendre et je vous refait signe
    0