单链表的内存本质是节点分散存储、逻辑通过指针串联:每个节点含数据域和存放下一节点地址的指针域,节点间地址不连续;头指针作为唯一入口标识链表,本身不存数据。

单链表的内存本质:节点分散,逻辑成链
单链表不是一块连续的“大蛋糕”,而是一串散落在内存各处的“小点心”。每个节点(node)由两部分组成:数据域(比如一个整数)和指针域(一个指向另一个节点的地址)。这两部分在内存中紧挨着,构成一个独立的内存块;但不同节点之间,地址完全不连续——可能一个在 0x7fff1234,下一个在 0x6000abcd,再下一个又跳到 0x5000ff00。这种离散性是链表动态性的根基:新增节点时,系统只需在堆(heap)里随便找一块空地 malloc 出来,不用管前后有没有邻居。
指针域到底存什么?不是值,是“门牌号”
指针域存储的不是下一个节点的数据,也不是某种抽象概念,而是**下一个节点在内存中的起始地址**——就像一张纸条上写着“隔壁老王家门牌号:302室”。在 C 中,struct ListNode* next 是一个变量,它本身的值就是这个地址(例如 0x6000abcd);在 Java 中,Node next 是一个引用,其语义等价,只是语言层做了封装,不暴露原始地址数值。关键在于:只要拿到这个地址,就能定位并访问那个节点的 data 和它的 next,从而实现“一环扣一环”的遍历。
为什么必须初始化 next 为 NULL?
新 malloc 出来的内存是“脏”的,里面全是随机残留数据。如果不显式设置 newnode->next = NULL,那这个指针域就可能指向一个非法地址(比如 0x00000001),后续遍历时一旦顺着它跳转,程序大概率崩溃。NULL 是一个约定俗成的“终止信号”,表示“这里没下一站了”。链表的尾节点靠它收尾,遍历循环靠它退出(while (cur != NULL)),插入删除操作也靠它判断边界。这不是可选项,是内存安全的底线。
头指针:唯一入口,不存数据
头指针(如 struct ListNode* head)本身是一个局部变量或全局变量,它不包含 data 或 next,只负责“记住第一个节点在哪”。它可能指向堆里的某个节点,也可能为 NULL(空链表)。它像一把钥匙,打开整条链的大门;但它本身不是门上的一块砖。操作链表时,所有遍历、插入、删除都从 head 出发,靠不断解引用 next 往后走——整个逻辑链条,全靠这一串地址接力完成。










