因此,对于我的一类,我需要在C中编写一个链接列表,它在从文件中读取时添加或删除项目,并且在插入它们时,它们通过插入排序按顺序放置。文件中的每一行都包含一个名称,后跟a或d,表示是否添加或删除该名称。
我理解链表的概念,并在之前用Java实现过。出于某种原因,我无法让它在C中工作。任何帮助都将非常感激。
第一个值现在进入列表,但还有另一个问题如下所示。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct node
{
char name[42];
struct node *next;
};
void insertNode(char name[42], struct node *head)
{
struct node *new = (struct node*)malloc(sizeof(struct node));
strcpy(new->name, name);
struct node *curr = head;
int finished = 0;
if(!curr)
{
head = new;
return;
}
while(curr->next != NULL) //This loop right here is not working
//it doesn't make it into the loop, curr somehow equals null
//not sure why this isn't working
{
if((strcmp(curr->name, new->name) < 0))
{
new->next = curr->next;
curr->next = new;
finished = 1;
break;
}
curr = curr->next;
}
if(finished = 0)
{
new->next = curr->next;
curr->next = new;
}
}
void removeNode(char name[42], struct node *head)
{
struct node *temp = (struct node*)malloc(sizeof(struct node));
strcpy(temp->name, name);
struct node *curr = head;
while(curr->next != NULL)
{
if(curr->next == temp)
{
curr->next = temp->next;
free(temp->name);
temp->next = NULL;
}
}
}
void FREE(struct node *head)
{
int i;
struct node *temp;
while(head != NULL)
{
temp = head;
head = head->next;
free(temp);
}
}
void printList(struct node *head)
{
struct node *curr = head;
printf("Linked list:\n");
while(curr != NULL)
{
printf("%s\n", curr->name);
curr = curr->next;
}
}
int main(void)
{
FILE *input = fopen("hw7.data", "r");
struct node *head = (struct node*)malloc(sizeof(struct node));
head->next = NULL;
strcpy(head->name, "");
char *tempText = NULL;
char *tempName = NULL;
char *tempOP = NULL;
size_t lineLen;
int i = 0;
getline(&tempText, &lineLen, input);
while(!feof(input))
{
tempName = strtok(tempText, " ");
tempOP = strtok(NULL, "\n");
if(i == 0)
{
strcpy(head->name, tempName);
i = 1;
}
if(tempOP[0] == 'a')
{
insertNode(tempName, head);
}
else
{
removeNode(tempName, head);
}
getline(&tempText, &lineLen, input);
}
printList(head);
fclose(input);
FREE(head);
return 0;
}
这是数据文件:
Beverly a
Kathy a
Radell a
Gary a
Chuck a
David a
kari a
Tom a
Tanya a
Scott a
Beverly d
Brenda d
Kathy a
Gary a
WenChen a
Chuck a
Mike a
Emanuel a
Linda a
Bernie a
Hassan a
Brian a
Gary d
Kathy d
Gary a
Eunjin a
Kathy a
Brenda a
Jun a
Peanut a
Travis a
答案 0 :(得分:3)
此代码中存在大量错误,包括但不限于:
free
&d;或malloc
&#39; d realloc
feof
。为每个代码重新编写代码,从基础知识开始。为避免缓冲区溢出结构name
成员,只需使用动态分配。您已经使用链接列表杀死了缓存;也可以确保它在6英尺以下:
struct node
{
char *name; /* will use strdup() for allocation */
struct node *next;
};
接下来,插入例程可以使用指向指针的指针遍历列表(main
通过地址传递head
指针,这样我们就可以通过解引用。这很关键,但代码中缺少:
void insertNode(char const name[], struct node **head)
{
printf("Adding: %s\n", name);
while (*head && strcmp((*head)->name, name) < 0)
head = &(*head)->next;
struct node *p = malloc(sizeof *p);
p->name = strdup(name);
p->next = *head;
*head = p;
}
当涉及到删除时,我们可以做同样的事情,它具有正确的头指针管理的额外优势,即使在链表中的单个节点的情况下,甚至根本没有:
void removeNode(char const name[], struct node **head)
{
int cmp = 0;
while (*head && (cmp = strcmp((*head)->name, name)) < 0)
head = &(*head)->next;
if (*head && (cmp == 0))
{
printf("Removing: %s\n", name);
struct node *tmp = *head;
*head = tmp->next;
free(tmp->name); // note: freeing what we strdup()'d
free(tmp);
}
else
{
printf("Not found: %s\n", name);
}
}
虽然在这种情况下不是必需的,但我总是建议使用与焦土freeList
意识形态相同的指针机制的地址指针。它可以确保你不会给喋喋不休的指针留下愚蠢的指针,他们可能会试图取消引用。
void freeList(struct node **head)
{
while (*head)
{
struct node *tmp = *head;
*head = tmp->next;
free(tmp->name);
free(tmp);
}
}
在打印列表时,使用const指针移动它是微不足道的:
void printList(struct node const *head)
{
printf("Linked list:\n");
for (; head; head = head->next)
printf("%s\n", head->name);
}
最后,您的计划的核心,main
。修复while循环仅在实际读取行内容时继续,并正确释放getline
的最终结果而不是让它泄漏(这不重要,因为程序将很快退出,但是良好的做法) ,我们得到:
int main()
{
FILE *input = fopen("hw7.data", "r");
if (!input)
{
perror("Failed to open file: ");
return EXIT_FAILURE;
}
struct node *head = NULL;
char *text = NULL;
size_t lineLen = 0;
while(getline(&text, &lineLen, input) > 0)
{
char *name = strtok(text, " ");
char *op = strtok(NULL, "\n");
if(*op == 'a')
{
insertNode(name, &head);
}
else if (*op == 'd')
{
removeNode(name, &head);
}
}
fclose(input);
free(text);
printList(head);
freeList(&head);
return EXIT_SUCCESS;
}
<强>输出强>
以下是您输入的输出,我添加了insertNode
和removeNode
中的工具,让您知道发生了什么:
Adding: Beverly
Adding: Kathy
Adding: Radell
Adding: Gary
Adding: Chuck
Adding: David
Adding: kari
Adding: Tom
Adding: Tanya
Adding: Scott
Removing: Beverly
Not found: Brenda
Adding: Kathy
Adding: Gary
Adding: WenChen
Adding: Chuck
Adding: Mike
Adding: Emanuel
Adding: Linda
Adding: Bernie
Adding: Hassan
Adding: Brian
Removing: Gary
Removing: Kathy
Adding: Gary
Adding: Eunjin
Adding: Kathy
Adding: Brenda
Adding: Jun
Adding: Peanut
Adding: Travis
Linked list:
Bernie
Brenda
Brian
Chuck
Chuck
David
Emanuel
Eunjin
Gary
Gary
Hassan
Jun
Kathy
Kathy
Linda
Mike
Peanut
Radell
Scott
Tanya
Tom
Travis
WenChen
kari
<强>摘要强>
有很多错误。我解决了上面我能找到的所有内容,并希望提供一些链接列表管理的具体示例,您现在和将来都可以使用它们。
我强烈建议您在调试器中使用此代码,并在变量发生时支付非常密切关注变量。加载您的监视列表,并查看每个行在输入项目中的进度。通过调试正确运行的代码来学习可能是一种很好的学习技巧,值得你花费半小时。