链表头结点指向失败
情况一:Node ans = new Node(); Node headAns = ans;
当你使用 Node ans = new Node();
时,你在内存中创建了一个新的 Node
对象实例,并且 ans
变量存储了这个新对象在内存中的地址。
然后 Node headAns = ans;
这行代码做的事情是,将 headAns
也赋值为 ans
所存储的内存地址。也就是说,此时 ans
和 headAns
都指向了同一个刚创建的 Node
对象,它们共享这个对象的内存地址。
当你后续通过 ans = ans.next;
来移动 ans
指针沿着链表前进时,比如假设 next
指向了链表中的下一个节点,那么 ans
就会更新为指向新的节点,但 headAns
并没有被改变,它仍然指向最初的那个节点,也就是整个链表的头节点。
这是因为 headAns
只是存储了一个内存地址,当你没有对它进行重新赋值操作时,它就会一直保持指向最初的那个对象,也就是链表的头节点。
情况二:Node ans = null; Node headAns = ans;
在这里,Node ans = null;
表示 ans
初始化为一个空指针,它不指向任何有效的内存地址,也就是没有指向任何实际的 Node
对象。
然后 Node headAns = ans;
使得 headAns
也被初始化为同样的空指针状态。
当你后续尝试通过 ans = ans.next;
来移动 ans
指针时,因为 ans
最初就是空指针,所以 ans.next
这种操作是非法的(会导致程序崩溃,通常会抛出空指针异常之类的错误,具体取决于编程语言),在假设没有发生这种错误并且我们继续分析的情况下,即使 ans
被赋予了某个新的节点地址(假设通过其他正确的方式给 ans
赋值了一个有效的节点地址),headAns
仍然保持为空指针,因为它没有被重新赋值过,它始终指向最初的那个空状态,也就是它不会自动跟着 ans
的赋值变化而变化,始终保持为 null
。
所以总结来说,在这两种情况下,关键的区别在于最初 ans
是否指向了一个实际的对象(通过 new Node()
创建的情况)还是初始化为空指针(null
)的情况。当 ans
初始化为空指针时,后续的操作如果没有正确地更新 headAns
,它就会一直保持为空指针状态,而不会指向实际构建的链表的头节点。
Node ans = new Node(); Node headAns = ans;
这样写,ans链表添加节点next,ans = ans.next,headAns可以指向一整个链表的头结点。
Node ans = null; Node headAns = ans;
这样写,ans链表添加节点next,ans = ans.next,headAns不可以指向一整个链表的头结点,始终为null
变量=null会赋值内存地址吗
不会
当你将一个变量赋值为 null
(在支持 null
概念的编程语言中,比如 Java、C# 等),它并不会被赋予一个有效的内存地址来指向实际的数据对象。
相反,null
表示该变量不指向任何有效的内存位置,也就是它没有引用任何实际存在的对象或数据结构。
例如在 Java 中:
class MyClass { // 类的定义内容 } MyClass obj = null;
这里的 obj
变量被初始化为 null
,此时它在内存中并没有一个有效的内存地址与之对应,它仅仅是一个空的引用,表示目前没有指向任何 MyClass
的实例对象。
在 C++ 中,虽然没有直接等同于 null
的概念,但有类似的空指针表示方式,比如 nullptr
:
class MyClass { // 类的定义内容 }; MyClass* obj = nullptr;
这里的 obj
指针被初始化为 nullptr
,同样意味着它不指向任何有效的 MyClass
对象,也就是没有一个有效的内存地址与之关联,它只是一个空指针的状态,表示当前未指向任何实际的内存区域来获取 MyClass
对象相关的数据。
所以,将变量赋值为 null
(或类似的空指针表示形式)是表示该变量当前不具有有效的内存地址指向,而不是被赋予了一个特定的内存地址。