常见代码问题与解答:(一)函数内可以释放内存,却无法将外部指针置 NULL?
2026/7/19 1:46:34 网站建设 项目流程
下一篇
因外部晶振频率改变导致 MCU 锁死的原因及处理方法

目 录

  • 函数内可以释放内存,却无法将外部指针置 NULL?
    • 1)现象
    • 2)原因
    • 3)正确做法

函数内可以释放内存,却无法将外部指针置 NULL?

1)现象

先从一段串口环形缓冲区释放函数的原版实现开始:

int32_tring_buffer_release(volatileRING_BUFFER_T*ring_buffer){if(!ring_buffer||!ring_buffer->buffer)return-1;free(ring_buffer->buffer);ring_buffer->buffer=NULL;free((void*)ring_buffer);ring_buffer=NULL;// ← 这行置空无效return0;}

调用处类似:

RING_BUFFER_T*rb=ring_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->buffer=NULL;}free((void*)rb);*pp_ring_buffer=NULL;// 通过解引用修改外部的指针变量本身return0;}

调用方式变为:

ring_buffer_release(&rb);// 此时 rb 被置为 NULL

pp_ring_buffer接收到的是rb变量的地址,*pp_ring_buffer就是rb变量本身,对它赋值直接改变了main中的rb


需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询