2017-09-15 58 views
1

我是否錯誤地使用了fgets()C:用於構建char鏈表的fgets用法*

我正在嘗試建立一個鏈接列表(char *),將每一行添加到LL的末尾。我正在從一個文件中讀取這些行,但由於某種原因,每行都被正在處理的當前行覆蓋,只有在while循環內使用fgets()時,但add函數似乎正在正確接收每行。

如果我在main()中單獨添加線條,則沒有問題。

下面是一個示例輸入文件:

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 

代碼:

#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; 
} 

可能有人請向我解釋發生了什麼?我一直把頭撞在牆上太久。已經有一些我一直在嘗試使用的評論打印語句,但沒有成功進行調試。

+0

得到一些紙。跟蹤調用「add」並繪製鏈接列表的表示形式。特別要注意'node-> line'指向什麼。 –

+0

這種行爲有幾個kilodupes;( –

回答

1

你的問題是在add()方法中。 它一直向列表添加相同的緩衝區指針。 您需要將列表中的緩衝區複製到新分配的空間,即。 節點 - >行也需要進行混搭,並將newLine複製到其中。 不要忘記malloc(strlen(newLine)+ 1)。

0

您有一個緩衝區,您將存儲輸入。並且在添加節點時將指針傳遞給此單個緩衝區的第一個元素。這意味着中的所有節點中的字符串指針將指向相同的單個緩衝區。最後將包含您讀取的最後一個字符串。

最簡單的解決方案是將節點結構中的字符串作爲數組,並將字符串複製到數組中。

另一種解決方法是動態地爲字符串分配內存(記住終止的空字符),並再次將字符串複製到該內存中。

使用常量字符串文字時的區別在於每個字符串都是不同的數組。

0

您必須爲每一行分配內存。按照當前編碼,所有節點都指向main()的本地數組,其內容被每次調用fgets()覆蓋。

另請注意,添加到列表中的每行都包含一個終止換行符,您可能應該在調用之前將其刪除。

這裏是一個修正版本:

#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; 
}