为什么释放内存会导致分段错误?

时间:2019-11-19 09:04:38

标签: c memory-management linked-list segmentation-fault singly-linked-list

我很拼命,因为这段代码不时出现分段错误,我也不知道为什么。实际上,只应该添加一些链接的列表注释,打印它们,然后通过释放内存来清空列表。

struct int_list {
   int value;
   struct int_list *next;
};
typedef struct int_list IntList;


void list_print(IntList *start)
{
   IntList *cur = start;
   while(cur != NULL)
   {
      printf("%d\n", cur->value);
      cur = cur->next;
   }
}


void list_append(IntList **start, int newval)
{
   IntList *newel = malloc(sizeof(IntList));
   newel->value = newval;
   newel->next = NULL;

   if(*start == NULL)
   {
      *start = newel;
   }

   else
   {
      IntList *cur = *start;
      while(cur->next != NULL)
      {
          cur = cur->next;
      }

      cur->next = newel;
   }

}


void list_free(IntList *start)
{
   IntList *prev = start;                           // prev = start
   while (start != NULL)                            // if start != Null
   {
       start = start->next;                         // make start point to the next element
       printf("Deleting %d\n", prev->value);
       free(prev);                                  // delete the previous element
       prev = start;                                // make previous point to start again
   }
   printf("\n");
}


int main(int argc, char *argv[])
{
   // fill the list
   IntList *start = NULL;
   list_append(&start, 42);
   list_append(&start, 30);
   list_append(&start, 16);

   // print the list
   printf("\nList 1\n");
   list_print(start);
   printf("\n");

   // free the memory and print again
   list_free(start);
   printf("Empty list:\n");
   list_print(start);
   printf("\n");

}

在尝试实现list_free()之前,一切工作都很好。因此,我强烈认为可以在此函数中找到错误。也只发布其余的代码,因为我是结构的新手,不确定100%正确地处理它们。你知道我在做什么错吗?...

3 个答案:

答案 0 :(得分:4)

由于指针悬空,您有不确定的行为

   list_free(start);

也就是说,start仍指向您尝试访问的已释放内存。

start之后,您需要将NULL设置为free

   list_free(start);
   start = NULL;
   printf("Empty list:\n");
   list_print(start);

答案 1 :(得分:1)

函数list_free通过值获取其参数。因此,该函数处理指向节点的原始指针的副本。结果,指向节点start的原始指针保持不变。

因此,调用函数list_free

之后,列表的输出
list_free(start);
printf("Empty list:\n");
list_print(start);

具有未定义的行为。

该函数应该像函数list_append一样接受通过引用指向节点的原始指针。

例如

void list_free( IntList **start )
{
    while ( *start != NULL )
    {
        IntList *prev = *start;                     // prev = start
        *start = ( *start )->next;                  // make start point to the next element
        printf("Deleting %d\n", prev->value);
        free(prev);                                  // delete the previous element
    }

    printf("\n");
}

调用类似函数

list_free( &start );

退出函数后,原始指针start将等于NULL。那列表确实会被释放。

这比当列表的客户端自己将指针显式设置为NULL时要好。他可能会犯与您忘记将指针设置为NULL相同的错误。

答案 2 :(得分:0)

指针仍然指向已释放内存的内存位置,这也是分段错误的一个实例。 这是“未定义的行为”,由于指向的位置的内容未知,并且会随着运行时间的变化,可能会导致发生不可预知的事情。