C语言多项式加法程序中free()双释放错误的技术咨询
咱们直接切入核心:你遇到的double free detected in tcache 2,本质是同一个内存块被你释放了两次。结合你的场景和Valgrind输出,原因其实很清晰:
错误发生的逻辑链
当其中一个多项式是零多项式时,你的求和函数(sum_pol)应该是直接返回了另一个非零多项式的指针(比如p2是零多项式时,直接返回p1)。而错误版本的main函数里,你大概率写了这样的代码:
free(p1); free(p2); free(p3);
这时候麻烦来了——如果p3和p1是同一个指针(因为sum_pol返回了p1),你先free了p1,接着又free了p3,等于把同一块内存释放了两次,触发了内存管理器的保护机制,程序直接崩溃。
Valgrind输出实锤了这一点
看Valgrind的关键日志:
11720 Address 0x4a4b960 is 0 bytes inside a block of size 24 free'd
11720 at 0x483A9AB: free (vg_replace_malloc.c:538)
11720 by 0x1092CC: main (in //p_c.out)
11720 Block was alloc'd at
11720 at 0x483BD7B: realloc (vg_replace_malloc.c:834)
11720 by 0x1093D8: inp_pol (in //p_c.out)
然后紧接着第二次释放同样的地址:
11720 at 0x483A9AB: free (vg_replace_malloc.c:538)
11720 by 0x1092F2: main (in //p_c.out)
这说明main里有两处free操作都指向了inp_pol分配的同一块内存——完全就是重复释放的典型特征。
为什么你的修复能解决问题?
你说“仅当p1和p2均非NULL时才调用free(p3)”,这个逻辑完全正确:
- 当p1或p2是NULL(零多项式)时,p3其实是另一个非NULL指针的“别名”(比如p3=p1);
- 这时候你已经通过
free(p1)释放了这块内存,再free(p3)就是画蛇添足,反而触发double free; - 只有当p1和p2都非NULL时,p3才是求和函数新分配的独立内存块,这时候才需要单独释放它。
几个避坑小建议
为了以后不再踩这类内存管理的坑,给你几个小技巧:
- 明确内存所有权:谁分配的内存谁负责释放,或者在函数注释里明确说明返回的指针是原指针还是新分配的内存;
- free后置NULL:每次free完指针后,立刻把它设为
NULL——因为free(NULL)是安全的,就算不小心重复free也不会崩溃; - 避免指针别名混淆:如果求和函数需要返回原指针,最好在代码里做明确标记,比如用注释提醒自己“这里返回的是p1的原指针,不要重复释放”。
内容的提问来源于stack exchange,提问作者Ankan

