簡體   English   中英

解凍鏈表中的節點

[英]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);

currentprev是一樣的嗎? 你怎么看?

您是否嘗試刪除最后一個節點。

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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM