C 释放链接列表中的节点
我正在用C语言做一些链表练习,遇到了一个指针问题。我正在尝试实现函数RemoveListByIndex(list,index)。 到目前为止,我已经完成了这个代码C 释放链接列表中的节点,c,list,pointers,free,C,List,Pointers,Free,我正在用C语言做一些链表练习,遇到了一个指针问题。我正在尝试实现函数RemoveListByIndex(list,index)。 到目前为止,我已经完成了这个代码 void RemoveNodeByIndex(struct node** head,int index) // NOT WORKING YET { // Remove node list struct node* current = GetNodeByIndex(*(&head), index); struct n
void RemoveNodeByIndex(struct node** head,int index) // NOT WORKING YET
{
// Remove node list
struct node* current = GetNodeByIndex(*(&head), index);
struct node* prev = GetNodeByIndex(*(&head), index-1);
// For debugging
PrintHRLine();
printf("Deleting item %d from list.\n", index);
printf("Item %d data = %d\n", index, current->data);
PrintHRLine();
// Change link from prev link node to the next
prev->link = current->link;
// Unlink node wished to delete
current->link = NULL;
current->data = 0;
// Free data
free((struct node*) current);
}
GetNodeByIndex函数:
struct node* GetNodeByIndex(struct node** list, int index)
{
// Return node by an index given
// if error it returns NULL
// for i < index
// next_node <- node.link
// node <- next.node
// return next_node
struct node* current = *list;
int counter = 0;
if (current)
{
while (current->link != NULL)
{
if (counter == index)
return current;
current = current->link;
counter++;
}
}
else
{
return NULL;
}
return NULL;
}
我从主代码中调用函数,如下所示:
struct node
{
int data;
struct node* link;
};
int main()
{
struct node* head = NULL;
struct node* edit_node = NULL;
int i;
edit_node = (struct node*)malloc(sizeof(struct node));
// Create a list of 10 elements
for (i = 0; i < SIZE_OF_LIST; i++)
{
struct node* item = (struct node*) malloc(sizeof(struct node));
item->data = i;
if (i==0)
head = item;
printf("(item+%d)->data = %d\n",i,i);
if (i<SIZE_OF_LIST-1)
{
item->link = (item+i+1);
printf("(item+%d->link = (item+%d+1);\n", i, i);
printf("(item+%d adress = 0x%lx\n",i, (unsigned long int) &item+i);
}
else
{
item->link = NULL;
printf("(item+%d->link = NULL;\n", i);
}
}
// RemoveNodeByIndex(head, 5);
// PrintListData(&head);
edit_node->data = 1001;
AddLastNode(&head, &edit_node);
SearchNode(&head, 101);
RemoveNodeByIndex(&head, 8);
PrintListData(&head);
// Free memory
free(item);
free(edit_node);
free(head);
return 0;
}
我怀疑我在处理指针时出了什么差错。
但我做错了什么
编辑:
我已将所有源代码包含在以下链接中:
我在这里包括了程序生成的所有输出:
谢谢,请提前通知。您没有发布完整的代码,但我认为问题出在
free()
上
如free()
的手册页所示
free()释放ptr指向的内存空间,该内存空间必须由以前对malloc()、calloc()或realloc()的调用返回。其他-
wise,或者如果之前已经调用了free(ptr),则会发生未定义的行为。如果ptr为NULL,则不执行任何操作
我认为在您的cse中,current
的指针不是由malloc()
或calloc()
分配的。通过执行(*(头部)+索引)代码>您指向的是其他地方
编辑:
在代码中,不要使用item=(struct node*)malloc(sizeof(struct node)*10)
,尝试分别分配每个节点。此外,在删除n
th节点时,方法应该是转到n-1
th节点,获取next
[或link
]指针并free()
编辑2:
为什么
struct node* current = GetNodeByIndex(*(&head), index);
struct node* prev = GetNodeByIndex(*(&head), index);
current
和prev
是否相同?您认为如何?您正在尝试删除最后一个节点
结构节点*当前=((头部)+索引);这指向索引+1节点,而不是索引节点
结构节点prev=(*(头部)+索引-1);这指向的是索引节点,而不是索引-1
伙计,您正试图删除malloc分配的内存的一部分。我认为这是不允许的
尝试单独malloc每个节点,而不是将10个节点聚合为一个malloc,在“RemoveNodeByIndex”函数中,请检查以下行
struct node* current = GetNodeByIndex(*(&head), index);
struct node* prev = GetNodeByIndex(*(&head), index);
两者都将具有相同的节点,并且您将当前节点设置为NULL,并且如果删除当前节点,则不会维护任何链接。这可能会导致未定义的行为。您的代码尝试实现一个链接列表,其中节点存储在单独的节点池中,项
。您对此实现有一些误解:
- 如果池大小是固定的,则应该只有一个分配,即池的10个节点的分配。所有其他指针——列表头、当前迭代器节点、节点中的链接和临时工作节点——都应该是指向现有内存的指针
- 因为只有一个分配,所以最后应该只有一个
免费
,即免费(项目)
。传递到free
的指针必须与从malloc
返回的指针相同。您的h列表头可能会随着工作指针的变化而变化;你显然不能释放这些
- 当您谈论索引时,您在这里谈论两个不同的概念:项索引,它是数组
items
中节点的索引;列表索引,它是列表中的索引,列表头位于索引0
- 由于
items
是一个节点数组,因此可以使用items+item_ix
在项目索引处获取节点。这不适用于链接列表。链表的优点是插入和删除速度快。(好吧,这确实适用于双链接列表。)缺点是按索引查找节点的速度慢:您必须从头部开始计数并在列表中迭代
- 将列表头作为指向头节点的指针传递给函数。只有当函数更改列表时(例如,当它删除或添加节点时),才需要这样做。当您只是检查列表时,即在查找节点或打印节点时,不需要这样做;指向节点的指针在这里就足够了
- 添加或删除节点时,
项的分配内存保持不变。例如,如果列表为空,items
会保存10个节点(其数据是任意的)。您需要一种机制来判断列表中是否正在使用节点。这可能是struct node
中的附加条目,也可能是辅助数组
- 您可以在
main
中的循环中创建列表。更好的实现是使用一个额外的函数,将节点添加到列表中。当然,这样的函数必须了解节点池,因为它需要从池中获取节点
- 此时,您应该将整个列表逻辑封装在一个结构中。将指针传递给列表结构并在其中进行所有更改,而不是头指针
我在下面展示了一个示例实现,它不在堆上使用分配,而是在堆栈上使用固定大小的池。代码使用hree数据结构:
- 节点与代码中的相同
- 池是一个固定大小的节点池,可以在堆栈上创建,并且应该初始化为零,以便正常工作。池使用一个额外的数组(
used
)跟踪可用节点。固定池大小由编译时常量定义
- 列表包含对列表头节点的引用和对池的引用。(多个列表可能共享一个池,但这些列表的最大节点总数是固定的。)它还跟踪大小,这不是必需的,但很容易做到
main
中的客户端代码仅在初始化结构后通过函数访问这些结构。注意游泳池是怎样的
struct node* current = GetNodeByIndex(*(&head), index);
struct node* prev = GetNodeByIndex(*(&head), index);
#include <stdio.h>
#include <stdlib.h>
#define POOL_SIZE 10
struct node { /* List node */
int data;
struct node *next;
};
struct pool { /* Fixed-size node pool */
char used[POOL_SIZE]; /* used/free markers */
struct node data[POOL_SIZE]; /* associated nodes */
};
struct list { /* List structure */
struct pool *pool; /* Node pool reference */
struct node *head;
struct node *tail;
int size;
};
/*
* Find an unused node and return it. If there are no unused
* nodes in the pool, return NULL:
*/
struct node *pool_new_node(struct pool *pool)
{
int i;
for (i = 0; i < POOL_SIZE; i++) {
if (pool->used[i] == 0) {
pool->used[i] = 1;
return pool->data + i;
}
}
return NULL;
}
/*
* Mark a node in the pool as unused, effectively freeing it.
* Return 0 on success, -1 on error.
*/
int pool_free_node(struct pool *pool, struct node *node)
{
int i = node - pool->data;
if (i < 0 || i >= POOL_SIZE) return -1;
if (pool->used[i] == 0) return -1;
pool->used[i] = 0;
return 0;
}
/*
* Append an item with value x at the tail.
*/
struct node *list_append(struct list *list, int x)
{
struct node *node = pool_new_node(list->pool);
if (node == NULL) return NULL;
node->next = NULL;
node->data = x;
if (list->tail) {
list->tail->next = node;
} else {
list->head = node;
}
list->tail = node;
list->size++;
return node;
}
/*
* Return ix'th node in list or NULL.
*/
struct node *list_find_by_index(const struct list *list, int ix)
{
struct node *node = list->head;
if (ix < 0 || ix >= list->size) return NULL;
while (node) {
if (ix-- == 0) return node;
node = node->next;
}
return NULL;
}
/*
* Return first node with given data or NULL.
*/
struct node *list_find_by_data(const struct list *list, int data)
{
struct node *node = list->head;
while (node) {
if (node->data == data) return node;
node = node->next;
}
return NULL;
}
/*
* Delete given node from list.
*/
void list_delete_node(struct list *list, struct node *node)
{
if (node) {
struct node **iter = &list->head;
while (*iter) {
if (*iter == node) {
*iter = node->next;
pool_free_node(list->pool, node);
list->size--;
return;
}
iter = &(*iter)->next;
}
}
}
/*
* Delete node at index from list.
*/
void list_delete_by_index(struct list *list, int ix)
{
struct node *node = list_find_by_index(list, ix);
if (node) list_delete_node(list, node);
}
/*
* Print the list items
*/
void list_print(const struct list *list)
{
struct node *node = list->head;
printf("%d items: [", list->size);
while (node) {
if (node != list->head) printf(", ");
printf("%d", node->data);
node = node->next;
}
printf("]\n");
}
/*
* Example client code
*/
int main()
{
struct pool pool = {{0}};
struct list list = {&pool};
struct node *node;
int i;
for (i = 0; i < 12; i++) {
list_append(&list, i);
list_print(&list);
}
node = list_find_by_index(&list, 9);
if (node) node->data = 1001;
node = list_find_by_index(&list, 10);
if (node) node->data = 1001;
list_print(&list);
node = list_find_by_data(&list, 7);
if (node) node->data = 999;
list_print(&list);
list_delete_by_index(&list, 0);
list_delete_by_index(&list, 0);
list_delete_by_index(&list, 0);
list_delete_by_index(&list, 5);
list_print(&list);
for (i = -10; i < 0; i++) {
list_append(&list, i);
list_print(&list);
}
list_print(&list);
return 0;
}