C链接列表插入功能在最后创建不需要的条目

时间:2014-05-25 18:36:38

标签: c doubly-linked-list circular-list

我正在编写一个简单的C程序,但遇到了代码问题。我正在创建一个循环链表数据结构,并用文本文件中的数据填充它。一切似乎都运行得很好,除了它在链表的末尾添加了一个额外的条目。任何人都可以指出我做错了什么并提出解决这个问题的方法吗?

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define SIZE 20
#define MAXLEN 100

//Definition of the structure:
struct list{
    char name[SIZE];
    int min, max;
    struct list *next;
    struct list *prev;
};

typedef struct list List;
typedef List *ListPtr;

//Function prototypes
ListPtr getData(ListPtr lst, ListPtr start);
void print(ListPtr start);

这是我的主要():

int main()
{
    ListPtr lst, start;
    lst = (ListPtr) malloc(sizeof(List));
    lst->next = NULL;
    lst->prev = NULL;

    //Gets data from text file
    start = getData(lst, start); //Making start to point to the 1st entry
    print(start);
    system("PAUSE");    
    return 0;
}

这是getData():

ListPtr getData(ListPtr lst, ListPtr start){
    //For some reason aditional entry is created with system data in it
    char arr[MAXLEN];
    FILE *data = fopen("data.txt", "r");
    //while(fgets(arr, MAXLEN, data)){
        strcpy(lst->name, strtok(arr, " "));
        lst->min = atoi(strtok(NULL, " "));
        lst->max = atoi(strtok(NULL, " "));
        lst->next = (ListPtr)malloc(sizeof(List));
        lst->next->prev = lst;
        lst = lst->next;
    }
    fclose(data);
    start = lst; //start = end of the list
    while(lst->prev != NULL)
        lst = lst->prev; //goes to the start of the list
    start->next = lst;
    lst->prev = start;
    start = lst;
    return start;
}

这是一个检查列表条目的函数:

void print(ListPtr start){
    int i;
    for(i = 0; i < 9; i++){
        printf("%s %d %d\n", start->name, start->min, start->max);
        start = start->next;
    }
}

data.txt的样本:

John 10 15
Mike 13 17
Anna 18 23

我想以循环方式创建此列表,以便稍后我可以随机选择条目,并使用rand()生成大数字;并滚动列表,因为它给rand()更多随机性。任何有关我的问题的帮助都非常感谢。

修改getData();fclose(data)之后更改start = lst->prev;中的行似乎已解决此问题,但似乎不对。这仍然会创建一个不需要的条目,我只是将它从列表中删除,使其污染内存,或者这只是我的逻辑错误,这是解决它的正确方法吗?

4 个答案:

答案 0 :(得分:0)

似乎错过了

lst->next = NULL

在函数getData()中,紧跟在while循环之后,从中读取文件中的数据。

如果你想要一个循环列表,你需要这样做,而不是我上面所说的:

lst->next = <head of the list>

修改 我更好地阅读了你的代码,你在这段代码中做了我说过的最后一件事:

start = lst; //start = end of the list
while(lst->prev != NULL)
    lst = lst->prev; //goes to the start of the list
start->next = lst;
lst->prev = start;
start = lst;

问题是: 在最后一次迭代中,您使用malloc创建了一个新节点,但是您没有在其中放置任何内容!这就是为什么用lst-&gt; prev它起作用了。

答案 1 :(得分:0)

1)您的代码是如何编译的? lst未在您的打印功能中声明。你是如何在printf中访问它的? 2)而不是循环使用while循环条件为start!= NULL

答案 2 :(得分:0)

解决方案存在一些设计问题;我建议稍作重新思考并重写。

正如Jim评论的那样,首先是你在解析数据之前创建了一个空节点。假设您的数据文件为空,那么单个节点的列表是否有效?另一个设计问题是,在构建列表的最后,您将遍历所有列表节点,这非常奇怪,不应该被要求。

首先,决定是否要列出标题。这将是一个不同的结构,指向列表的头部和尾部,也许也有节点的计数,但实际上并不是列表节点本身。这可能与您创建的初始节点有关。

标头节点不是必需的,如果没有读取节点,您可以从getData()函数返回NULL,并且您将在该例程中创建所有列表节点。列表标题在某些方面更好,因为它允许您存储列表元数据,并允许您建模和区分空列表(指向没有节点的列表标题的指针)和缺少列表(空指针)。

双重链接列表将遵循以下内容。编写一个createNode()函数来构造一个包含data和next / prev NULL的新节点。如果你真的需要它是圆形的,头部和尾部可以很容易地连接。

ListNode* getData()
{
    ListNode* head = 0;
    ListNode* tail = 0;
    const char* data;
    while (data = moreData() /* wherever the data comes from */) {
        ListNode* node = createNode(data);

        if (!head) {
          head = node;
        }
        else
        {
          node->prev = tail;
          tail->next = node;
        }

        tail = node;
     }
     return head;
}

答案 3 :(得分:0)

我建议你将列表的头部保留在一个变量中,让它称之为 head 。 您可以通过以下方式解决问题:

int getData(ListPtr *head, char *filename){
   ListPtr lst;
   int count = 0;
   char arr[MAXLEN];
   FILE *data = fopen(filename, "r");

   if (data == NULL)
      return -1;

   *head = (ListPtr)malloc(sizeof(List));
   lst = *head;
   while(fgets(arr, MAXLEN, data)){
       count++;
       strcpy(lst->name, strtok(arr, " "));
       lst->min = atoi(strtok(NULL, " "));
       lst->max = atoi(strtok(NULL, " "));
       if (!feof(data))
       {
           lst->next = (ListPtr)malloc(sizeof(List));
           lst->next->prev = lst;
           lst = lst->next;
       }
   }

   fclose(data);

   if (count == 0)
   {
       free(*head);
       return -1;
   }

   lst->next = *head;
   (*head)->prev = lst;

   return count;
}

因此,在空头文件中,如果出现错误,函数将返回-1。当文件存在且它不为空时,它返回列表中元素的数量,head将是列表头部的指针。

您应该使用以下方法调用此函数:

ListPtr head;
int nEl;

nEl = getData(&head, "data.txt");