当前位置: 首页 > 知识库问答 >
问题:

在 C 中将结构元素地址设置为 null(单链表)

子车修平
2023-03-14

我有这样的结构:

struct Node {
    int num;
    Node *next;

    Node(int, Node*);
};

在类< code >集合内部。

当我尝试删除列表的最后一个元素时,使用此函数:

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;
}

前一个节点的< code>*next仍然指向现在为空的地址位置,如何将< code >目标内存位置设置为< code>null?

有关详细信息,这是我的函数find()

Collection::Node* Collection::find(int num) {
    Node *temp = head;
    while (temp != nullptr && temp->num != num) temp = temp->next;
    return temp;
}

共有3个答案

干善
2023-03-14

将指针设置为nullptr并不一定会更改其值。如果您取消引用nullptr,则您正在煽动未定义的行为(请参阅此处)。在这种情况下,未定义的行为意味着您仍然能够引用并插入该内存。但下次它可能会让你的程序崩溃。你在这里做的很糟糕:

if (temp == nullptr) {
       delete target;  
       target = nullptr;       // You delete target
} 
target->num = temp->num;       // Then you immediately dereference it.

在删除< code>target之前,您需要设置next。

target->next = temp->next;
delete temp;
麹培
2023-03-14

对我来说,这一切看起来都像是老式的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参数,它将只删除列表中的最后一个元素。为了使它正确工作,你可能需要使这个列表向前和向后可迭代,以使前一个元素指向下一个。或者您也可以修改find函数来返回前一个元素。

弘涛
2023-03-14

实际上,您使用的是普通删除逻辑的一个微小变化,这在大多数情况下都有效。不同之处在于,不是删除当前元素,而是将数据从下一个元素移到当前元素中,然后删除下一个元素。这意味着你永远不需要返回到前一个元素,这对于单链表来说是很困难的(不需要存储额外的信息或者再次遍历链表)。

不幸的是,当您删除列表中的最后一个元素时,这种方法不起作用。在这种情况下,没有后续元素可以从中移动数据,因此您需要删除当前元素并调整前一个元素以成为列表的新结尾。

而且,由于您无论如何都需要这样做,因此您最好恢复到所有情况下的正常逻辑:-)

按照这种逻辑,您基本上需要在要删除的元素之前访问该元素。然后将其下一个指针设置为绕过要删除的指针。

您还需要处理删除列表中第一个元素的特殊情况。假设您有一个指向第一个元素的< code>head成员和分别指向要删除的节点及其前置节点的< code>curr/prev,伪代码将是:

if curr is head:
    set head to curr.next
else
    set prev.next = curr.next
free curr

一种不涉及太多更改的简单方法是修改您的< code>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;
}

请注意,我只是在代码中使用了Node,而不是Collection::Node,因为您的问题有两种变体,我不确定您是否在名为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.
}
 类似资料:
  • 我使用JAXB生成了类。它为一些复杂元素生成了列表。我提供了一个由JaxB生成的类示例- ArrayOfLineOfBusiness用于Customer类 我的模型类类似于以下内容: 下面是我的推土机贴图 我想设置ArrayOfLineOfBusiness,如果我的服务模型中的lineOfBusiness数组为空。有办法吗?

  • 问题内容: 我有一个带有文本框的Web表单。默认情况下,如何将焦点设置到文本框? 像这样: 所以有人可以帮我吗?我不知道如何使用JavaScript将焦点设置到文本框。 问题答案: 做这个。 如果您的元素是这样的。 您的脚本是

  • 问题内容: 我希望将值设置为如果我提交的表单中的文本框未放入任何内容。我怎样才能做到这一点?我尝试插入,但这只是将单词添加到字段中。 我不确定应该为此提供什么代码,我只是在编写UPDATE查询。 问题答案: 不要在更新语句中加引号。这应该工作:

  • 问题内容: 通过使用strace和ifconfig,我发现可以通过以下方式设置IP地址: 但是我对这种解决方案不是很满意: 这样做的“正确”方法是什么? 问题答案: 没有魔术+2的IPv4的“正确”方式: 要使用IPv6,请将其强制转换为

  • 问题内容: 我试图找出一种在Hive中从平面源中选择数据并将其输出到一个名为struct的数组中的方法。这是我正在寻找的示例… 样本数据: 所需的输出: 我尝试了collect_list和collect_set,但是它们仅允许原始数据类型。关于如何在Hive中进行此操作有任何想法吗? 问题答案: 我会使用这个jar,它是的更好的实现(并需要复杂的数据类型)。 查询 : 输出 :

  • 本文向大家介绍在C ++中将单链表转换为XOR链表,包括了在C ++中将单链表转换为XOR链表的使用技巧和注意事项,需要的朋友参考一下 在本教程中,我们将讨论将单链表转换为XOR链表的程序。 为此,我们将提供一个单链表。我们的任务是获取该列表的元素,并将其转换为XOR链接列表。 示例 输出结果