2017-09-15 5 views
1

Est-ce que j'utilise incorrectement fgets()?C: utilisation de fgets pour construire une liste chaînée de char *

J'essaye de construire une liste liée de chaînes (char *) en ajoutant chaque nouvelle ligne à la fin de la LL. Je lis ces lignes à partir d'un fichier, mais pour une raison quelconque, chaque ligne est écrasée par la ligne en cours de traitement, uniquement lorsque vous utilisez fgets() dans la boucle while, mais la fonction d'ajout semble recevoir chaque ligne correctement.

Si j'ajoute des lignes individuellement dans main(), il n'y a aucun problème.

Voici un fichier d'entrée exemple:

input.txt:

This life, which had been the 
tomb of his virtue and of his 
honour, is but a walking 
shadow; a poor player, that 
struts and frets his hour upon 
the stage, and then is heard 
no more: it is a tale told by an 
idiot, full of sound and fury, 
signifying nothing. 
    --William Shakespeare 

Le code:

#include <stdio.h> //printf, fopen 
#include <stdlib.h> //exit, EXIT_FAILURE 
#include <string.h> //strlen 

struct node { 
    char *line; 
    struct node *next; 
}; 

void print(struct node *node); 

void add(struct node **head, char *newLine) { 
    //printf("%s", newLine); 

    struct node *new_node = (struct node *)malloc(sizeof(struct node)); 
    struct node *curr = *head; 

    new_node->line = newLine; 
    new_node->next = NULL; 

    if (*head == NULL) { 
     *head = new_node; 
    } else { 
     while (curr->next != NULL) { 
      curr = curr->next; 
     } 
     curr->next = new_node; 
    } 
    print(*head); 
} 

void print(struct node *node) { 
    printf("\n"); 

    while (node != NULL) { 
     printf("%s\n", node->line); 
     node = node->next; 
    } 
} 

int main(int argc, char *argv[16]) { 
    char newLine[81]; 
    struct node *head = NULL; 
    FILE *fp = fopen(argv[1], "r"); 

    if (fp == NULL) { 
     printf("ERROR: file open failed"); 
     exit(EXIT_FAILURE); 
    } 

    while (fgets(newLine, 81, fp)) { 
     add(&head, newLine); 
    } 

    add(&head, "why"); 
    add(&head, "does"); 
    add(&head, "this"); 
    add(&head, "work??"); 

    fclose(fp); 

    print(head); 

    return 0; 
} 

Quelqu'un pourrait-il expliquer s'il vous plaît me ce qui se passe? Je me suis cogné la tête contre un mur pendant trop longtemps. Il y a déjà quelques instructions d'impression commentées que j'essayais d'utiliser, sans succès pour le débogage.

+0

chercher du papier. Tracez les appels à 'add' et dessinez une représentation de votre liste chaînée. Portez une attention particulière à ce que 'node-> line' pointe vers. –

+0

Il y a plusieurs kilodupes de ce comportement; –

Répondre

1

Votre problème est dans la méthode add(). Il continue à ajouter le même pointeur de tampon à la liste. Vous devez copier le tampon de votre liste dans l'espace nouvellement alloué, c'est-à-dire. node-> line doit aussi être mallocé, et la newLine doit être copiée dedans. Ne pas oublier de malloc (strlen (newLine) + 1).

0

Vous avez un tampon où vous stockez l'entrée. Et vous passez un pointeur sur le premier élément de ce tampon unique lors de l'ajout de nœuds. Cela signifie que le pointeur de chaîne dans tous les nœuds pointe vers le même tampon unique. Ce qui à la fin contiendra la dernière chaîne que vous avez lue.

La solution la plus simple consiste à faire de la chaîne de la structure de noeud un tableau et à y copier la chaîne.

Une autre solution consiste à allouer dynamiquement de la mémoire pour la chaîne (en rappelant le caractère nul final) et à copier à nouveau la chaîne dans cette mémoire. La différence lors de l'utilisation de littéraux à chaînes constantes est que chacune des chaînes sera un tableau différent.

0

Vous devez allouer de la mémoire pour chaque ligne. Comme codé actuellement, tous les nœuds pointent vers le tableau local au main() dont le contenu est remplacé par chaque appel à fgets().

Notez également que chaque ligne ajoutée à la liste contient une nouvelle ligne de terminaison dont vous devriez probablement vous débarrasser avant l'appel.

Voici une version corrigée:

#include <stdio.h> // printf, fopen 
#include <stdlib.h> // exit, EXIT_FAILURE 
#include <string.h> // strlen, strdup 

struct node { 
    char *line; 
    struct node *next; 
}; 

void print(struct node *node); 

void add(struct node **head, char *newLine) { 
    //printf("%s", newLine); 

    struct node *new_node = malloc(sizeof(struct node)); 
    struct node *curr = *head; 

    new_node->line = strdup(newLine); 
    new_node->next = NULL; 

    if (*head == NULL) { 
     *head = new_node; 
     return; 
    } 

    while (curr->next != NULL) { 
     curr = curr->next; 
    } 

    curr->next = new_node; 
    print(*head); 
} 

void print(const struct node *node) { 
    printf("\n"); 

    while (node != NULL) { 
     printf("%s\n", node->line); 
     node = node->next; 
    } 
} 

int main(int argc, char *argv[16]) { 
    char newLine[81]; 
    struct node *head = NULL; 
    FILE *fp = fopen(argv[1], "r"); 

    if (fp == NULL) { 
     printf("ERROR: file open failed"); 
     exit(EXIT_FAILURE); 
    } 

    while (fgets(newLine, sizeof newLine, fp)) { 
     newLine[strcspn(newLine, "\n")] = '\0'; // strip the newline if present 
     add(&head, newLine); 
    } 

    add(&head, "why"); 
    add(&head, "does"); 
    add(&head, "this"); 
    add(&head, "work??"); 

    fclose(fp); 

    print(head); 

    return 0; 
}