2017-09-15 31 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; 
}