[英]Freeing node in a linked list
我正在用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
謝謝,提前。
在“RemoveNodeByIndex”函數中,請檢查以下行。
struct node* current = GetNodeByIndex(*(&head), index);
struct node* prev = GetNodeByIndex(*(&head), index);
兩者都將具有相同的節點,並且您將當前節點設為NULL,並且如果當前節點被刪除,則不會保留鏈接。 這可能導致未定義的行為。
你沒有發布完整的代碼,但我認為問題是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
是一樣的嗎? 你怎么看?
您是否嘗試刪除最后一個節點。
struct node * current =( (head)+ index); 這指向索引+ 1節點而不是索引節點struct node prev =(*(head)+ index-1); 這指向索引節點而不是索引 - 1。
伙計你試圖刪除malloc分配的一部分內存。 我不認為這是允許的。
嘗試分離malloc每個節點而不是將10個節點聚合到一個malloc中,
你的代碼試圖實現一個鏈表,其中節點被存儲在一個單獨的節點池, items
。 您對此實現有一些誤解:
如果池大小是固定的,則應該只有一個分配,即池的10個節點。 所有其他指針 - 列表頭,當前迭代器節點,節點中的鏈接和時間工作節點 - 應該是指向現有內存的指針。
因為只有一個分配,所以最后應該只有一個free
分配,即free(items)
。 傳遞給free
的指針必須與從malloc
一次返回的指針相同。 你的h'list頭可能會像工作指針那樣改變; 你顯然無法釋放那些。
當你談論索引時,你在這里討論兩個不同的概念: 項索引 ,它是數組items
節點的索引和列表索引 , 列表索引是列表頭在索引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;
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.