下面代码可以安全地删除单链表的头结点,并使 head 指向删除后的新头结点。
Node *p = head;
delete p;
head = p->next;看到题先想三件事:1)delete 后 p 是否还能用?2)head 更新时机是否安全?3)是否遗漏了临时指针保存后继?关键观察是代码顺序:p = head; delete p; head = p->next; 这里 delete p 后 p 悬空,紧接着 p->next 就是非法访问。正确的删除头结点流程是:Node *tmp = head; head = head->next; delete tmp; 先用 tmp 保存原头结点,再更新 head,最后释放 tmp。这一类题的通法是"先存后继,再改头,后删旧",任何删除操作都要保证被删节点在释放前至少被访问一次。
选项 A 是"正确",命题人利用考生对"先释放再更新"的直觉,以为只要最终 head 指向新节点就行,忽略了中间步骤的内存安全。选项 B 是"错误",正确。题目中最阴险的细节是"绝对化表述"——代码看似简洁,实则违反 C++ 标准,delete 后指针立即失效,后续访问 p->next 属于未定义行为,编译器可能优化掉 p->next 的访问,导致运行时崩溃。边界条件也值得注意:若 head 为 nullptr,代码会先解引用 head,直接崩溃,但题目隐含 head 非空,所以主要陷阱仍是内存安全。
本题考查《GESP 考试大纲》C++ 语言基础中"指针与内存管理"模块(五级),同时涉及数据结构"链表"操作。命题人放这道题,就是卡住考生对"delete 后指针有效性"的盲区——很多考生凭直觉认为"先删再改"没问题,却忽略了 C++ 标准中 delete 后指针立即失效,后续访问 p->next 属于未定义行为。
看到题先想三件事:1)delete 后 p 是否还能用?2)head 更新时机是否安全?3)是否遗漏了临时指针保存后继?关键观察是代码顺序:p = head; delete p; head = p->next; 这里 delete p 后 p 悬空,紧接着 p->next 就是非法访问。正确的删除头结点流程是:Node *tmp = head; head = head->next; delete tmp; 先用 tmp 保存原头结点,再更新 head,最后释放 tmp。这一类题的通法是"先存后继,再改头,后删旧",任何删除操作都要保证被删节点在释放前至少被访问一次。