【问题标题】:C++ Linked List – a new pointer that is not used to traverse the list CAN print the list?C++ Linked List - 一个不用于遍历列表的新指针可以打印列表吗?
【发布时间】:2015-10-16 13:08:00
【问题描述】:

我在 C++ 中创建了一个简单的动态链表实现,它的头节点为 42,之后,如果他/她想要将其他数字添加到列表中,则会提示用户。

#include <iostream>

using namespace std;

struct Node
{
    int x;
    Node *next;
};

int main(int argc, char** argv)
{
    char choice;

    Node *start = new Node;

    start->next = NULL;
    start->x = 42;

    Node *traverser = start;

    while (1) {
        cout << "Add item to the list (Y/N)? ";
        cin >> choice;

        if (choice == 'Y') {
            traverser->next = new Node;
            traverser = traverser->next;
            traverser->next = NULL;
            cout << "New item: ";
            cin >> traverser->x;
        }
        else {

            cout << "Linked List:\n";
            Node *p;
            for (p = start; p != NULL; p = p->next) {
                cout << p->x << endl;                    //QUESTION HERE!
            }
            cout << "\nProgram dismissed.";
            exit(0);
        }
    }
}

现在问题,如代码块所示,在于指针 *p。我的链表的头部被命名为 start,而遍历并添加项目到链表的指针被命名为 traverser。为什么 *p 仅分配给头部时能够打印列表中的所有内容

p = start

而不是列表的主体。我会明白这适用于打印

cout << "Linked List:\n";
for (traverser = start; traverser != NULL; traverser = traverser->next) {
    cout << traverser->x << endl;
}

但是 *p 能够打印整个列表让我很困惑!

请帮忙。

【问题讨论】:

  • “不在列表的正文中”是什么意思?
  • p 指向与start 相同的东西。因此,无论您可以使用 start 做什么,您都可以使用 p
  • 指针“指向”事物,可以通过赋值改变为指向其他事物。 pstart开始,然后改为指向下一个Node等,直到下一个NodeNULL
  • @CaptainGiraffe 不是列表的主体,我的意思是指针被初始化为 *p = start,而不是 *p = traverser。我们知道 start 只包含一项 - 42,即列表的头部。而遍历器包含列表的整个主体。

标签: c++ pointers linked-list


【解决方案1】:

*p 能够打印整个列表,因为 *p (最初)指向列表的开头。在列表开始之后,是您链接的列表主体

if (choice == 'Y') {
        traverser->next = new Node;
        traverser = traverser->next;
        traverser->next = NULL;
        cout << "New item: ";
        cin >> traverser->x;
    }

了解这里,最初的 traverser 和 start 都操作同一个对象。用外行的话来说,当您使用指针时,您不是在克隆值,而是在克隆有关如何访问值的说明。也许这就是你困惑的根源?

所以,Node* start 指向一个节点。 Node* traverse 指向同一个节点,正如您声明的 Node *traverser = start; 您可以通过 traverse->x 或 start->x 操作相关节点的值,并获得完全相同的结果。

【讨论】:

  • 谢谢!但是有一个问题,您提到“最初遍历器和启动都操作同一个对象”,我们在这里谈论的究竟是哪个对象?一个对象应该是,说 Node obj 对吧?如果我在前面放一个指针,即 Node *obj,那么它在技术上就不再是一个对象了?
  • 通过对象,我的意思是指针开始和遍历指向的节点。用new Node; 创建的那个。当然,看到它只能通过指向它的指针来访问,它的存在很容易被忽视。所以简而言之,Node *p 是一个指针,不是一个对象,而是指向一个对象。
  • 哇,好答案!这完全消除了我现在的困惑。所以新节点就是对象!一直以来,我一直在试图找到对象的确切位置,而事实上,它一直是由“新”创建的。谢谢!
【解决方案2】:

p 只是一个指针变量,就像任何其他变量一样,它可以有不同的值,但它指向地址。

p = start

p 开始指向你的第一个节点。

 p = p->next

它开始指向下一个节点。 你在哪里迷茫?

【讨论】:

  • 你看,一开始,我初始化了头节点start->x = 42。这意味着struct对象start只有一项——链表的头。然后我初始化了一个DIFFERENT struct object *traverse = start,表示它指向start。在程序主体中,我通过动态更改 *traverser 指针而不是 *start 将项目添加到列表中。因此,初始化一个新的 Node *p = start,应该只包含 42,而不是整个列表,因为 start 和 traverser 是两个不同的结构对象指针。
  • starttraverse point 指向一开始的同一件事。您需要了解内存中不同对象之间的区别以及多个指针如何指向它们。
  • @Loqz :您没有创建 DIFFERENT 结构对象!您创建了一个不同的 pointer 指向 struct 对象,链表的第一个节点保持不变,您在开头创建 Node *start = new Node;,您只是创建了指向同一事物的不同指针。
【解决方案3】:

traverser 不包含列表的正文。 start确实。

让我们回顾一下你的程序的内容:

    Node *start = new Node;

start 将始终指向此处创建的节点。 start 始终是列表的开头。

从这个节点,您可以使用节点next 成员遍历整个列表。

Node *traverser = start;

traverser 最初是与start 节点相同的节点。 traverser 表示列表的结束。您不能使用traverser 浏览列表。使用traverser 的原因是它简化了在列表末尾插入新节点的过程。

语句显示最后一条语句

traverser->next = new Node;
traverser = traverser->next;
traverser->next = 0;

最后一条语句告诉我们,我们不能在任何地方跟踪traverser 节点。这是列表的结尾。

所以start是整个列表,start-&gt;x是列表中的第一个值。 start-&gt;next 是指向列表中下一个元素的指针。

现在,我们不想破坏列表中的start。因此,让我们复制指向第一个元素的指针,并将该副本称为 p。使用 p 浏览列表。 p 只对这一小部分代码有用,而starttraverser 对整个程序有用。

Node* p = start;  
for (; p != NULL; p = p->next) {
     cout << p->x << endl;
 }

最后打印的元素与traverser指向的元素相同。

【讨论】:

  • 知道了,谢谢!我可能误解了结构对象指针的独特功能。我认为声明两个 struct 对象,即 Node *start 和 Node *traverser 将是两个完全不同的相互独立的对象,这引起了混乱。我现在意识到结构对象和结构指针是完全不同的。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-09-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多