<p>单向链表节点须用指针定义:struct Node { int data; Node next; };,其中next必须为Node类型以避免递归定义错误,并建议构造函数中初始化为nullptr。</p>

怎么用指针定义单向链表节点
单向链表的核心是每个节点存数据 + 下一个节点的地址,C++ 里必须用指针来表达“下一个”的指向关系。next 成员必须是指针类型,否则无法动态串联。
常见错误是写成 Node next;(值类型),这会导致无限递归定义、编译报错 invalid use of incomplete type;或者漏掉 * 写成 Node next; 而不是 Node* next;。
-
struct Node { int data; Node* next; };—— 正确:next是指向Node的指针 - 构造函数建议显式初始化
next为nullptr,避免野指针:Node(int d) : data(d), next(nullptr) {} - 不要在节点里直接 new 一个新
Node,那会引发内存泄漏或逻辑混乱
插入节点时指针怎么改才不丢链
插入分头插、尾插、中间插,但本质都是修改某处的 next 指针。最容易出错的是“先连后断”还是“先断后连”——顺序错了就断链。
比如头插:必须先让新节点的 next 指向原头节点,再把头指针更新为新节点。如果反过来(先动头指针),原链表就找不到了。
立即学习“C++免费学习笔记(深入)”;
组合式C++代码评审方案,融合静态分析、AI推理、多轮迭代评审和C++专项检查,适用于PR审查、增量代码审查、全项目评审和代码质量评分,触发词包括review cpp、cpp代码评审、C++review、代码审查。
- 头插:
new_node->next = head; head = new_node; - 尾插:需遍历到
last->next == nullptr的位置,再赋值:last->next = new_node; - 中间插(如插在
prev后):new_node->next = prev->next; prev->next = new_node;—— 这个顺序不能颠倒
遍历和删除时怎么避免访问空指针
所有涉及 -> 解引用的操作前,必须检查指针是否为 nullptr。常见崩溃错误是 curr->next = curr->next->next; 在 curr->next 为空时直接解引用。
遍历时循环条件别写成 curr != nullptr 就完事——如果你要访问 curr->next,就得提前判断 curr 和 curr->next 都非空。
- 安全遍历:
for (Node* curr = head; curr != nullptr; curr = curr->next) - 删节点(非头):
if (curr->next && curr->next->data == target) { Node* to_del = curr->next; curr->next = to_del->next; delete to_del; } - 删头节点要单独处理:
if (head && head->data == target) { Node* old = head; head = head->next; delete old; }
为什么 delete 后不置 nullptr 容易出问题
delete 只释放内存,不改指针值。被删掉的指针变成悬空指针(dangling pointer),后续若误用(比如再次 delete 或访问),行为未定义,可能 crash 或静默错误。
这不是风格问题,是实际调试中高频雷区——尤其在多处持有同一节点指针时(比如迭代器、临时备份指针)。
- 删完立刻置空:
delete ptr; ptr = nullptr; - 头删后别忘了更新
head:delete head; head = nullptr;(如果链表变空) - 用智能指针(如
std::unique_ptr<node></node>)能自动管理,但手写链表时必须手动置空
链表本身结构简单,但指针操作的每一步都依赖“当前指针是否有效”这个前提。漏掉一次 nullptr 检查,或删完没置空,后面 debug 时往往要花几倍时间定位。

















