【问题标题】:Why is a pointer pointing to null evaluating to true?为什么指向 null 的指针评估为 true?
【发布时间】:2021-08-23 02:25:54
【问题描述】:

我有一个自定义数据结构,它本质上是一个循环链表。结束节点指向起始节点,起始节点指向列表中的第一个节点。该列表按预期完美运行,我只是不太确定以下代码的行为方式为何:

List::~List()
{
    Node* p = end->next;
    end->next = NULL;
    while (p != NULL)
    {
        Node* tmp = p;
        p = p->next;
        delete tmp;
    }
}

在解构器中,我将当前指针 (p) 设置为 end->next,正如我所说,它指向指向第一个数据节点的 start。然后我将end->next 设置为null,我认为这意味着现在开始指向任何内容。但是当它执行下一行while (p != NULL) 时,它的计算结果为真。这是为什么呢?

【问题讨论】:

  • 您将end->next 设置为空,但p 不为空。 p 是任何 end->next 在您将其设置为空之前。如果您希望将 end->nextNode **p = &(end->next) 的值作为别名,则需要 p 成为 Node**,然后当您执行 (*p) != NULL 时,您将跟随 p 指针返回准确的end->next,如果end->next 发生了变化,*p 将能够看到更新后的值。
  • @ggorlen 好吧,我明白了。我将指针分配与常规分配混为一谈。感谢您的复习!
  • 顺便说一句,你应该在 C++ 中使用 nullptr 而不是 NULL
  • 另外,在命名法上 - 您正在使用的函数是 析构函数,而不是“解构函数”。

标签: c++ pointers linked-list


【解决方案1】:

然后我将 end->next 设置为 null,我认为这意味着 start 现在不指向任何内容。

它没有。或者至少,我是这么认为的;我们无法知道,因为您还没有显示start。我假设 start 是一个不同的对象,因此修改 end 的成员不会修改它。 start 仍然指向它在分配之前指向的位置。分配的变化是end->next 不再指向它曾经指向的位置(根据您的说法,它是起始节点)。同样,p 仍然指向 end->next 在设置为 null 之前所指向的位置。

考虑一个类似的例子,由于没有指针,它可能更容易理解:

int end_next = 42;

int p = end_next;
end_next = 0;
assert(p != 0);

end_next的修改对p的值没有影响。它与指针的工作方式相同:

Node a_node;
Node* end_next = &a_node;

Node* p = end_next;
end_next = nullptr;
assert(p != nullptr);

当指针是成员变量时还是一样的(这里的例子应该和原程序很接近):

Node a_node;
Node* end->next = &a_node;

Node* p = end->next;
end->next = nullptr;
assert(p != nullptr);

【讨论】:

    【解决方案2】:

    您将end->next 设置为空,但p 不为空。 pend->next 在您将其设置为 null 之前的任何值。

    如果你想让p 成为end->nextNode **p = &end->next 的别名,你需要p 成为Node** 的别名,那么当你使用*p != NULL 时,你将跟随p 指针回到确切的end->next,如果end->next 发生了变化,*p 将能够看到更新后的值。

    这是一个简单的例子:

    #include <iostream>
    
    struct Node {
        struct Node *next;
    };
    
    int main() {
        struct Node *end = new Node{new Node{nullptr}};
        struct Node *p = end->next; // pointer to a Node
        struct Node **pp = &end->next; // pointer to a pointer to a Node
        std::cout << end->next << std::endl; // addr(end->next)
        end->next = nullptr;
        std::cout << p << std::endl; // still addr(end->next)
        std::cout << *pp << std::endl; // 0
        delete p;
        delete end;
    }
    

    这是一个线框图:

    p = end-&gt;next之后:

    .-------.
    |  end  |  .------.
    | [next]-->| Node |
    `-------`  `------`
                  ^
                  |
               .------.
               |  p   |
               `------`
    

    end-&gt;next = NULL之后:

    .-------------.
    |     end     |
    | [next=NULL] |
    `-------------`
    
               .------.
               | Node |  
               `------`
                  ^
                  |
               .------.
               |  p   |
               `------`
    

    你可以看到 p 仍然不是 null 只是因为 end-&gt;next 是。

    使用双指针**pp,在p = end-&gt;next之后,我们有:

    .-------.
    |  end  |  .------.
    | [next]-->| Node |
    `---^---`  `------`
        |         ^
        |         |
    .-------.  .------.
    |  pp   |  |  p   |
    `-------`  `------`
    

    现在我们有一个指向指针end-&gt;next 的指针。在end-&gt;next = NULL之后,我们有:

    .-------------.
    |     end     |  .------.
    | [next=NULL] |  | Node |
    `---^---------`  `------`
        |               ^
        |               |
    .-------.        .------.
    |  pp   |        |  p   |
    `-------`        `------`
    

    *pp 给了我们end-&gt;next 的当前值,NULL。

    【讨论】:

      猜你喜欢
      • 2012-04-22
      • 2020-04-22
      • 2023-03-28
      • 1970-01-01
      • 1970-01-01
      • 2014-06-17
      • 2015-03-15
      • 1970-01-01
      • 2012-10-07
      相关资源
      最近更新 更多