我正在编写一个简单的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;
中的行似乎已解决此问题,但似乎不对。这仍然会创建一个不需要的条目,我只是将它从列表中删除,使其污染内存,或者这只是我的逻辑错误,这是解决它的正确方法吗?
答案 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");