链表的初始化
c++
ListNode* Init(int n){
if (n <= 0) return nullptr;
ListNode* head = new ListNode(1);
ListNode* current = head; //把头结点地址赋值给下一个节点地址
for (int i = 2; i <= n; ++i) {
current->next = new ListNode(i);
current = current->next;
}
return head;
}Q:既然 ListNode* head = new ListNode(1)说明已经在堆区创建了,为什么还要返回head的地址?我直接在主函数中调用ListNode *head不就行了?
A:
虽然你在 Init() 函数中用了 new 在堆区创建了节点(ListNode* head = new ListNode(1);),但这个 head 指针本身是在 Init() 函数的栈上分配的局部变量。如果你不返回它,它就会在函数结束后“消失”,主函数是访问不到它的。
✅ 正确做法:返回 head
你应该这样写:
c++
ListNode* head = Init(5);这样,Init() 函数返回了指向堆内存中第一个节点的指针,你在主函数中就能通过 head 访问整个链表。
🧠 延伸思考:如果用引用传参?
如果你真不想用返回值,也可以通过 引用传参 的方式:
c++
void Init(int n, ListNode*& head) {
if (n <= 0) {
head = nullptr;
return;
}
head = new ListNode(1);
ListNode* current = head;
for (int i = 2; i <= n; ++i) {
current->next = new ListNode(i);
current = current->next;
}
}
// 使用方式
ListNode* head;
Init(5, head); // 这里通过引用将堆内节点地址“返回”出去Q:这个head指针本身是局部变量该怎么理解?
A:
🔍 什么叫“head 是局部变量”?
当你写这个函数:
c++
ListNode* Init(int n) {
ListNode* head = new ListNode(1); // ①
// ...
return head;
}- 这一句中的
head是定义在Init函数内部的局部变量(也就是局部作用域)。 - 它存在于 栈内存 中,当函数执行完毕后,这个指针变量
head本身会被销毁(出栈)。 - 但是,它指向的链表节点 是通过
new分配在 堆内存 中的,不会随函数结束而销毁。
✅ 简单来说:
head是局部变量 —— 它是个指针,存在栈上,生命周期只在函数内部。head(也就是链表节点)是动态分配的内存,在堆上,必须手动释放。
🧠 举个更直观的比喻:
把 head 想象成一个遥控器📱,它能控制一台电视📺(即堆上的链表节点):
head这台遥控器放在Init()这个房间里(栈中);- 电视机
new ListNode(1)放在客厅(堆中); - 如果你不把遥控器拿出来(即返回
head),那么外面就找不到这台电视了(你分配的内存也会泄漏)。
💥 如果不返回 head 会怎样?
你做了动态分配,但函数结束后:
head变量没了(指针变量被释放);- 没人再能访问
new出来的链表节点; - 内存泄漏发生 —— 你分配了空间但丢了指针。
✅ 小结:
| 名称 | 分配在哪里 | 生命周期 | 是否自动释放 | 举例 |
|---|---|---|---|---|
head | 栈 | 函数结束就消失 | ✅ 是 | ListNode* head; |
*head | 堆 | 手动 delete 才释放 | ❌ 否 | new ListNode(1) |