将结构元素地址设置为C 中的null(单链接列表)
Setting a struct element address to null in C++ (singly linked list)
我有这个结构:
struct Node {
int num;
Node *next;
Node(int, Node*);
};
在Collection
中内部。
当我尝试删除列表的最后一个元素时,使用此功能:
void Collection::remove(int num){
Node *target = find(num);
if (target == nullptr) return;
n--;
Node *temp = target ->next;
if (temp == nullptr) {
delete target;
target = nullptr; // This is where the problem occurs
return;
}
target->num = temp->num;
target->next = temp->next;
delete temp;
}
上一个节点的*next
仍指向现在空的地址位置,我如何将target
内存位置设置为null
?
有关更多信息,这是我的功能find()
Collection::Node* Collection::find(int num) {
Node *temp = head;
while (temp != nullptr && temp->num != num) temp = temp->next;
return temp;
}
实际上,您实际上在正常的删除逻辑上使用了轻微的变化,该逻辑在最多的情况下工作。该变化不是删除当前元素,而是将 data 从以下元素移动到其中,然后删除以下元素。这意味着您永远不必备份以前的元素,这是困难的(如果不存储额外的信息或再次浏览列表)使用单链列表。
不幸的是,当您删除列表中的最终元素时,该不工作的一种情况是。在这种情况下,没有以下元素可以将数据从中移动,因此您需要删除 current 元素并调整上一个元素以成为列表的新末端。
,而且,由于您无论如何都需要这样做,因此您也可以恢复到所有情况下的正常逻辑: - )
使用该逻辑,您基本上需要在要删除的元素之前访问元素。然后,您将其next
指针设置为绕过要删除的指针。
您还需要处理列表中 first 元素的特殊情况。假设您有一个head
成员指向第一个元素,并且curr/prev
分别指向要删除的节点及其前身,则伪代码为:
if curr is head:
set head to curr.next
else
set prev.next = curr.next
free curr
一种轻松执行此操作的方法而不涉及太多更改的方法是修改您的find
方法,以便您也可以使用它来获取先前的节点:
Node* Collection::find(
int num,
Node **pPrev = nullptr
) {
// Initially store null as previous item.
if (pPrev != nullptr) *pPrev = nullptr;
// Cycle through list until found or not there.
Node *temp = head;
while ((temp != nullptr) && (temp->num != num)) {
// Update previous before advancing.
if (pPrev != nullptr) *pPrev = temp;
temp = temp->next;
}
return temp;
}
请注意,我只是在代码中而不是Collection::Node
中使用了Node
,因为您的问题都具有变体,而且我不确定您是否在 namespace 中称为 Collection
。根据您的实际用法,只需根据需要进行调整。
在任何情况下,将第二个参数默认为nullptr
将允许您与当前完全调用(使用一个参数,它不会打扰尝试存储以前的节点指针)。
但是,如果您想要 先前的指针,您将使用类似的内容删除:
Node *prev;
Node *curr = find(num, &prev); // Get previous as well.
if (curr != nullptr) { // Only delete if actually found.
if (prev == nullptr) // Null means current is head.
head = curr->next;
else // Otherwise adjust previous.
prev->next = curr->next;
delete curr; // Regardless of head-ness, delete.
}
所有这些看起来像我的老式C:)
要实际更改收藏集外的内存::删除函数,您应该修改查找功能以实际返回指针到点:
Node** find(int num) {
Node **temp = &head;
while (*temp != NULL && (*temp)->num != num)
{
temp = &((*temp)->next);
}
return temp;
}
使用指针在点上,您可以更改原始内存:
int main(int argc, char *argv[])
{
head = new Node(1, new Node(2, new Node(3, NULL)));
Node **elem = find(2);
if (*elem)
{
delete *elem;
*elem = NULL;
cout << "elem 2 deleted" << endl;
}
elem = find(2);
if (*elem)
{
delete *elem;
*elem = NULL;
cout << "elem 2 deleted" << endl;
}
cout << "Hello World!" << endl;
return 0;
}
和您的收藏::删除看起来像:
void Collection::remove(int num){
Node **target = find(num);
if (*target == nullptr) return;
n--;
Node *temp = (*target)->next;
if (temp == nullptr) {
delete *target;
*target = nullptr;
//cout << "elem " << num << " deleted " << endl;
return;
}
(*target)->num = temp->num;
(*target)->next = temp->next;
delete temp;
}
但似乎您的删除功能无法正常工作。如果该列表等于NUM参数,它将仅删除列表的最后一个元素。为了使其正常工作,您可能需要使此列表向前和落后迭代,以使以前的元素指向下一个元素。或者,您可以更改查找函数以返回以前的元素。
设置指针到nullptr
不一定会更改其值。如果您放弃nullptr
,则煽动不确定的行为(请参阅此处)。在这种情况下,未定义的行为意味着您仍然能够引用该内存并插入它。但是下次可能会使您的程序崩溃。你在这里做的是不好的:
if (temp == nullptr) {
delete target;
target = nullptr; // You delete target
}
target->num = temp->num; // Then you immediately dereference it.
您需要在之前设置下一个删除target
。
target->next = temp->next;
delete temp;
- lambda参数转换为constexpr技巧,然后获取带链接的数组
- CMake-按正确顺序将项目与C运行时对象文件链接
- 从链接列表c++中删除一个项目
- 有根的二进制搜索树.保留与其父级的链接
- 读取文件的最后一行并输入到链接列表时出错
- 静态数据成员的问题-修复链接错误会导致编译器错误
- node-gyp 在 macOS 上未正确链接库
- 基于boost的程序的静态链接——zlib问题
- 无法链接 CMake 中的本地库
- 内联函数中具有内部链接的全局变量
- 链接阶段在Ubuntu上失败,但在MacOS上失败
- 使用gcc从静态链接的文件中查找可选符号
- 我可以将一个用clang c++11编译的对象与另一个用c++17编译的对象链接起来吗
- 将--whole archive链接器选项与CMake和具有其他库依赖项的库一起使用
- 在链接链接静态(GSOAP)库的共享库时,为什么会得到一个未定义的符号
- 未定义的参考,但链接链接
- 链接链接器/加载器错误时"undefined reference to ..."与拉斯皮康库链接时
- 将Typedef语句放入类链接链接列表中的C 错误
- 对嵌套结构单链接和双链接进行排序
- 如何制作一个函数,只需更改链接即可交换单链表中的两个相邻元素