解冻链表中的节点

时间:2014-11-06 05:49:47

标签: 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 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

先谢谢。

4 个答案:

答案 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);

currentprev是一样的吗?你觉得怎么样?

答案 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;
}