IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

 C Discussion :

Listes simplement chainees - problème de pointeurs


Sujet :

C

  1. #21
    Expert confirmé
    Inscrit en
    Mars 2005
    Messages
    1 431
    Détails du profil
    Informations forums :
    Inscription : Mars 2005
    Messages : 1 431
    Points : 4 182
    Points
    4 182
    Par défaut
    Par pitié, penses à la planète ! Ne fais pas de captures d'écran de ton terminal, c'est du texte : copies-colles simplement son contenu entre balises CODE.

    Bon. decompose_ligne provoque potentiellement de jolies petites fuites de mémoire, je vois au moins un cas qui provoque une erreur de segmentation, on ne se sert pas des fonctions de la bibliothèque standard dédiées à l'analyse de chaînes, parfois on utilise strdup et parfois malloc/memcpy... passons. Je ne sais pas si tu as le droit de réécrire cette fonction mais c'est ce que je recommanderais.

    fgets ne « gère » pas les lignes vides/blanches, elle te renvoie simplement la chaîne "\n" (ou " \t \t\t \n"..) et c'est à toi de l'analyser. Ce que je vois ici c'est que decompose_ligne ne prend pas en compte le caractère '\n' qui va donc se retrouver à la fin de ton troisième élément.

    D'une manière générale il y a vraisemblablement des parties de ton programme dont tu n'es pas certaine du bon fonctionnement. Procède à des tests unitaires : isole ces parties, fonction par fonction s'il le faut, et intègre-les dans un programme vide indépendant du reste, que tu compiles et testes à part. Un exemple pour vérifier le bon fonctionnement de decompose_ligne justement (c'est juste un exemple, ajouter_serie_a_collection peut également être testée ainsi) :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    #include <stdio.h>
    #include <stdlib.h>
     
    #define NELEMS (unsigned int)3
     
    char **decompose_ligne(const char *line, unsigned int nelems) {
        /*
            ...
        */
    }
     
    int main(int argc, char *argv[]) {
        for (int i = 1; i < argc; ++i) {
            char **table = decompose_ligne(argv[i], NELEMS);
            if (!table)
                continue;
     
            printf("decomposition de : '%s'\n", argv[i]);
     
            for (unsigned int j = 0; j < NELEMS; ++j) {
                printf("  element %u : '%s'\n", j, table[j]);
                free(table[j]);
            }
     
            free(table);
        }
     
        return 0;
    }

  2. #22
    Membre à l'essai
    Femme Profil pro
    Étudiant
    Inscrit en
    Février 2016
    Messages
    26
    Détails du profil
    Informations personnelles :
    Sexe : Femme
    Localisation : France, Haute Saône (Franche Comté)

    Informations professionnelles :
    Activité : Étudiant
    Secteur : Enseignement

    Informations forums :
    Inscription : Février 2016
    Messages : 26
    Points : 22
    Points
    22
    Par défaut
    Citation Envoyé par Matt_Houston Voir le message

    Bon. decompose_ligne provoque potentiellement de jolies petites fuites de mémoire, je vois au moins un cas qui provoque une erreur de segmentation, on ne se sert pas des fonctions de la bibliothèque standard dédiées à l'analyse de chaînes, parfois on utilise strdup et parfois malloc/memcpy... passons. Je ne sais pas si tu as le droit de réécrire cette fonction mais c'est ce que je recommanderais.
    Merci Matt de prendre le temps de répondre et d'aider. Je n'ai pas le droit de changer la fonction decompose_ligne. En même temps, si je me sentais plus à l'aide je le tenterai. Je vais essayer d'utiliser votre code pour corriger le PB de lignes blanches.


    Citation Envoyé par Matt_Houston Voir le message
    D'une manière générale il y a vraisemblablement des parties de ton programme dont tu n'es pas certaine du bon fonctionnement. Procède à des tests unitaires : isole ces parties, fonction par fonction s'il le faut, et intègre-les dans un programme vide indépendant du reste, que tu compiles et testes à part.
    Je suis tout à fait d'accord. J'ai l'impression d'être dans un cercle vicieux où toutes les fonctions dépendent les unes des autres et n'ont pour paramètres que des listes crées à partir des autres fonctions. Je viens donc d'écrire un code simplifié pour essayer de tester mes fonctions creer_tome, afficher tome et liste_tri_bulles_tomes. Dans le main, j'essais de créer "à la main" une liste d'auteurs et une liste de tomes. Voici les fonctions:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <assert.h>
     
    typedef struct Auteur_s{
      char *nom;
    } Un_auteur;
     
    Un_auteur *creer_auteur(char *nom){
    Un_auteur *auteur=(Un_auteur*)malloc(sizeof(Un_auteur));
    auteur->nom=strdup(nom);
    return auteur;
    }
     
    typedef struct _un_element_auteurs *P_un_element_auteurs;
     
    typedef struct _un_element_auteurs {
      char mot[30];
      struct Auteur_s * element;
      P_un_element_auteurs suivant;
    } Un_element_auteurs;
     
     
    typedef struct Tome_s {
      char *titre;
      P_un_element_auteurs scenaristes;
      P_un_element_auteurs dessinateurs;
      int no_serie;
    } Un_tome;
     
    typedef struct _un_element_tomes *P_un_element_tomes;
     
    typedef struct _un_element_tomes {
      char mot[30];
      struct Tome_s * element;
      P_un_element_tomes suivant;
    } Un_element_tomes;
     
     
    Un_tome *creer_tome(char *titre, P_un_element_auteurs scenaristes, 
    P_un_element_auteurs dessinateurs, int no_serie) {
       Un_tome *tome = (Un_tome *)malloc(sizeof(Un_tome));
       assert(tome!= NULL);
        tome->titre=strdup(titre);
        tome->scenaristes=scenaristes;
        tome->dessinateurs=dessinateurs;
        tome->no_serie=no_serie;
    	return tome;
    }
     
     
     
    void afficher_tome(Un_tome *tome) {
      printf("\t %d. %s par le(s) scenaristes(s)",tome->no_serie,tome->titre);
     
      while(tome->scenaristes){
      printf("%s",tome->scenaristes->element->nom);
      tome->scenaristes=tome->scenaristes->suivant;
      }	
      printf("et le(s) dessinateur(s)");
     
      while(tome->dessinateurs){
      printf("%s\n",tome->dessinateurs->element->nom);
      tome->dessinateurs=tome->dessinateurs->suivant;
      }
    }
     
    void liste_tri_bulle_tomes(P_un_element_tomes *listes){
    P_un_element_tomes iliste = *listes, pliste, ppliste;
     
    while(iliste->suivant!=NULL && iliste->suivant->suivant!=NULL){
    pliste=iliste;
    ppliste=iliste->suivant;
    while(ppliste->suivant!=NULL){
    if(ppliste->element->no_serie < pliste->element->no_serie){
    pliste=ppliste;
    }
    ppliste=ppliste->suivant;
    }
     
    iliste=iliste->suivant;
    }
    }
    Voici le main:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    int main() {
     
    //pourquoi pas de valeur en retour?
     
    Un_auteur *auteur1=creer_auteur("Goscinny");
     
    printf("%s",auteur1->nom);
    Un_auteur *auteur2=creer_auteur("herge");
    printf("%s",auteur2->nom);
    Un_auteur *auteur3=creer_auteur("Uderzo");
    printf("%s",auteur3->nom);
     
     
    P_un_element_auteurs scenaristes=malloc(sizeof(Un_element_auteurs));
    scenaristes->element=auteur1;
    scenaristes->suivant->element=auteur2;
    scenaristes->suivant->suivant->element=auteur3;
     
    P_un_element_auteurs dessinateurs=malloc(sizeof(Un_element_auteurs));
    dessinateurs->element=auteur1;
    dessinateurs->suivant->element=auteur2;
    dessinateurs->suivant->suivant->element=auteur3;
     
    //comment je cree ma liste auteur?
     
     
    Un_tome *tome1 = creer_tome("Asterix le gaulois",scenaristes,dessinateurs, 12);
    Un_tome *tome2 = creer_tome("Asterix le gaulois",scenaristes,dessinateurs, 3);
    Un_tome *tome3 = creer_tome("Asterix le gaulois",scenaristes,dessinateurs, 20);
     
    //comment je cree ma liste tome?
     
    P_un_element_tomes tome=malloc(sizeof(Un_element_tomes));
    tome->element=tome1;
    tome->suivant->element=tome2;
    tome->suivant->suivant->element=tome3;
     
    afficher_tome(tome1);
     
    return 0;
    }
    Le programme compile sans PB mais j'obtiens encore un bus error...

    J'obtiens:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    Program received signal EXC_BAD_ACCESS, Could not access memory.
    Reason: KERN_PROTECTION_FAILURE at address: 0x00000020
    0x00001e74 in main () at test.c:101
    101	scenaristes->suivant->element=auteur2;
    Encore un PB d'accés à la mémoire donc d'un zéro si j'ai bien compris? Etant donne que les printf pour auteur1, auteur2 et auteur3 ne s'impriment pas, j'en conclus qu'il n'y a pas de valeurs à la sortir de la fonction creer_auteur... Et pourtant j'ai bien un "return auteur"?

    Merci encore

  3. #23
    Expert confirmé
    Inscrit en
    Mars 2005
    Messages
    1 431
    Détails du profil
    Informations forums :
    Inscription : Mars 2005
    Messages : 1 431
    Points : 4 182
    Points
    4 182
    Par défaut
    Tu as compris l'esprit : on isole la partie du code dont on désire vérifier le fonctionnement et on lui fait subir des cas d'utilisation.

    Il y a cependant un souci dans ce main lors de la création de tes listes. Que crois-tu qu'il se passe lorsque tu exécutes quelque chose de cette forme :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    P_un_element_auteurs scenaristes=malloc(sizeof(Un_element_auteurs));
    scenaristes->element=auteur1;
    scenaristes->suivant->element=auteur2; // Bim badaboum !
    scenaristes->suivant->suivant->element=auteur3; // Re-bim !

  4. #24
    Membre à l'essai
    Femme Profil pro
    Étudiant
    Inscrit en
    Février 2016
    Messages
    26
    Détails du profil
    Informations personnelles :
    Sexe : Femme
    Localisation : France, Haute Saône (Franche Comté)

    Informations professionnelles :
    Activité : Étudiant
    Secteur : Enseignement

    Informations forums :
    Inscription : Février 2016
    Messages : 26
    Points : 22
    Points
    22
    Par défaut
    OK merci

    Donc en enlevant les parties surlignées en rouge, mon code (au moins la fonction 'print' marche) mais par contre, non je ne comprends pas pourquoi je ne peux directement affecter les autres auteurs aux "*elements" des listes suivantes. Encore une histoire de pointeurs. Je vais continuer de chercher.

    Bonne nuit

  5. #25
    Expert confirmé
    Inscrit en
    Mars 2005
    Messages
    1 431
    Détails du profil
    Informations forums :
    Inscription : Mars 2005
    Messages : 1 431
    Points : 4 182
    Points
    4 182
    Par défaut
    Ce n'est pas tant l'accès au champ element qui pose souci que le déréférencement du champ suivant !

    Vois-tu la différence fondamentale entre :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    P_un_element_auteurs first = malloc(sizeof(Un_element_auteurs));
    first->element = auteur1;
     
    P_un_element_auteurs next = malloc(sizeof(Un_element_auteurs));
    first->suivant = next;
     
    first->suivant->element = auteur2;
    Et :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    P_un_element_auteurs first = malloc(sizeof(Un_element_auteurs));
    first->element = auteur1;
     
    P_un_element_auteurs next;
    first->suivant = next;
     
    first->suivant->element = auteur2;
    ?

  6. #26
    Membre à l'essai
    Femme Profil pro
    Étudiant
    Inscrit en
    Février 2016
    Messages
    26
    Détails du profil
    Informations personnelles :
    Sexe : Femme
    Localisation : France, Haute Saône (Franche Comté)

    Informations professionnelles :
    Activité : Étudiant
    Secteur : Enseignement

    Informations forums :
    Inscription : Février 2016
    Messages : 26
    Points : 22
    Points
    22
    Par défaut
    OK Matt - Je crois avoir bêtement compris mon erreur. Il n'y avait effectivement pas de mémoire à accéder pour l'auteur. Enfin si je comprends bien?Je viens de modifier mon code et ça a l'air de fonctionner (pour l'instant).

    Merci!

  7. #27
    Membre à l'essai
    Femme Profil pro
    Étudiant
    Inscrit en
    Février 2016
    Messages
    26
    Détails du profil
    Informations personnelles :
    Sexe : Femme
    Localisation : France, Haute Saône (Franche Comté)

    Informations professionnelles :
    Activité : Étudiant
    Secteur : Enseignement

    Informations forums :
    Inscription : Février 2016
    Messages : 26
    Points : 22
    Points
    22
    Par défaut
    Bonjour,

    Toujours sur les series et tome, je n'arrive pas à m'en sortir avec une fonction qui doit afficher les tomes manquants d'une série.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    void tomes_manquants(P_un_element_series collectionSeries, char *titre){
    Une_serie *serie = chercher_serie(collectionSeries, titre);
    if(serie!=NULL){
    int compte=0;
    int nb=serie->nb_parus;
    do{
    compte=compte+1;
    if(serie->tomes->element->no_serie!=compte){
    printf("Le tome %d manque dans ma collection!\n",compte);
    } else {
    serie->tomes=serie->tomes->suivant;
    }
    } while (compte!=nb);
    }
    return;
    }
    Mon résultat:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    Donnez le titre de la serie:Asterix
    Le tome 2 manque dans ma collection!
    Le tome 4 manque dans ma collection!
    Le tome 5 manque dans ma collection!
    Le tome 6 manque dans ma collection!
    Le tome 7 manque dans ma collection!
    Le tome 8 manque dans ma collection!
    Le tome 9 manque dans ma collection!
    Le tome 10 manque dans ma collection!
    Le tome 11 manque dans ma collection!
    Le tome 12 manque dans ma collection!
    Le tome 13 manque dans ma collection!
    Le tome 14 manque dans ma collection!
    Le tome 15 manque dans ma collection!
    Le tome 16 manque dans ma collection!
    Le tome 17 manque dans ma collection!
    Le tome 18 manque dans ma collection!
    Le tome 19 manque dans ma collection!
    Bus error
    ... tome 1, 3 et 20 de la série sont existants dans la collection.

    Étant donné que tous les tomes manquants doivent être affichés, la condition de sortie de ma boucle est le nombre de tomes parus (serie->nb_parus)... sauf que lorsque la boucle atteint le dernier tome existant de la liste (tome 20 ici) qui n'est pas le dernier tome de la serie mais de la liste serie (dernier tome est 36), le programme me donne un bus error (erreur d'accés à la mémoire) car effectivement serie->tomes->suivant est nulle. Je ne sais pas comment dire au programme qu'il doit continuer à afficher jusqu'à nb_parus sans être affecté par le dernier tome suivant NULL?

    Est-ce que quelqu'un peut me mettre sur la voie?

    Merci

  8. #28
    Membre à l'essai
    Femme Profil pro
    Étudiant
    Inscrit en
    Février 2016
    Messages
    26
    Détails du profil
    Informations personnelles :
    Sexe : Femme
    Localisation : France, Haute Saône (Franche Comté)

    Informations professionnelles :
    Activité : Étudiant
    Secteur : Enseignement

    Informations forums :
    Inscription : Février 2016
    Messages : 26
    Points : 22
    Points
    22
    Par défaut
    Rebonjour,

    je viens de solutionner le problème en insérant
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    serie->tomes->suivant=serie->tomes;
    à mon code.

    Merci

  9. #29
    Expert confirmé
    Inscrit en
    Mars 2005
    Messages
    1 431
    Détails du profil
    Informations forums :
    Inscription : Mars 2005
    Messages : 1 431
    Points : 4 182
    Points
    4 182
    Par défaut
    Tu n'as malheureusement rien solutionné. Il y a un gros souci avec tomes_manquants : c'est une procédure de consultation, elle doit de fait accéder à ses paramètres en lecture seule et les laisser inchangés. Hors tu modifies ici ta structure de données à chaque appel. La signature de la fonction devrait d'ailleurs être void tomes_manquants(const P_un_element_series collectionSeries, const char *titre) (ce qui ne garantit pas grand chose techniquement mais a le mérite de la clarté sémantique : on « annonce » à l'utilisateur qu'on n'accède aux paramètres qu'en lecture seule).

    Quelques conseils :
    • indentes et aères ton code, je ne sais pas si c'est le copier-coller qui fait cela mais tel quel c'est difficile à relire, surtout pour un débutant ;
    • avant de savoir exactement ce que tu fais, boucles uniquement via for et while (pas de do while, c'est moins indulgent) ;
    • utilises une variable de type « pointeur sur tome » pour parcourir la séquence d'exemplaires disponibles et teste la condition de fin de liste (pointeur nul), exemple (à adapter, et d'après ton code je suppose que la liste d'exemplaires disponibles est triée) :
      Code : Sélectionner tout - Visualiser dans une fenêtre à part
      1
      2
      3
      4
      5
      6
      7
      8
      9
      const tome_t *tome = serie->tomes->element;
      for (unsigned int i = 0; i < nb_parus; ++i) {
          unsigned int no_serie = i + 1; // car la numérotation des tomes se fait à partir de 1, j'imagine
       
          if (tome && tome->no_serie == no_serie) // tome == NULL lorsque la liste d'exemplaires disponibles est terminée
              tome = tome->suivant; // ici c'est la variable locale 'tome' qui est modifiée, la liste d'origine reste inchangée
          else
              printf("tome %u manquant\n", no_serie);
      }

  10. #30
    Membre à l'essai
    Femme Profil pro
    Étudiant
    Inscrit en
    Février 2016
    Messages
    26
    Détails du profil
    Informations personnelles :
    Sexe : Femme
    Localisation : France, Haute Saône (Franche Comté)

    Informations professionnelles :
    Activité : Étudiant
    Secteur : Enseignement

    Informations forums :
    Inscription : Février 2016
    Messages : 26
    Points : 22
    Points
    22
    Par défaut
    Matt merci.


    Citation Envoyé par Matt_Houston Voir le message
    Il y a un gros souci avec tomes_manquants : c'est une procédure de consultation, elle doit de fait accéder à ses paramètres en lecture seule et les laisser inchangés. Hors tu modifies ici ta structure de données à chaque appel.
    Je crois comprendre et non.
    serie->tomes=serie->tomes->suivant
    est bien la liste tomes et pas serie mais il vrai que je reaffecte a chaque fois tomes->suivant dans tomes... Sa veut dire quoi..? Que j'aurai plus que le dernier tome dans la liste tome a la fin de la boucle?


    La signature de la fonction devrait d'ailleurs être void tomes_manquants(const P_un_element_series collectionSeries, const char *titre) (ce qui ne garantit pas grand chose techniquement mais a le mérite de la clarté sémantique : on « annonce » à l'utilisateur qu'on n'accède aux paramètres qu'en lecture seule).
    Les signatures des fonctions ont ete donnees et si je rajoute des const, ça génère pas mal de problèmes. Il est vrai qu'il faudrait que je le fasse mais je ne suis pas sure de comprendre pourquoi collectionSeries est une const? Par exemple, comment je declare collectionSeries dans chercher_serie si on Const P_un_element_series collectionSeries?

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
     
    // seulement si les tomes sont ordonnes
    void tomes_manquants(P_un_element_series collectionSeries, char *titre){
    Une_serie *serie = chercher_serie(collectionSeries, titre);
    if((serie!=NULL) && (serie->tomes!=NULL)){
     
    int nb=serie->nb_parus;
    int i;
    int compte = 0;
    P_un_element_tomes tomes=serie->tomes;
    	Un_tome *tome=tomes->element;
    	for (i= 0; i <= nb-1; i++) {
    	compte=i+1;
    		if( tome && tome->no_serie==compte){
    		tomes=tomes->suivant;
    		tome=tomes->element;
    		if(tomes->suivant==NULL){
     		tomes->suivant=tomes;
     			}
    		} else {
    		printf("tome %d manquant\n",compte);
    		}	
    }
    }
    return;
    }
    je ne sais pas si c'est le copier-coller qui fait cela mais tel quel c'est difficile à relire
    non c'est comme ça sur TextWrangler. Je n'arrive pas à indenter mon texte même si j'ai l'option "Allow tab key to indent text blocks" activee dans Preferences->Editing:keyboard. Il doit y avoir autre à faire mais je n'ai pas trouvé.

    utilises une variable de type « pointeur sur tome » pour parcourir la séquence d'exemplaires disponibles et teste la condition de fin de liste (pointeur nul), exemple (à adapter, et d'après ton code je suppose que la liste d'exemplaires disponibles est triée)
    J'ai modifié mon code pour avoir le pointeur sur tome mais je ne suis pas sure que ça change qqch par rapport à ce que j'ai fait avant?

    Merci - Bonne soiree

  11. #31
    Expert confirmé
    Inscrit en
    Mars 2005
    Messages
    1 431
    Détails du profil
    Informations forums :
    Inscription : Mars 2005
    Messages : 1 431
    Points : 4 182
    Points
    4 182
    Par défaut
    Non ça ne va pas. Laisses tomber les const pour l'instant, ce qu'il faut comprendre c'est qu'il ne faut pas modifier les données en les consultant.

    Prenons les choses dans l'ordre : de quelle façon parcoures-tu une liste chaînée basique ?
    Par exemple, que mets-tu dans list_print ci-dessous ?
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    typedef struct node {
        int value;
     
        struct node *next;
    } node_t;
     
    /* Prints the value of struct member 'value' to stdout for each element in linked list 'list'.
       /!\ 'list' may be NULL! */
    void list_print(const node_t *list) {
        // ???
    }

  12. #32
    Membre à l'essai
    Femme Profil pro
    Étudiant
    Inscrit en
    Février 2016
    Messages
    26
    Détails du profil
    Informations personnelles :
    Sexe : Femme
    Localisation : France, Haute Saône (Franche Comté)

    Informations professionnelles :
    Activité : Étudiant
    Secteur : Enseignement

    Informations forums :
    Inscription : Février 2016
    Messages : 26
    Points : 22
    Points
    22
    Par défaut
    Bonjour Matt,

    Je ferai comme ça:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    void list_print(const node_t *list) {
    	while (list){
    printf("%d",list->value);
    list=list->next;
    	}	
    }
    Merci

  13. #33
    Expert confirmé
    Inscrit en
    Mars 2005
    Messages
    1 431
    Détails du profil
    Informations forums :
    Inscription : Mars 2005
    Messages : 1 431
    Points : 4 182
    Points
    4 182
    Par défaut
    Oui c'est exactement cela. Je me permets de réécrire ta proposition sous cette forme avant d'introduire la suite (c'est équivalent) :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    void list_print1(const node_t *list) {
        const node_t *local = list;
     
        while (local){
            printf("%d ", local->value);
            local = local->next;
        }
    }

    Considères maintenant le programme suivant :
    Code ptr_test.c : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    #include <stdio.h>
     
     
    typedef struct node {
        int value;
     
        struct node *next;
    } node_t;
     
     
    void list_print1(const node_t *list) {
        const node_t *local = list;
     
        while (local){
            printf("%d ", local->value);
            local = local->next;
        }
    }
     
    void list_print2(/*const */node_t *list) {
        /*const */node_t *local = list;
     
        if (!local)
            return; // empty list
     
        while (local->next){
            printf("%d ", local->next->value);
            local->next = local->next->next;
        }
    }
     
     
    int main(int argc, char *argv[]) {
        (void)argc; (void)argv; // disable irrelevant compiler warnings
     
        node_t n4 = {  42, NULL };
        node_t n3 = {   5,  &n4 };
        node_t n2 = { -18,  &n3 };
        node_t n1 = { 666,  &n2 };
     
        printf("list_print1 says: "); list_print1(&n1); printf("\n");
        printf("list_print1 says: "); list_print1(&n1); printf("\n");
        printf("list_print1 says: "); list_print1(&n1); printf("\n");
     
        printf("list_print2 says: "); list_print2(&n1); printf("\n");
     
        printf("list_print1 says: "); list_print1(&n1); printf("\n");
        printf("list_print1 says: "); list_print1(&n1); printf("\n");
     
        return 0;
    }

    Tu peux le compiler et l'exécuter comme ceci :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    $ gcc -std=c11 -pedantic -Wall -Wextra ptr_test.c
    $ ./a.out
    Arrêtons-nous là le temps de comprendre ce qui se passe. Vois-tu la différence entre les traitements réalisés par list_print1 et list_print2 ? Tu en avais déjà décelé les conséquences dans un de tes précédents messages mais le souci est ici isolé.

    Que se passe-t-il si tu décommentes les const lignes 20 et 21 ? Attention ce n'est pas le mot-clef const en lui-même qui est important ici, c'est de bien comprendre la manière dont les adresses mémoire sont manipulées via les pointeurs.

    Que peux-tu en déduire sur la manière d'itérer proprement sur ta collection de tomes disponibles dans ton problème original ?

  14. #34
    Membre à l'essai
    Femme Profil pro
    Étudiant
    Inscrit en
    Février 2016
    Messages
    26
    Détails du profil
    Informations personnelles :
    Sexe : Femme
    Localisation : France, Haute Saône (Franche Comté)

    Informations professionnelles :
    Activité : Étudiant
    Secteur : Enseignement

    Informations forums :
    Inscription : Février 2016
    Messages : 26
    Points : 22
    Points
    22
    Par défaut
    Matt, merci pour votre temps;

    En reprenant votre code et avec les Const activés ou non sur liste_print2, j'obtiens:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    list_print says: 666-18542
    list_print says: 666-18542
    list_print says: 666-18542
    list_print2 says: -18 5 42 
    list_print2 says: 
    list_print2 says:
    Je comprends que la difference entre les deux (liste_print 1 & 2) est que la premiere balaie la liste list (local) sans rien détruire. La deuxième, en revanche, réaffecte la valeur de la liste suivante dans la locale et ainsi détruis toute la liste sauf la dernière avant le NULL.

    Je pense comprendre qu'en theorie il faut utiliser au maximum la liste dans laquelle on travaille.


    Citation Envoyé par Matt_Houston Voir le message
    Tu n'as malheureusement rien solutionné. Il y a un gros souci avec tomes_manquants : c'est une procédure de consultation, elle doit de fait accéder à ses paramètres en lecture seule et les laisser inchangés. Hors tu modifies ici ta structure de données à chaque appel. La signature de la fonction devrait d'ailleurs être void tomes_manquants(const P_un_element_series collectionSeries, const char *titre) (ce qui ne garantit pas grand chose techniquement mais a le mérite de la clarté sémantique : on « annonce » à l'utilisateur qu'on n'accède aux paramètres qu'en lecture seule).

    En reprenant votre code:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    const tome_t *tome = serie->tomes->element;
    for (unsigned int i = 0; i < nb_parus; ++i) {
        unsigned int no_serie = i + 1; // car la numérotation des tomes se fait à partir de 1, j'imagine
     
        if (tome && tome->no_serie == no_serie) // tome == NULL lorsque la liste d'exemplaires disponibles est terminée
            tome = tome->suivant; // ici c'est la variable locale 'tome' qui est modifiée, la liste d'origine reste inchangée
        else
            printf("tome %u manquant\n", no_serie);
    }
    [/LIST]
    ici tome est un enregistrement qui ne possede pas d'element suivant. L'element suivant se trouve dans la liste tomes. c'est donc cette liste que je veux utiliser pour variable locale. Comme la condition de sortie de la boucle est nb_parus, je ne peux donc pas utiliser tomes=tomes->suivant dans la boucle while. Je ne saisis pas comment accéder à l'élement tome suivant sans le détruire. J'ajoute ici mon dernier code. Il est surement 'presque' identique a mes precedents.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    void tomes_manquants(P_un_element_series collectionSeries, char *titre){
    Une_serie *serie = chercher_serie(collectionSeries, titre);
    	if((serie!=NULL) && (serie->tomes!=NULL)){
     
    P_un_element_tomes tomes=serie->tomes;
    int nb=serie->nb_parus;
    int i;
    int no_serie;
     
    		for ( i = 0; i < nb-1; i++) {
        		no_serie = i + 1; 
        		Un_tome *tome=tomes->element;
     
       		 	if (tomes && tome->no_serie == no_serie) {
            		tomes = tomes->suivant;
     
            		if(tomes->suivant==NULL){
    					tomes->suivant=tomes;
      				}
      			} else
            		printf("tome %u manquant\n", no_serie);
    		}
    	}
    return;
    }


    Merci encore pour votre aide. J'espere enfin comprendre quand la correction du devoir sera rendu.

  15. #35
    Expert confirmé
    Inscrit en
    Mars 2005
    Messages
    1 431
    Détails du profil
    Informations forums :
    Inscription : Mars 2005
    Messages : 1 431
    Points : 4 182
    Points
    4 182
    Par défaut
    Citation Envoyé par Audinet Voir le message
    Je pense comprendre qu'en theorie il faut utiliser au maximum la liste dans laquelle on travaille.
    Il faut surtout ne pas modifier la valeur de l'objet pointé comme tu le fais ligne 18 dans ton dernier essai !

    tomes = tomes->suivant; : ok, tomes est une variable locale que j'ai créée pour me déplacer au sein de la liste, je peux donc la modifier librement.
    tomes->suivant = tomes; : pas ok, ici je ne modifie pas la valeur du pointeur (l'adresse mémoire) mais directement l'élément pointé (en l'occurrence lui-même un pointeur du même type) ! D'ailleurs si tomes était déclaré const TYPE *, le compilateur me l'interdirait. Si j'ai ce type d'affectation dans ma fonction de consultation, je suis déjà certain qu'il y a une erreur quelque part.


    Citation Envoyé par Audinet Voir le message
    ici tome est un enregistrement qui ne possede pas d'element suivant. L'element suivant se trouve dans la liste tomes. c'est donc cette liste que je veux utiliser pour variable locale. Comme la condition de sortie de la boucle est nb_parus, je ne peux donc pas utiliser tomes=tomes->suivant dans la boucle while.
    Je n'ai pas d'objection, comme je l'ai dit mon exemple n'était pas destiné à être utilisé tel quel. Je n'avais pas relu la configuration de tes structures de données en l'écrivant. Tu dois effectivement parcourir une liste de P_un_element_tomes plutôt que de Un_tome * (dieu que cette nomenclature est affreuse...).


    Citation Envoyé par Audinet Voir le message
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    void tomes_manquants(P_un_element_series collectionSeries, char *titre){
    Une_serie *serie = chercher_serie(collectionSeries, titre);
    	if((serie!=NULL) && (serie->tomes!=NULL)){
     
    P_un_element_tomes tomes=serie->tomes;
    int nb=serie->nb_parus;
    int i;
    int no_serie;
     
    		for ( i = 0; i < nb-1; i++) {
        		no_serie = i + 1; 
        		Un_tome *tome=tomes->element;
     
       		 	if (tomes && tome->no_serie == no_serie) {
            		tomes = tomes->suivant;
     
            		if(tomes->suivant==NULL){
    					tomes->suivant=tomes;
      				}
      			} else
            		printf("tome %u manquant\n", no_serie);
    		}
    	}
    return;
    }
    C'est presque ça, quelques indices :
    • ligne 3, si la série est manquante ou vide il faut tout de même afficher les tomes manquants d'après ta description de l'énoncé ;
    • ligne 12, si tomes == NULL (relatif au premier point évoqué), boum ;
    • ligne 17, à quoi sert ce if au final ?

  16. #36
    Membre à l'essai
    Femme Profil pro
    Étudiant
    Inscrit en
    Février 2016
    Messages
    26
    Détails du profil
    Informations personnelles :
    Sexe : Femme
    Localisation : France, Haute Saône (Franche Comté)

    Informations professionnelles :
    Activité : Étudiant
    Secteur : Enseignement

    Informations forums :
    Inscription : Février 2016
    Messages : 26
    Points : 22
    Points
    22
    Par défaut
    Citation Envoyé par Matt_Houston Voir le message
    C'est presque ça, quelques indices :
    • ligne 3, si la série est manquante ou vide il faut tout de même afficher les tomes manquants d'après ta description de l'énoncé ;
    • ligne 12, si tomes == NULL (relatif au premier point évoqué), boum ;
    • ligne 17, à quoi sert ce if au final ?
    Ok merci c'est vrai tous tomes doit etre affiche.

    Ligne 12 -> oui c'est le probleme. Et ça me donne le bus error d'accés à la memoire donc ligne 17 'résout' le probleme en reaffectant le dernier tome a suivant jusqu'a la sortie de la boucle sur nb. C'est la seule solution que j'ai trouve pour enlever le fait que le dernier tome de la liste n'est pas forcement le dernier de la serie.

    Bonne soiree

+ Répondre à la discussion
Cette discussion est résolue.
Page 2 sur 2 PremièrePremière 12

Discussions similaires

  1. problème liste simplement chainée
    Par cyrill.gremaud dans le forum C
    Réponses: 9
    Dernier message: 04/12/2012, 15h40
  2. tri par insertion, list simplement chainee
    Par Maf77 dans le forum C
    Réponses: 24
    Dernier message: 12/11/2008, 19h30
  3. Réponses: 2
    Dernier message: 12/10/2007, 11h32
  4. Réponses: 20
    Dernier message: 22/03/2006, 14h00
  5. problème de pointeur avec les listes chainees
    Par innosang dans le forum C
    Réponses: 9
    Dernier message: 30/12/2005, 15h46

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo