【问题标题】:C: fgets usage for building a linked list of char*C: fgets 用于构建 char* 链表的用法
【发布时间】:2017-09-15 15:32:23
【问题描述】:

我是否错误地使用了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;
}

有人可以向我解释发生了什么吗?我已经用头撞墙太久了。我已经尝试使用一些注释打印语句,但未能成功调试。

【问题讨论】:

  • 拿些纸。跟踪对add 的调用并绘制您的链接列表的表示。特别注意'node->line'指向什么。
  • 这种行为有好几千个;(

标签: c linked-list fgets


【解决方案1】:

您的问题出在 add() 方法中。 它不断将相同的缓冲区指针添加到列表中。 您需要将列表中的缓冲区复制到新分配的空间,即。 node->line 也需要 malloced,并将 newLine 复制到其中。 不要忘记 malloc (strlen (newLine) + 1)。

【讨论】:

    【解决方案2】:

    您有 一个 用于存储输入的缓冲区。添加节点时,您将指针传递给该单个缓冲区的第一个元素。这意味着 all 节点中的字符串指针将指向同一个缓冲区。最后将包含您阅读的最后一个字符串。

    最简单的解决方案是将节点结构中的字符串制作成数组,然后将字符串复制到其中。

    另一种解决方案是为字符串动态分配内存(记住终止的空字符),然后再次将字符串复制到该内存中。

    使用常量字符串字面量的区别在于每个字符串都是不同的数组。

    【讨论】:

      【解决方案3】:

      您必须为每一行分配内存。按照目前的编码,所有节点都指向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;
      }
      

      【讨论】:

        猜你喜欢
        • 2012-10-05
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-11-06
        • 2013-12-10
        • 1970-01-01
        • 2021-12-29
        相关资源
        最近更新 更多