常见代码问题与解答:(一)函数内可以释放内存,却无法将外部指针置 NULL?
下一篇因外部晶振频率改变导致 MCU 锁死的原因及处理方法目 录函数内可以释放内存却无法将外部指针置 NULL1现象2原因3正确做法函数内可以释放内存却无法将外部指针置 NULL1现象先从一段串口环形缓冲区释放函数的原版实现开始int32_tring_buffer_release(volatileRING_BUFFER_T*ring_buffer){if(!ring_buffer||!ring_buffer-buffer)return-1;free(ring_buffer-buffer);ring_buffer-bufferNULL;free((void*)ring_buffer);ring_bufferNULL;// ← 这行置空无效return0;}调用处类似RING_BUFFER_T*rbring_buffer_init(256);// 使用 rb ...ring_buffer_release(rb);// rb 仍然是非 NULL 的悬空指针这段代码能成功释放堆内存但写ring_buffer NULL无法让调用方的rb变成NULL。这是为什么2原因核心原因指针变量的值传递。C 语言所有函数参数都是按值传递。当我们将指针变量传给函数时传递的是指针变量里保存的地址值而不是指针变量本身。示意图如下调用方: rb (变量) → 存储值 0x20001000 (指向结构体内存) ↓ 函数形参: ring_buffer (另一个局部变量) → 也存储值 0x20001000 ↓ 通过该地址操作内存 堆内存块 (0x20001000)free(ring_buffer)依靠地址值释放内存无论传入的地址是原始变量还是副本都能正确定位堆内存。因此释放必然成功。但ring_buffer NULL只把函数内部那个副本局部变量的值改成了NULL完全不影响外部rb变量它仍然保留旧的地址值变成悬空指针。3正确做法正确做法用二级指针修改调用方指针。如果希望函数有能力将外部指针安全置空必须传入原指针的地址二级指针int32_tring_buffer_release(volatileRING_BUFFER_T**pp_ring_buffer){if(!pp_ring_buffer||!*pp_ring_buffer)return-1;volatileRING_BUFFER_T*rb*pp_ring_buffer;if(rb-buffer){free(rb-buffer);rb-bufferNULL;}free((void*)rb);*pp_ring_bufferNULL;// 通过解引用修改外部的指针变量本身return0;}调用方式变为ring_buffer_release(rb);// 此时 rb 被置为 NULLpp_ring_buffer接收到的是rb变量的地址*pp_ring_buffer就是rb变量本身对它赋值直接改变了main中的rb。