Partage
  • Partager sur Facebook
  • Partager sur Twitter

Création d'une fonction pour une liste chaînée

Fonction permettant d'insérer un élément au milieu d'une liste chaînée

    3 avril 2023 à 19:26:45

    Bonjour

    Je dispose du code d'une liste chainée organisé de façon modulaire avec écrit

    dans le fichier main.c:

    #include <stdio.h>
    #include <stdlib.h>
    #include "liste chainee modulaire.h"
    
    int main()
    {
        Liste *maListe = initialisation();
    
        insertion(maListe, 4);
        insertion(maListe, 8);
        insertion(maListe, 15);
        suppression(maListe);
    
        afficherListe(maListe);
    
        return 0;
    }

    dans un fichier .h nommé "liste chainee modulaire.h":

    #ifndef LISTE_CHAINEE_MODULAIRE_H_INCLUDED
    #define LISTE_CHAINEE_MODULAIRE_H_INCLUDED
    
    typedef struct Element Element;
    struct Element
    {
        int nombre;
        Element *suivant;
    };
    
    typedef struct Liste Liste;
    struct Liste
    {
        Element *premier;
    };
    
    Liste *initialisation();
    void insertion(Liste *liste, int nvNombre);
    void suppression(Liste *liste);
    void afficherListe(Liste *liste);
    
    
    #endif // LISTE_CHAINEE_MODULAIRE_H_INCLUDED

    Et dans un fichier .c:

    #include <stdio.h>
    #include <stdlib.h>
    #include "liste chainee modulaire.h"
    
    Liste *initialisation()
    {
        Liste *liste = malloc(sizeof(*liste));
        Element *element = malloc(sizeof(*element));
    
        if (liste == NULL || element == NULL)
        {
            exit(EXIT_FAILURE);
        }
    
        element->nombre = 0;
        element->suivant = NULL;
        liste->premier = element;
    
        return liste;
    }
    
    
    void insertion(Liste *liste, int nvNombre)
    {
        /* Création du nouvel élément */
        Element *nouveau = malloc(sizeof(*nouveau));
        if (liste == NULL || nouveau == NULL)
        {
            exit(EXIT_FAILURE);
        }
        nouveau->nombre = nvNombre;
    
        /* Insertion de l'élément au début de la liste */
        nouveau->suivant = liste->premier;
        liste->premier = nouveau;
    }
    
    
    void suppression(Liste *liste)
    {
        if (liste == NULL)
        {
            exit(EXIT_FAILURE);
        }
    
        if (liste->premier != NULL)
        {
            Element *aSupprimer = liste->premier;
            liste->premier = liste->premier->suivant;
            free(aSupprimer);
        }
    }
    
    void afficherListe(Liste *liste)
    {
        if (liste == NULL)
        {
            exit(EXIT_FAILURE);
        }
    
        Element *actuel = liste->premier;
    
        while (actuel != NULL)
        {
            printf("%d -> ", actuel->nombre);
            actuel = actuel->suivant;
        }
        printf("NULL\n");
    }

    Lorsqu'on lance la console le programme affiche les unes derrière les autres avec des flèches qui les sépare: "8 -> 4 -> 0 -> NULL"

    Je souhaiterais y ajouter une fonction qui permet d'insérer un nouvel élément au milieu de la liste. Apparemment la fonction doit inclure comme paramètre l'adresse de l'élément qui précède celui à insérer, parcourir la liste puis placer celui à insérer derrière celui qui le précède. Le problème est que je ne vois pas quelles instructions permettent d'y arriver.

    //fonction pour insérer un élément au milieu de la liste
    void insertionAuMilieu(Liste *liste, Liste *listePrecedente, int nouveauNombre)
    {
        if (liste == NULL || listePrecedente == NULL)
        {
            exit(EXIT_FAILURE);
        }
    }

    Quelqu'un saurait-il comment peut-on s'y prendre pour créer cette fonction ?

    Cordialement





    -
    Edité par 1Stark 3 avril 2023 à 19:29:02

    • Partager sur Facebook
    • Partager sur Twitter
      3 avril 2023 à 19:45:56

      Bonjour,

      Apparemment la fonction doit inclure comme paramètre l'adresse de l'élément qui précède.
      Ca n'est pas ce que tu passes en paramètres! Je te propose plutôt:

      void insertionAuMilieu(Liste *liste, Element *elementPrecedent, int nouveauNombre)

      Ensuite tu dois rechercher l'élément désigné par elementPrecedent dans la liste.
      Puis insérer juste après un élément nouvellement créé.
      Attention, le cas où elementPrecedent est le premier de la liste est peut-être à bien gérer!

      • Partager sur Facebook
      • Partager sur Twitter

      En recherche d'emploi.

        4 avril 2023 à 7:08:38

        D'abord, je n'aime pas l'idée d'initialiser une liste chaînée avec un élément que je qualifie de "fictif".
        On devrait pouvoir insérer dans une liste vide.
        Il y a un risque de passer un pointeur vers l'élément cherché, mais ça n'est pas pire que de passer le descripteur de liste.
        Si on passe un pointeur NULL, on devrait pouvoir insérer à la fin de toute liste (même vide).
        Il est préférable d'attendre au moment de l'insertion pour créer le nouvel élément.
        Comme ça, si on a un problème, on ne crée pas un élément inutile.
         
        void insertionAuMilieu(Liste *liste, Element *elementPrecedent, int nouveau) {
            // Je ne vérifie pas si la liste n'existe pas ...
            Element *actuel = liste->premier;
            Element *precedent = NULL;
            while(actuel != NULL && actuel != elementPrecedent) {
                precedent = actuel;
                actuel = actuel->suivant;
            }
            if(actuel != NULL) {     // Si on veut insérer "après" l'élément cherché.
                precedent = actuel;
                actuel = actuel->suivant;
            }
            Element *ajout = malloc(sizeof(Element));
            ajout->suivant = actuel;
            ajout->nombre = nouveau;
            if(precedent != NULL) {
                precedent->suivant = ajout;
            } else {
                liste->premier = ajout;
            }
        }
        • Partager sur Facebook
        • Partager sur Twitter

        Le Tout est souvent plus grand que la somme de ses parties.

          4 avril 2023 à 17:07:03

          > D'abord, je n'aime pas l'idée d'initialiser une liste chaînée avec un élément que je qualifie de "fictif".

          En fait, c'est une idiotie liée à la confusion entre liste et pointeur sur maillon (lequel contient une valeur et l'adresse du suivant).

          De même l'idée

          Liste *maListe = initialisation();
           

          de ne pouvoir avoir une variable représentant une liste qu'à travers une allocation dynamique est remarquablement stupide.

          ----

          je suspecte que l'origine de cette erreur, c'est un cours réalisé par un mauvais programmeur qui avait commencé avec l'idée  liste = pointeur.

          C'est ce qui donne ce genre de truc déjà foireux

          typedef struct Maillon {
             ...
          } Maillon ;
          
          Maillon* ajouter_a_la_fin(struct Maillon *m, int v)
          {
             ...
          }
          
          

          où on récupère l'adresse du premier élément de la liste bricolée.

          Pourquoi ? Parce que si on considère qu'une liste est (à peu près) l'adresse d'un maillon, les opérations ajouter, enlever, etc  modifient la liste. et donc il serait logique de passer l'adresse de (la structure qui représente) cette liste puisqu'on la modifie

          void ajouter_a_la_fin(Liste *Liste, int v) {
             ....
          }
          

          MAIS

          Le type Liste n'ayant pas été mis en évidence conceptuellement, on en reste aux Maillons

          void ajouter_a_la_fin(Maillon ** m, int v)
          {
             ....
          }
          

          et SOUDAIN, C'EST LE DRAME ! la PANIQUE !  Un DOUBLE POINTEUR !  HORREUR, MALHEUR  ! "on ne peut quand même pas montrer ça au premier cours sur les pointeurs"

          Et donc là, RETRAITE STRATÉGIQUE : si on colle un élément fictif devant (*) il suffit de passer son adresse, c'est lui qui contient l'adresse du premier maillon. Quel génie.

          Bref, c'est du boulot complètement salopé.

          ---

          Une autre explication ça pourrait être de refuser d'avoir à appeler des fonctions avec des adresses obtenues par "&"

          Liste l;
          
          initialiser( & l);
          ajouter    ( & l, 12);
          ...
          


          C'est pas mieux, comme idée.   Quand on se lance dans les listes chaînées, normalement on doit avoir pris connaissance des petits secrets de C : des fois, on a besoin que les fonctions modifient ce qu'on leur passe en paramètre, et pour ça on passe l'adresse, que l'on manipule à travers un pointeur. Si on ne sais pas ça on a loupé des étapes, et c'est vraiment pas le moment de s'empêtrer en plus dans les chaînages, qui sont une autre histoire.

          (*) qui tient lieu maladroitement de struct Liste (on a un champ valeur qui ne sert à rien, et ça ne permet pas d'avoir un pointeur sur le dernier, ni le nombre d'éléments, ce qui serait une évolution fort utile).


          -
          Edité par michelbillaud 5 avril 2023 à 11:51:47

          • Partager sur Facebook
          • Partager sur Twitter
            6 avril 2023 à 14:28:26

            Bonjour

            Voici comment j'ai modifier mon fichier main.c:

            #include <stdio.h>
            #include <stdlib.h>
            #include "liste chainee modulaire.h"
            
            int main()
            {
                Liste *maListe = initialisation();
            
                insertion(maListe, 4);
                insertion(maListe, 8);
                insertion(maListe, 15);
                suppression(maListe);
                insertionAuMilieu(maListe, 4, 50);
            
                afficherListe(maListe);
            
                return 0;
            }

            mon fichier liste chainee modulaire.c

            #include <stdio.h>
            #include <stdlib.h>
            #include "liste chainee modulaire.h"
            
            Liste *initialisation()
            {
                Liste *liste = malloc(sizeof(*liste));
                Element *element = malloc(sizeof(*element));
            
                if (liste == NULL || element == NULL)
                {
                    exit(EXIT_FAILURE);
                }
            
                element->nombre = 0;
                element->suivant = NULL;
                liste->premier = element;
            
                return liste;
            }
            
            
            void insertion(Liste *liste, int nvNombre)
            {
                /* Création du nouvel élément */
                Element *nouveau = malloc(sizeof(*nouveau));
                if (liste == NULL || nouveau == NULL)
                {
                    exit(EXIT_FAILURE);
                }
                nouveau->nombre = nvNombre;
            
                /* Insertion de l'élément au début de la liste */
                nouveau->suivant = liste->premier;
                liste->premier = nouveau;
            }
            
            
            void suppression(Liste *liste)
            {
                if (liste == NULL)
                {
                    exit(EXIT_FAILURE);
                }
            
                if (liste->premier != NULL)
                {
                    Element *aSupprimer = liste->premier;
                    liste->premier = liste->premier->suivant;
                    free(aSupprimer);
                }
            }
            
            void afficherListe(Liste *liste)
            {
                if (liste == NULL)
                {
                    exit(EXIT_FAILURE);
                }
            
                Element *actuel = liste->premier;
            
                while (actuel != NULL)
                {
                    printf("%d -> ", actuel->nombre);
                    actuel = actuel->suivant;
                }
                printf("NULL\n");
            }
            //fonction pour insérer un élément au milieu de la liste
            void insertionAuMilieu(Liste *liste, Element *elementPrecedent, int nouveauNombre)
            {
                    // Je ne vérifie pas si la liste n'existe pas ...
                Element *actuel = liste->premier;
                Element *precedent = NULL;
                while(actuel != NULL && actuel != elementPrecedent) {
                    precedent = actuel;
                    actuel = actuel->suivant;
                }
                if(actuel != NULL) {     // Si on veut insérer "après" l'élément cherché.
                    precedent = actuel;
                    actuel = actuel->suivant;
                }
                Element *ajout = malloc(sizeof(Element));
                ajout->suivant = actuel;
                ajout->nombre = nouveau;
                if(precedent != NULL) {
                    precedent->suivant = ajout;
                }
                else {
                    liste->premier = ajout;
                }
            }
            

            et mon fichier liste chainee modulaire.h

            #ifndef LISTE_CHAINEE_MODULAIRE_H_INCLUDED
            #define LISTE_CHAINEE_MODULAIRE_H_INCLUDED
            
            typedef struct Element Element;
            struct Element
            {
                int nombre;
                Element *suivant;
            };
            
            typedef struct Liste Liste;
            struct Liste
            {
                Element *premier;
            };
            
            Liste *initialisation();
            void insertion(Liste *liste, int nvNombre);
            void suppression(Liste *liste);
            void afficherListe(Liste *liste);
            //prototype de la nouvelle fonction pour insérer un élément au milieu de la liste
            void insertionAuMilieu(Liste *liste, Element *elementPrecedent, int nouveauNombre);
            
            #endif // LISTE_CHAINEE_MODULAIRE_H_INCLUDED

            Lorsque je tente de lancer la console j'ai le message suivant qui apparemment, me dit que je n'ai pas déclarer "nouveau" dans la fonction:

            "error: 'nouveau' undeclared (first use in this function)"

            Serait-il convenable si j'ajoutais dans la fonction: "Element *nouveau = malloc(sizeof(*nouveau));" ?


            Cordialement

            -
            Edité par 1Stark 6 avril 2023 à 15:19:40

            • Partager sur Facebook
            • Partager sur Twitter
              6 avril 2023 à 16:54:08

              1Stark a écrit:

              Lorsque je tente de lancer la console j'ai le message suivant qui apparemment, me dit que je n'ai pas déclarer "nouveau" dans la fonction:

              Effectivement tu ne l'as pas déclaré. Mais je pense que ce n'est pas nouveau que tu voulais affecter à ajout->nombre mais le paramètre nouveauNombre .

              Aussi Quand tu appelles la fonction en question (insertionAuMilieu) tu ne peux pas l'appeler avec un entier en second paramètre puisqu'il est attendu un pointeur sur un élément : Element *elementPrecedent .

              -
              Edité par rouIoude 6 avril 2023 à 17:00:23

              • Partager sur Facebook
              • Partager sur Twitter
              ...
                6 avril 2023 à 18:33:36

                > Lorsque je tente de lancer la console

                C'est pas la console que tu lance (j'espère), mais la compilation de ton programme....  Je dis ça pas juste pour être pénible, mais parce qu'il va falloir distinguer "lancer la compilation" et "lancer l'exécution".
                Et les messages que tu obtiens ne sont pas l'avis de ChatGPT, mais des indications précises :

                "error: 'nouveau' undeclared (first use in this function)"

                ça ne laisse pas place au doute.  Il y a un "nouveau" qui apparait dans la fonction et sans y avoir été déclaré.


                Et surtout, bien regarder de quelle ligne ça cause.

                ---

                > Serait-il convenable si j'ajoutais dans la fonction: "Element *nouveau = malloc(sizeof(*nouveau));" ?

                Si tu veux programmer par essais et erreur, le mieux c'est que tu demandes directement au compilateur ce qu'il en pense, plutôt qu'aux participants d'un forum. Et si il accepte, que tu fasses tourner pour voir si ça marche.

                Mais nouveau, si c'est le truc que tu veux allouer (un nouvel élément), ben tu en as déjà un qui s'appelle ajout.... Il t'en faut vraiment deux ?

                ---

                Ca vaudrait de coup de remplacer les trois lignes suivantes,

                  Element *ajout = malloc(sizeof(Element));
                  ajout->suivant = actuel;
                  ajout->nombre = nouveau;
                


                Par un appel à une fonction qui fait l'allocation et l'initialisation

                Element *ajout = nouvel_element(nouveau, actuel);
                

                vu que ça revient un peu partout.

                Fonction laissée en exercice.



                -
                Edité par michelbillaud 7 avril 2023 à 6:45:54

                • Partager sur Facebook
                • Partager sur Twitter
                  6 avril 2023 à 20:18:19

                  rouIoude a écrit:

                  Aussi Quand tu appelles la fonction en question (insertionAuMilieu) tu ne peux pas l'appeler avec un entier en second paramètre puisqu'il est attendu un pointeur sur un élément : Element *elementPrecedent .

                  Peut-être 1Stark s'est-il mal exprimé, et qu'il souhaite ajouter après un maillion dont ptr->nombre contient la valeur passée en paramètre.

                  • Partager sur Facebook
                  • Partager sur Twitter

                  On écrit "j'ai tort", pas "tord" qui est le verbe "tordre" à la 3ème personne de l'indicatif présent

                    6 avril 2023 à 20:55:25

                    edgarjacobs a écrit:

                    rouIoude a écrit:

                    Aussi Quand tu appelles la fonction en question (insertionAuMilieu) tu ne peux pas l'appeler avec un entier en second paramètre puisqu'il est attendu un pointeur sur un élément : Element *elementPrecedent .

                    Peut-être 1Stark s'est-il mal exprimé, et qu'il souhaite ajouter après un maillion dont ptr->nombre contient la valeur passée en paramètre.

                    Je parlais de son code.

                    Prototype de la fonction :

                    void insertionAuMilieu(Liste *liste, Element *elementPrecedent, int nouveauNombre);

                    Appel :

                    insertionAuMilieu(maListe, 4, 50);

                    On ne peut pas mettre un entier ou un pointeur est attendu.




                    • Partager sur Facebook
                    • Partager sur Twitter
                    ...
                      7 avril 2023 à 0:09:55

                      rouIoude a écrit:

                      On ne peut pas mettre un entier ou un pointeur est attendu. 

                      Tout à fait d'accord avec toi, il se peut simplement qu'en temps que débutant il se soit emmêler les pinceaux



                      -
                      Edité par edgarjacobs 7 avril 2023 à 0:10:12

                      • Partager sur Facebook
                      • Partager sur Twitter

                      On écrit "j'ai tort", pas "tord" qui est le verbe "tordre" à la 3ème personne de l'indicatif présent

                        7 avril 2023 à 6:43:04

                        Sinon, si il s'agit de

                              Ajouter dans une liste une nouvelle valeur après un élément (maillon) qui est désigné par son adresse

                        il n'y a pas du tout besoin de parcourir la liste, puisqu'on sait déjà à quel maillon il faut ajouter un successeur.

                        ___ 

                        Le parcours, on a besoin de le faire quand le problème, c'est

                              Ajouter dans une liste une nouvelle valeur juste après la première occurrence d'une valeur que l'on indique.  Exemple  ajouter 12 après 43.

                        Là, il faudrait chercher le maillon qui contient 43.

                        -
                        Edité par michelbillaud 7 avril 2023 à 9:26:02

                        • Partager sur Facebook
                        • Partager sur Twitter
                          7 avril 2023 à 9:09:03

                          Bonjour 

                          J'ai modifié ma fonction comme suit dans mon fichier .c dans laquelle j'ai simplement déclaré "nouveau" comme je l'avais suggéré :

                          //fonction pour insérer un élément au milieu de la liste
                          void insertionAuMilieu(Liste *liste, Element *elementPrecedent, int nouveauNombre)
                          {
                                  // Je ne vérifie pas si la liste n'existe pas ...
                              Element *actuel = liste->premier;
                              Element *precedent = NULL;
                              Element *nouveau = malloc(sizeof(*nouveau));
                              while(actuel != NULL && actuel != elementPrecedent) {
                                  precedent = actuel;
                                  actuel = actuel->suivant;
                              }
                              if(actuel != NULL) {     // Si on veut insérer "après" l'élément cherché.
                                  precedent = actuel;
                                  actuel = actuel->suivant;
                              }
                              Element *ajout = malloc(sizeof(Element));
                              ajout->suivant = actuel;
                              ajout->nombre = nouveau;
                              if(precedent != NULL) {
                                  precedent->suivant = ajout;
                              }
                              else {
                                  liste->premier = ajout;
                              }
                          }

                          L'exécution accepte de se lancer même avec l'erreur d'avoir placé un entier en deuxième paramètre mais comme prévu j'obtiens un résultat non voulu qui me place une adresse avant "NULL":  8 -> 4 -> 0 -> 12916000 -> NULL

                          Toutes mes excuses pour mon manque de clarté : je voudrais demander à l'ordinateur "place-moi ce maillon contenant telle valeur derrière le tel ième maillon", par exemple "place-moi l'élément contenant 20 derrière le deuxième (et donc qui devra se situer entre 4 et 0)". La difficulté pour moi consiste à trouver la façon de prendre l'adresse de 4 pour compléter la fonction. Comment puis-je m'y prendre ?

                          Cordialement

                          -
                          Edité par 1Stark 7 avril 2023 à 9:16:05

                          • Partager sur Facebook
                          • Partager sur Twitter
                            7 avril 2023 à 9:27:56

                            Peux-tu expliquer pourquoi ta fonction insertionAuMilieu fait deux allocations mémoire ? (lignes 7 et 16)

                            >Toutes mes excuses pour mon manque de clarté : je voudrais demander à l'ordinateur "place-moi ce maillon contenant telle valeur derrière le tel ième maillon", par exemple "place-moi l'élément contenant 20 derrière le deuxième (et donc qui devra se situer entre 4 et 0)".

                            Si c'est ça que tu veux, dans le prototype

                            void insertionAuMilieu(Liste *liste, Element *elementPrecedent, int nouveauNombre)

                            quel paramètre correspond au 2  de "deuxième" (la position) ?



                            -
                            Edité par michelbillaud 7 avril 2023 à 11:45:23

                            • Partager sur Facebook
                            • Partager sur Twitter
                              7 avril 2023 à 10:24:35

                              Le paramètre nouveauNombre, il sert à quoi ?

                              Pourquoi affecter un pointeur sur un élément (Element *) à ajout->nombre qui attend un entier (int). 

                              • Partager sur Facebook
                              • Partager sur Twitter
                              ...
                                7 avril 2023 à 11:41:54

                                Y a un moment, il faut se poser, lâcher le code qu'on a écrit (*), et se poser la question : bon, qu'est-ce que ma fonction doit faire exactement ? Quels paramètres je lui donne ? Quel est l'effet sur la liste ?

                                Le comment, c'est à dire le code qui est censé faire ça, ça vient après.


                                --


                                un bon point de départ, c'est le genre de programme de test que tu as écrit au début

                                    Liste *maListe = initialisation();
                                 
                                    insertion(maListe, 4);
                                    insertion(maListe, 8);
                                    insertion(maListe, 15);
                                	
                                    insertionAuMilieu(maListe, 4, 50);  // appel
                                 
                                    afficherListe(maListe);

                                Ca devrait afficher quoi ?  Le 4 de l'appel, il dit qu'il fait ajouter un élément après (ou avant ?) celui qui contient 4, où avant/après celui qui est en position 4 (numéroté à partir de 0 ou de 1) ?

                                Mais déjà ça nous dit que que le second paramètre est un entier. Et ça ne colle pas du tout avec

                                void insertionAuMilieu(Liste *liste, Element *elementPrecedent, int nouveauNombre)
                                //                                   [      devrait être int  ]
                                





                                (*) psychologiquement, ce n'est pas facile, parce qu'on croit (fort de l'expérience trompeuse des petits exemples qu'on a programmé avant) comme ça compile, on y est presque. On aime bien croire des trucs, en fait, surtout ceux qui laissent penser qu'en bidouillant ici ou là ça finira par marcher. Bah non, ajouter une déclaration de nouveau, le compilateur arrêtera peut-être de râler, mais probable que ça ne marchera pas quand même.

                                -
                                Edité par michelbillaud 7 avril 2023 à 12:21:35

                                • Partager sur Facebook
                                • Partager sur Twitter
                                  7 avril 2023 à 13:47:45

                                  Pour que tout soit clair, il faut bien définir par ce que l'on entend par "insérer au milieu" ?

                                  1Stark a écrit:

                                  Je souhaiterais y ajouter une fonction qui permet d'insérer un nouvel élément au milieu de la liste. Apparemment la fonction doit inclure comme paramètre l'adresse de l'élément qui précède celui à insérer, parcourir la liste puis placer celui à insérer derrière celui qui le précède. 

                                  Dans ce cas le prototype de la fonction est correcte. Mais pour obtenir l'adresse de l'élément, il te faudra une autre fonction qui te retourne cette adresse selon les critères que tu souhaites. (par exemple l'adresse de l'élément ayant pour valeur 8).

                                  Est-ce que le prototype de la fonction est imposé ?

                                  Sinon comme te le suggère Michel tu peux faire en sorte que ta fonction insère le nouvel élément après l'élément qui a une certaine valeur. 

                                  • Partager sur Facebook
                                  • Partager sur Twitter
                                  ...
                                    7 avril 2023 à 18:32:43

                                    A priori, un cours qui parle d' insérer au milieu d'une liste est bon à jeter à la poubelle.

                                    Ajouter au début, ou à la fin : ça a un sens, ok.

                                    Par contre, "au milieu", c'est vaseux. Ca serait quoi le milieu d'une liste à un seul élément ? :-)

                                    Avec le recul, on devine que ce qui est sous-entendu, c'est qu'on n'ajoute pas forcément en tête ni en queue, mais à un autre endroit.  Et cet endroit, il faut le spécifier (voir plus haut) par un rang dans la liste (en première, seconde, troisième position, ...) par un repère (avant/après le premier ou le dernier élément qui contient ceci-cela), etc.

                                    Si c'est pas fait, si ça reste sous-entendu, et que l'endroit où il faut ajouter n'est pas explicité, c'est que le cours a été écrit par quelqu'un qui ne maîtrise pas le sujet, et ne sait pas l'expliquer.

                                    ---

                                    quand je lis,  sur https://openclassrooms.com/fr/courses/19980-apprenez-a-programmer-en-c/19733-stockez-les-donnees-avec-les-listes-chainees

                                    <<Insertion d'un élément en milieu de liste : si on veut pouvoir ajouter un élément au milieu, il faut créer une fonction spécifique qui prend un paramètre supplémentaire : l'adresse de celui qui précèdera notre nouvel élément dans la liste. Votre fonction va parcourir la liste chaînée jusqu'à tomber sur l'élément indiqué. Elle y insèrera le petit nouveau juste après.>>

                                    Ben, c'est la cata. Dans la fonction qui prend l'adresse de l'élément précédent (etc), il n'y a absolument pas besoin de faire une boucle. C'est juste  une allocation et un bidouillage pour le chaîner.

                                    void ajouter_apres(Element *precedent, int valeur)
                                    {
                                        // allocation
                                        Element *nouveau   = malloc(...);
                                        nouveau->valeur = valeur;
                                    
                                        // accrochage
                                        nouveau->suivant = precedent->suivant;
                                        precedent->suivant = nouveau;
                                    }
                                    

                                    Peut être qu'il veut dire que "ça serait bien" d'écrire une telle fonction, qu'on utiliserait dans une autre qui s'occupera de chercher l'élément avant lequel on "insèrera le petit nouveau". Ce qui nous ferait deux fonctions. Mais c'est pas ce qu'il dit. 

                                    Bref, du travail de goret.

                                    Avec un minimum de conscience professionnelle, les rédacteurs de cours viendraient voir sur les forums qui en parlent,  constateraient les problèmes que leur production bâclée cause (depuis des années) aux débutants, et rectifieraient le tir. Ben non.

                                    Ça m'énerve, au cas où vous auriez pas remarqué :-)





                                    -
                                    Edité par michelbillaud 7 avril 2023 à 18:51:31

                                    • Partager sur Facebook
                                    • Partager sur Twitter
                                      7 avril 2023 à 20:35:32

                                      michelbillaud a écrit:

                                      Ça m'énerve, au cas où vous auriez pas remarqué :-)

                                      Et nous, on en profite, par exemple en lisant les tutoriels de ton site dont certains, si j'ai bien compris, sont inspirés de ce que tu as vu ici... :)
                                      • Partager sur Facebook
                                      • Partager sur Twitter
                                        7 avril 2023 à 23:34:58

                                        Je suis sans doute quelque peu hors sujet, mais dans mon esprit (c'est peut-être là que se trouve le grain de sable), si on utilise une liste chainée, c'est qu'il y a quelque part un critère qui permet de trier cette liste.

                                        Je peux comprendre que l'on fasse mumuse en lisant simplement des données dans en fichier et en les collant en mémoire dans une liste chaînée en utilisant seulement un InsertFirst() ou un InserLast().

                                        Mais dans ce cas, à quoi bon une fonction InsertSomewhereButNotInFirstOrLastPosition() ? Il doit y avoir un critère pour insérer après (ou avant) tel maillon donné ou telle valeur à rechercher. Et si tel est le cas, pourquoi ne pas trier les éléments au fur et à mesure de leur apparition ?

                                        Bien sur, il y a l'aspect manipulation des pointeurs, mais comme le suggère MichelBillaud, pourquoi ne pas faire un tutoriel avec un exemple concret plutôt que d'aller battre la cambrousse avec des fonctions à la con noix.

                                        -
                                        Edité par edgarjacobs 7 avril 2023 à 23:39:30

                                        • Partager sur Facebook
                                        • Partager sur Twitter

                                        On écrit "j'ai tort", pas "tord" qui est le verbe "tordre" à la 3ème personne de l'indicatif présent

                                          7 avril 2023 à 23:49:18

                                          robun a écrit:

                                          michelbillaud a écrit:

                                          Ça m'énerve, au cas où vous auriez pas remarqué :-)

                                          Et nous, on en profite, par exemple en lisant les tutoriels de ton site dont certains, si j'ai bien compris, sont inspirés de ce que tu as vu ici... :)


                                          Euh, les tutoriels de mon truc ca vient en grande partie de cours que je faisais quand les rédacteurs de celui ci n'étaient probablement pas nés :)

                                          (Oui, on faisait des listes chaînées en Pascal)

                                          Mais effectivement les horreurs que je peux voir dans les cours ici (et leur effet sur d'innocents débutants), ca peut etre un déclencheur pour rédiger des trucs.

                                          -
                                          Edité par michelbillaud 7 avril 2023 à 23:52:56

                                          • Partager sur Facebook
                                          • Partager sur Twitter
                                            8 avril 2023 à 3:23:25

                                            @michelbillaud:
                                            Peux-tu me donner le lien vers ton tuto sur les listes chaînées?
                                            Pas que j'en ai besoin, mais je cherche trop souvent des exemples de tuto à donner comme références à ceux qui en ont besoin.
                                            Et je suis d'accord avec vous tous. Ça prend un critère pour insérer ailleurs qu'au début ou à la fin.
                                            • Partager sur Facebook
                                            • Partager sur Twitter

                                            Le Tout est souvent plus grand que la somme de ses parties.

                                              8 avril 2023 à 8:08:17

                                              C'est pas vraiment  un  tutoriel, c'est une partie  d'un document qui essaie d'expliquer les pointeurs et ce qu'on peut en faire. Notamment des structures chaînées, mais pas que.

                                              https://www.mbillaud.fr/docs/Pointeurs/pointeurs.html#cha%C3%AEnages

                                              PS y a aussi ça https://www.mbillaud.fr/docs/Conteneurs/conteneurs.html

                                              << Ce document montre les principes de fonctionnement de divers conteneurs (tableau extensible, listes chaînées, dictionnaire, …) en allant jusqu’aux détails d’implémentation.

                                              Pour aller au niveau le plus bas que permet la portabilité, l’implémentation est réalisée en C. >>

                                              -
                                              Edité par michelbillaud 8 avril 2023 à 9:39:42

                                              • Partager sur Facebook
                                              • Partager sur Twitter
                                                8 avril 2023 à 15:40:56

                                                Bonjour

                                                @michelbillaud 

                                                Peux-tu expliquer pourquoi ta fonction insertionAuMilieu fait deux allocations mémoire ? (lignes 7 et 16)

                                                J'ai essayé de voir ce que cela donnerait en me doutant que cela n'est pas convenable, car ne connaissant pas les instructions qui permettraient d'arriver à construire la fonction voulut.

                                                quel paramètre correspond au 2  de "deuxième" (la position) ?


                                                En supposant que j'écrive:

                                                #include <stdio.h>
                                                #include <stdlib.h>
                                                #include "liste chainee modulaire.h"
                                                
                                                int main()
                                                {
                                                    Liste *maListe = initialisation();
                                                
                                                    insertion(maListe, 4);
                                                    insertion(maListe, 8);
                                                    insertion(maListe, 34);
                                                
                                                    insertionAuMilieu(maListe, adresseDeLaDeuxiemeListe, 50);
                                                    insertion(maListe, 15);
                                                
                                                    afficherListe(maListe);
                                                
                                                    return 0;
                                                }

                                                La fonction doit prendre en premier paramètre dans cet exemple un élément de type "Liste", en deuxième paramètre l'adresse de tel ième liste et en troisième paramètre l'entier de cet élément Liste. Pour l'exemple ci-dessus, il doit y avoir affiché dans la console : 4 -> 8 -> 50 -> 34 -> 15. Le problème est que j'ignore comment demander l'adresse de tel ième maillon

                                                @rouIoude

                                                Le paramètre nouveauNombre, il sert à quoi ?

                                                Il s'agit du nombre que l'on est censé affiché dans la console à telle position : En troisième position dans l'exemple plus haut

                                                Pourquoi affecter un pointeur sur un élément (Element *) à ajout->nombre qui attend un entier (int).

                                                Peut-être une maladresse de ma part

                                                Pour que tout soit clair, il faut bien définir par ce que l'on entend par "insérer au milieu" ?

                                                Cela signifie que la chaîne comprend au minimum deux maillons et que le maillon à insérer peut se trouver n'importe ou entre les deux (si la chaine ne possède que deux maillons, inévitablement le maillon à insérer sera en deuxième position). Je suppose donc que la fonction doit inclure une condition if

                                                Est-ce que le prototype de la fonction est imposé ?

                                                Non, ce prototype à été écrit selon ma compréhension personnelle

                                                Sinon comme te le suggère Michel tu peux faire en sorte que ta fonction insère le nouvel élément après l'élément qui a une certaine valeur. 

                                                Si je fais comme cela, je suppose que le code prendra en compte le premier maillon ayant cette valeur, or dans la chaine plusieurs maillons peuvent avoir la même valeur:

                                                #include <stdio.h>
                                                #include <stdlib.h>
                                                #include "liste chainee modulaire.h"
                                                
                                                int main()
                                                {
                                                    Liste *maListe = initialisation();
                                                
                                                    insertion(maListe, 5);
                                                    insertion(maListe, 2);
                                                    insertion(maListe, 2);
                                                    insertion(maListe, 2);
                                                    insertion(maListe, 4);
                                                    insertion(maListe, 5);
                                                
                                                    afficherListe(maListe);
                                                
                                                    return 0;
                                                }


                                                Cordialement

                                                -
                                                Edité par 1Stark 9 avril 2023 à 19:28:36

                                                • Partager sur Facebook
                                                • Partager sur Twitter
                                                  8 avril 2023 à 17:23:26

                                                  1Stark a écrit:
                                                  La fonction doit prendre en premier paramètre dans cet exemple un élément de type "Liste", en deuxième paramètre l'adresse de tel ième liste et en troisième
                                                  paramètre l'entier de cet élément Liste. Pour l'exemple ci-dessus, il doit y avoir affiché dans la console : 4 -> 8 -> 50 -> 34 -> 15. Le problème est
                                                  que j'ignore comment demander l'adresse de tel ième maillon
                                                   
                                                  Je ne sais pas si tu crois que le 3ième paramètre est associé au 2ième.
                                                  Pour obtenir l'adresse associée au pointeur de type Element, il faut écrire une "autre" fonction.
                                                  Hé oui. il faut chercher dans cette nouvelle fonction l'endroit où tu veux insérer.
                                                  On se répète, mais tu dois donner dans cette nouvelle fonction le critère te disant à quel endroit insérer.
                                                  + Est-ce avant ou après une valeur dans la liste courante?
                                                  + Est-ce avant ou après la position relative au début (le 6ième élément par exemple)?
                                                  et on retourne le pointeur obtenu pour "ensuite" s'en servir dans la fonction d'insertion "au milieu" ...
                                                  • Partager sur Facebook
                                                  • Partager sur Twitter

                                                  Le Tout est souvent plus grand que la somme de ses parties.

                                                    8 avril 2023 à 18:21:59

                                                        insertionAuMilieu(maListe, adresseDeLaDeuxiemeListe, 50);

                                                    1Stark a écrit:

                                                    @rouIoude

                                                    Le paramètre nouveauNombre, il sert à quoi ?

                                                    Il s'agit du nombre que l'on est censé affiché dans la console à telle position : En troisième position dans l'exemple plus haut

                                                    Si j'ai dit ça, c'est que dans ta fonction, tu n'en fait rien du paramètre nouveauNombre ! 

                                                    plus haut je t'avais suggéré : 

                                                    rouIoude a écrit:

                                                    Effectivement tu ne l'as pas déclaré. Mais je pense que ce n'est pas nouveau que tu voulais affecter à ajout->nombre mais le paramètre nouveauNombre .

                                                    Tu n'as pas lu ?

                                                        insertionAuMilieu(maListe, adresseDeLaDeuxiemeListe, 50);
                                                     adresseDeLaDeuxiemeListe  (attention à ne pas confondre liste et élément).
                                                    Tu envois cette variable à ta fonction, ok, mais tu ne l'as pas définie et comment va tu obtenir l'adresse à affecter à cette variable ?


                                                    • Partager sur Facebook
                                                    • Partager sur Twitter
                                                    ...

                                                    Création d'une fonction pour une liste chaînée

                                                    × Après avoir cliqué sur "Répondre" vous serez invité à vous connecter pour que votre message soit publié.
                                                    × Attention, ce sujet est très ancien. Le déterrer n'est pas forcément approprié. Nous te conseillons de créer un nouveau sujet pour poser ta question.
                                                    • Editeur
                                                    • Markdown