我正在使用C中的链接列表进行一些练习。并且遇到了指针问题。我试图实现函数RemoveListByIndex(list,index)。 到目前为止,我的代码。
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()电话时,一切似乎都很好。它失败。 输出:
===================================
Deleting item 8 from list. Located : 0x7fffd20ecad0
Item 8 data = 6
===================================
*** Error in `./a.out': double free or corruption (out): 0x00000000011b2090 ***
Aborted (core dumped)
我怀疑我处理我的指针有些不对劲。 但是我做错了什么?
编辑: 我已将所有源代码包含在以下链接中:SOURCE CODE 我已在此处列出了程序生成的所有输出:OUTPUT
先谢谢。
答案 0 :(得分:2)
在你的&#34; RemoveNodeByIndex&#34;功能,请检查以下行。
struct node* current = GetNodeByIndex(*(&head), index);
struct node* prev = GetNodeByIndex(*(&head), index);
两者都将具有相同的节点,并且您将当前节点设为NULL,并且如果当前节点被删除,则不会保留链接。这可能会导致未定义的行为。
答案 1 :(得分:1)
您没有发布完整的代码,但我认为问题出在free()
。
作为free()
的手册页
free()释放ptr指向的内存空间,该内存空间必须由之前调用malloc(),calloc()或realloc()返回。其他- 明智的,或者如果之前已经调用过free(ptr),则会发生未定义的行为。如果ptr为NULL,则不执行任何操作。
我认为在您的cse中,指向current
的指针未由malloc()
或calloc()
分配。通过(*(head)+index);
,您指向其他地方。
编辑:
在您的代码中,而不是使用item = (struct node*)malloc(sizeof(struct node) * 10);
,尝试单独分配每个node
。此外,在删除n
节点时,方法应该转到n-1
节点,获取next
[或link
]指针并free()
编辑2:
怎么来
struct node* current = GetNodeByIndex(*(&head), index);
struct node* prev = GetNodeByIndex(*(&head), index);
current
和prev
是一样的吗?你觉得怎么样?
答案 2 :(得分:0)
您是否尝试删除最后一个节点。
struct node * current =((head)+ index);这指向索引+ 1节点而不是索引节点 struct node prev =(*(head)+ index-1);这指向索引节点而不是索引 - 。
Buddy你试图删除malloc分配的一部分内存。我不认为这是允许的。
尝试分离malloc每个节点,而不是将10个节点聚合成一个malloc,
答案 3 :(得分:0)
您的代码尝试实现链接列表,其中节点存储在单独的节点池items
中。您对此实施有一些误解:
如果池大小是固定的,则应该只有一个分配,即池的10个节点。所有其他指针 - 列表头,当前迭代器节点,节点中的链接和时间工作节点 - 应该指向现有内存。
因为只有一个分配,所以最后应该只有一个free
,即free(items)
。传递给free
的指针必须与malloc
一次返回的指针相同。你的h'list头可能会像工作指针那样改变;你显然无法释放那些。
当你谈论索引时,你在这里讨论两个不同的概念:项索引,它是数组items
中节点的索引和 list index ,这是列表中索引为0
的列表中的索引。
由于items
是一个节点数组,因此您可以使用items + item_ix
获取项目索引处的节点。这不适用于链表。链表的优点是快速插入和删除。 (嗯,那真的是双链表。)缺点是通过索引慢慢查找节点:你必须从头开始计数并遍历列表。
将列表头传递给函数,作为指向头节点指针的指针。只有在函数更改列表时才需要这样做,例如删除或添加节点时。只检查列表时,即查找节点或打印时,没有必要;指向节点的指针就足够了。
添加或删除节点时,items
的已分配内存保持不变。例如,如果列表为空,则items
包含10个节点(其数据是任意的),无论如何。您需要一种机制来判断节点是否在列表中使用。这可能是struct node
中的附加条目,也可能是辅助数组。
您可以在main
的循环中创建列表。更好的实现是具有将节点添加到列表的额外功能。当然,这样的函数必须知道节点池,因为它需要从池中获取它的节点。
此时,您应该将整个列表逻辑封装在结构中。您将指针传递给列表结构并在那里进行所有更改,而不是头指针。
我在下面展示了一个示例实现,它不使用堆上的分配,而是使用堆栈上的固定大小的池。该代码使用了hree数据结构:
节点与您的代码中的相同。
池是一个固定大小的节点池,可以在堆栈上创建,并且应该在oder中初始化为零以便正常工作。池使用额外的数组used
跟踪可用节点。固定池大小使用编译时常量定义。
列表包含对列表头节点的引用和对池的引用。 (多个列表可能共享一个池,但是这些列表的最大节点总数是固定的。)它还跟踪大小,这不是必需的,但很容易做到。
main
中的客户端代码仅在初始化结构后通过函数访问这些结构。注意池如何不会溢出以及释放节点如何使sliots再次可用于新节点。
#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;
}