将文件中的内容添加到链接列表

时间:2018-12-18 00:05:49

标签: c file input linked-list

我在C编程领域还很陌生。

我想将文件中的内容添加到链接列表中。

文件中的内容是名称,每个名称应具有自己的节点。

但是,当运行代码时,我遇到了无限循环。 我已经尝试解决,但是我无法深入了解它。 我觉得fscanf引起了问题。

谢谢。

#include <stdio.h>
#include <stdlib.h> 
#include <string.h>

  typedef struct node {
    char name[50];
    struct node * next;
  }
node;

int main() {

  FILE * file = fopen("content.txt", "r");
  if (file == NULL)
    return 1;

  char buf[50];

  node * first = NULL;

  //read the contents of the file and write to linked list
  while (!feof(file)) {
    fscanf(file, "%s", buf);

    // try to instantiate node
    node * head = malloc(sizeof(node));
    if (head == NULL) {
      return -1;
    }

    head-> next = NULL;

    // add new word to linked list
    strcpy(head-> name, buf);

    //move node to start of linked list
    head-> next = first;
    first = head;

  }

  fclose(file);
  node * ptr = first;
  while (ptr != NULL) {
    printf("%s\n", ptr-> name);
  }

  return 0;

}

这是输入文件的外观。

REDA
REDB
REDC
REDE
RED 
REDb
REDc
REDpikachu
REDboom

3 个答案:

答案 0 :(得分:0)

我认为问题是输出部分。

  while (ptr != NULL) {
    printf("%s\n", ptr-> name); // here is the infinite loop
    ptr = ptr->next; // add this 
  }

您可以通过添加一行以更新ptr的值来修复它,如上所述。

答案 1 :(得分:0)

#include <stdio.h>
#include <stdlib.h> 
#include <string.h>

typedef struct node {
    char name[50];
    struct node * next;
} node;

void list_insert(node **head,char *data)
{
    node *new;

    new = malloc(sizeof(node));
    new->next = *head;
    strcpy(new->name,data);
    *head = new;
}

int main() {
    char buf[50];
    node * first = NULL;

    FILE * file = fopen("content.txt", "r");
    if (file == NULL) {
        return 1;
    }
    while (!feof(file)) {
      fscanf(file, "%s", buf);
      list_insert(&first,buf);
    }
    fclose(file);

    node * ptr = first;
    while (ptr != NULL) {
        printf("%s\n", ptr-> name);
        ptr = ptr->next;
    }
    return 0;
}

答案 2 :(得分:0)

您的代码中有许多问题需要纠正(某些问题比其他问题更多)。

您的第一个问题是,只需阅读Why is while ( !feof (file) ) always wrong?即可解决。 (简短的回答是EOF读到的最后一个成功不会生成fscanf,因此,在读完最后一个“名称”后,您检查!feof(file)会测试{ {1}},循环继续,TRUE失败,fscanf,您进行分配,然后尝试从EOFstrcpy保持不确定的值-调用 Undefined行为

在这种情况下,如果阅读的单词没有空格,则可以使用buf,但不能使用。尽早养成良好的习惯。从文件的每一行获取输入时,请使用面向 line 的输入函数(例如fscanf或POSIX fgets),以确保输入缓冲区中没有剩余内容。取决于使用的getline转换说明符。

例如,您可以:

scanf

...         / *读取文件的内容并写入链表* /         while(fgets(buf,MAXN,文件)){

#define MAXN 50     /* if you need a constant, #define one (or more) */

typedef struct node {
    char name[MAXN];
    struct node *next;
}
node;

注意:不要向您的外壳返回值,并且在 /* valdiating the last char is '\n' or length < MAXN - 1 omitted */ /* allocate new node */ node *head = malloc (sizeof(node)); if (head == NULL) { /* validate allocation */ perror ("malloc-node"); /* issue error message */ return 1; /* don't return negative values to the shell */ } /* trim '\n' from end of buf */ buf[strcspn(buf, "\n")] = 0; /* overwrite with nul-character */ /* initialize node values */ strcpy (head->name, buf); head->next = NULL; 后不要包含空格引用结构成员时的操作符)

至此,您已经成功地将“名称”读入->中,并分配给新节点,已验证,分配成功,并修剪了{中包含的结尾buf {1}}通过面向 line 的输入函数,将修整后的“名称”复制到'\n',并将buf初始化为head->name。但是,您有问题。您的所有姓名都以逆序(有时可能是您想要的)存储在列表中。但这通常不是所需的行为。通过简单地声明一个已更新的指向最后一个节点的附加指针,您可以按顺序插入列表中,而无需重复查找最后一个节点。

例如,仅声明一个head->next指针并检查两种情况(1)NULL表示循环为空,并使lastlast=NULL指向{{ 1}}节点允许您(2)在末尾添加所有其他节点,例如:

first

您的“无限循环” 已由@CS Pei正确寻址,在这里您只是忘记了在输出循环中将当前指针前进到last

您还无法first分配已分配的内存。是的,它在程序退出时被释放,但是习惯于跟踪您分配的所有内存,然后在不再需要该内存时释放它。 (这是防止随着代码的增长而导致内存泄漏的一项至关重要的技能)。例如,在输出循环中,您可以执行以下操作:

    node *first = NULL, *last = NULL;   /* use last for in-order chaining */
    ...
        /* initialize node values */
        strcpy (head->name, buf);
        head->next = NULL;

        /* in-order add at end of list */
        if (!last)
            first = last = head;
        else {
            last->next = head;
            last = head;
        }
    }

将其完全放在一起,您可以执行以下操作:

ptr->next

使用/输出示例

使用输入文件,您将获得以下输出:

free

内存使用/错误检查

在您编写的任何动态分配内存的代码中,对于任何分配的内存块,您都有2个职责:(1)始终保留指向起始地址的指针因此,(2)当不再需要它时可以释放

当务之急是使用一个内存错误检查程序来确保您不会尝试访问内存或在已分配的块的边界之外/之外进行写入,不要试图以未初始化的值读取或基于条件跳转,最后,以确认您释放了已分配的所有内存。

对于Linux, node *ptr = first; /* declare/set pointer to first */ while (ptr != NULL) { /* loop while ptr */ node *victim = ptr; /* declare/set pointer to victim */ printf ("%s\n", ptr->name); /* output name */ ptr = ptr->next; /* advance pointer to next */ free (victim); /* free victim */ } 是正常选择。每个平台都有类似的内存检查器。它们都很容易使用,只需通过它运行程序即可。

#include <stdio.h>
#include <stdlib.h> 
#include <string.h>

#define MAXN 50     /* if you need a constant, #define one (or more) */

typedef struct node {
    char name[MAXN];
    struct node *next;
}
node;

int main (int argc, char **argv) {

    FILE *file = argc > 1 ? fopen (argv[1], "r") : stdin;
    if (file == NULL)
        return 1;

    char buf[MAXN];

    node *first = NULL, *last = NULL;   /* use last for in-order chaining */

    /* read the contents of the file and write to linked list */
    while (fgets (buf, MAXN, file)) {

        /* valdiating the last char is '\n' or length < MAXN - 1 omitted */

        /* allocate new node */
        node *head = malloc (sizeof(node));
        if (head == NULL) {         /* validate allocation */
            perror ("malloc-node"); /* issue error message */
            return 1;   /* don't return negative values to the shell */
        }

        /* trim '\n' from end of buf */
        buf[strcspn(buf, "\n")] = 0;    /* overwrite with nul-character */

        /* initialize node values */
        strcpy (head->name, buf);
        head->next = NULL;

        /* in-order add at end of list */
        if (!last)
            first = last = head;
        else {
            last->next = head;
            last = head;
        }
    }

    if (file != stdin)  /* close file if not stdin */
        fclose(file);

    node *ptr = first;              /* declare/set pointer to first */
    while (ptr != NULL) {           /* loop while ptr */
        node *victim = ptr;         /* declare/set pointer to victim */
        printf ("%s\n", ptr->name); /* output name */
        ptr = ptr->next;            /* advance pointer to next */
        free (victim);              /* free victim */
    }

    return 0;
}

始终确认已释放已分配的所有内存,并且没有内存错误。

仔细检查一下,如果还有其他问题,请告诉我。