You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

C++中返回未用malloc初始化的结构体指针为何仍有效?

问题解答

核心误解澄清

你对实例的内存分配规则和位置判断存在两处错误:

  1. 并非只有malloc才会申请堆内存,C++的new操作符是和malloc作用一致的动态内存分配接口,同样会在堆上创建对象
  2. 代码中的ListNode实例不是栈上分配,全部通过new分配在堆内存区域,栈帧销毁不会影响堆内存的有效性

内存分配逻辑拆解

C++中程序的内存主要分为栈、堆两大区域,二者的生命周期规则完全不同:

  • 栈内存:存储函数的局部变量、参数、返回地址等,函数执行结束栈帧销毁时,该区域的所有内容都会被回收。
  • 堆内存:由开发者手动通过new/malloc申请,手动通过delete/free释放,只要不主动释放,对应的内存会在程序运行周期内一直有效。

你提供的代码中,somFunc内的每一行new操作都会执行两步动作:

  1. 在栈上创建一个ListNode*类型的局部指针变量(tail、head本身是栈上的指针变量)
  2. 在堆上创建一个ListNode结构体实例,将实例的内存地址赋值给对应的栈上指针
// 堆上创建val=2的ListNode实例,实例地址存到栈上的tail指针
ListNode *tail = new ListNode(2);
// 堆上创建val=12的ListNode实例,next成员指向第一个堆实例,实例地址存到栈上的head指针
ListNode *head = new ListNode(12, tail);

当函数返回head->next时,返回的是第一个堆上ListNode实例的地址。此时栈帧销毁只会回收tail、head这两个局部指针变量本身,堆上的两个ListNode实例完全不受影响,因此返回的指针指向的地址是有效的。

额外注意事项

这段代码存在明显的内存泄漏问题:

  • 你最终只拿到了第一个堆实例的地址(存到main的res变量),第二个堆实例(val=12的节点)的地址随着head指针被回收而丢失,永远无法被释放
  • 即使后续delete res,也只能释放第一个堆实例,第二个实例的内存会一直泄漏到程序退出
    正确的写法需要保证所有new出来的实例都有对应的delete操作,避免内存泄漏。

内容的提问来源于stack exchange,提问作者Stas Ezersky

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.14 07:36:05