C语言释放未分配内存相关疑问:程序崩溃可能性、校验必要性等
C程序中free调用与未定义行为的疑问解答
先看用户提供的代码:
int main() { char* c; if (c) { printf("called free\n"); free (c); } else { printf("not called free\n"); } printf("not crashed\n"); c = strdup("someString"); if (c) { printf("called free\n"); free(c); c = NULL; // why is this needed for last if (c) } if (c) { free(c); } printf("still not crashed\n"); return 0; }
问题1:该程序是否存在崩溃的可能?
当然存在。
- 开头的
char* c是未初始化的自动局部变量,它的值是随机的垃圾值。如果这个垃圾值是非空的,且指向的内存不属于当前进程、或者是无效地址,调用free(c)就会直接触发崩溃(比如段错误)。 - 如果不把
c置为NULL,最后那个if(c)会执行双重释放——释放已经归还给系统的内存,这属于未定义行为,同样可能导致崩溃。这次没崩只是运气好,未定义行为的结果完全不可预测,不能当成“不会崩溃”的依据。
问题2:调用free释放char*指针前是否必须进行if(c)校验?
分情况:
- 标准C明确规定
free(NULL)是安全操作,不会有任何问题。如果能保证指针要么是有效的堆内存地址,要么是NULL,可以直接调用free不用校验。 - 但如果指针可能是未初始化的垃圾值(比如代码开头的
c),必须先做if(c)校验——因为垃圾值非空时,free它是未定义行为,风险极高。 - 另外,对于已经释放但没置为
NULL的野指针,if(c)会判断为非空,此时调用free就是双重释放,这种情况下的校验毫无意义,核心是释放后要把指针置为NULL,避免重复释放。
问题3:为何不将c置为NULL时会再次调用free?
free(c)的作用是把指针指向的内存归还给系统,但不会修改指针变量c本身的值。也就是说,释放后c仍然保存着原来那块内存的地址,此时它已经是野指针(指向的内存不再属于当前程序)。后面的if(c)判断时,这个野指针的值不是NULL,条件成立,就会再次调用free,造成双重释放。而把c置为NULL后,if(c)条件不成立,就不会执行free,避免了这个问题。
补充:程序为何没崩溃?
纯粹是运气。
- 未初始化的
c恰好是NULL(自动变量未初始化值随机,但偶尔可能刚好是0),所以第一个if(c)走了else分支,没调用free。 - 后面即使出现双重释放,也只是没触发崩溃而已——未定义行为的结果可能是任何情况,包括看起来“正常运行”,但这绝对不是正确的行为,不能依赖。
内容的提问来源于stack exchange,提问作者lkm lkm
相关产品推荐
相关产品推荐

