为啥释放内存会导致分段错误?
Posted
技术标签:
【中文标题】为啥释放内存会导致分段错误?【英文标题】:Why does freeing the memory lead to segmentation fault?为什么释放内存会导致分段错误? 【发布时间】:2020-03-14 17:52:01 【问题描述】:我很绝望,因为这段代码时常给我一个分段错误,我不知道为什么。实际上它只是应该添加一些链表注释,打印它们然后通过释放内存来清空列表。
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% 确定正确处理它们。你知道我做错了什么吗?...
【问题讨论】:
提示:void list_print(IntList *start) IntList *cur = start; ...
可以写成void list_print(IntList *cur) ...
调用list_free()
后,start是一个悬空引用。因此,list_print()
的以下调用具有未定义的行为。
【参考方案1】:
指针仍然指向释放内存的内存位置,这也是分段错误的一个实例。 这是“未定义的行为”,并且可能导致发生任意不可预知的事情,因为指向位置的内容是未知的,运行时间不同。
【讨论】:
【参考方案2】:函数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 时相同的错误。
【讨论】:
【参考方案3】:由于悬空指针,您有未定义的行为
list_free(start);
也就是说,start
仍然指向您尝试访问的已释放内存。
您需要在free
ing 之后将start
设置为NULL
。
list_free(start);
start = NULL;
printf("Empty list:\n");
list_print(start);
【讨论】:
以上是关于为啥释放内存会导致分段错误?的主要内容,如果未能解决你的问题,请参考以下文章