c++ 链表知识汇总
文章目录
- 链表结点的创建方式
- 1. ListNode ans;:栈上创建(局部变量)
- 2. ListNode* ans = new ListNode(0);:堆上创建(动态分配)
- 总结对比表
- 链表场景中的选择
链表结点的创建方式
在 C++ 中,ListNode ans;
和 ListNode* ans = new ListNode(0);
是两种创建链表节点的方式,核心区别在于内存分配方式和生命周期管理,这直接影响它们的使用场景和行为:
1. ListNode ans;:栈上创建(局部变量)
- 内存分配:节点
ans
被分配在栈内存中,由编译器自动管理内存。 - 生命周期:仅在当前作用域内有效(如函数内、循环体或
if
块内)。当程序执行离开该作用域时,节点会被自动销毁,内存被释放。 - 访问方式:通过
.
运算符访问成员(如ans.val
、ans.next
)。 - 局限性:
- 离开作用域后,节点内存被释放,若之前保存了指向该节点的指针(如
p = &ans
),会变成野指针(访问已释放内存,导致未定义行为)。 - 无法在函数中作为返回值有效传递(返回后节点已销毁)。
- 离开作用域后,节点内存被释放,若之前保存了指向该节点的指针(如
2. ListNode* ans = new ListNode(0);:堆上创建(动态分配)
- 内存分配:通过
new
关键字在堆内存中手动分配节点,内存不会随作用域结束而自动释放。 - 生命周期:直到显式调用
delete ans;
才会释放内存,或程序结束时由操作系统回收。 - 访问方式:通过指针
ans
访问,使用->
运算符(如ans->val
、ans->next
)。 - 优势:
- 可以在函数间传递指针,即使创建节点的作用域结束,节点依然有效(只要未被
delete
)。 - 适合需要长期存在的对象(如链表节点,通常需要在函数返回后继续使用)。
- 可以在函数间传递指针,即使创建节点的作用域结束,节点依然有效(只要未被
- 注意:若忘记
delete
,会导致内存泄漏(堆内存未释放,持续占用资源)。
总结对比表
特性 | ListNode ans; (栈上) | ListNode* ans = new ListNode(0); (堆上) |
---|---|---|
内存位置 | 栈内存 | 堆内存 |
生命周期 | 作用域内有效,自动销毁 | 手动 delete 前一直有效 |
访问方式 | . 运算符(如 ans.val ) | -> 运算符(如 ans->val ) |
适用场景 | 临时使用,无需跨作用域传递 | 需要跨作用域使用(如链表节点、返回值) |
风险 | 作用域结束后指针失效(野指针) | 忘记 delete 导致内存泄漏 |
链表场景中的选择
在链表操作(如合并、反转、两数相加)中,几乎总是使用 new
在堆上创建节点,原因是:
链表节点需要在函数返回后继续存在(供调用者使用),而栈上的节点会随函数结束被销毁,导致返回的链表指针失效。
例如你之前代码中的 ListNode ans;
会导致后续 p->next = &tmp
指向已销毁的栈内存,而 new
创建的节点则能在函数返回后保持有效。