struct node {
char name[20];
int age;
int height;
node* next; // Pointer to the next node
};
node* startPTR = NULL; // global
void addNode_AT_END() {
node *temp1;
node *temp2;
temp1 = new node;
cout << "Enter the name : ";
cin >> temp1->name;
cout << endl << "Enter the age : ";
cin >> temp1->age;
cout << endl << "Enter height : ";
cin >> temp1->height;
temp1->next = NULL;
if( startPTR == NULL) {
startPTR = temp1;
} else {
temp2 = startPTR;
while( temp2->next != NULL )
temp2 = temp2->next;
temp2->next = temp1;
}
}
在这个代码片段中,当第三次调用函数时,else部分起作用。将startPTR
的地址分配给temp2
。在while循环中检查条件时,temp2->next
包含什么?(在第三次调用期间)如果你说它包含第二个节点的地址,请告诉它是如何知道第二个节点的地址的,因为我们在使用temp2->next = temp1
语句第二次调用函数期间将第二个节点的地址分配给了第一个节点,但由于它的局部作用域,我们丢失了地址。
这是我目前思考的方式。请解释在第三次调用函数时如何检查条件,以及链表是如何形成的?
只有指针变量temp1
和temp2
是局部作用域。实际的链表节点(类型为struct node
)是通过调用new
在堆上分配的。堆分配的数据一直存在,直到通过调用delete
释放。
这意味着temp2->next = temp1
行存储了附加到列表尾部的新节点的地址,并且该信息将在后续调用addNode_AT_END
函数时可用。
代码似乎有各种各样的问题-你使用全局变量,除非有后续调用delete
某处你有内存泄漏,已经有std容器类std::list
是可用的…
希望对你有帮助。
编辑:关于你的评论-当你调用new node
时,你正在堆上构造一个node
对象。该对象在后续调用delete
之前可以使用。
当您调用temp2->next = temp1
时,以下内容为真:
-
temp2
指向存储列表中最后一个节点的内存地址(该节点将在上次迭代中通过调用new
创建)。 - 指针变量
temp1
的值被赋值为列表中最后一个节点(temp2
"指向"的数据)的next
指针。这意味着该地址存储在堆中,而不是存储在本地temp2
指针变量中。
当你的函数退出时,是的,局部指针变量temp1
和temp2
超出了作用域,但是堆分配的链表节点不会被销毁-这就是地址存储的地方。
else
分支中,指针temp2
被初始化为指向列表的头行temp2 = startPTR;
下一行(while
循环)从头节点遍历链表,直到指针temp2
指向列表中的最后一个节点(直到temp2->next = NULL
)
在这个阶段,新节点被追加到列表中,如上所述。
在第三次调用期间,while循环的第一次迭代中的temp2->next
确实指向第二个节点。这里的关键是
temp1 = new node;
当您使用new
操作符时,这将在堆上分配一个对象(动态分配)并返回指向该对象的指针。使用new
在堆上分配的任何东西都会一直存在,直到您在指向该内存的指针上使用delete
。现在变量temp1
本身实际上只是堆栈上的一个指针,它是一个局部变量。这只意味着指针temp1
将超出作用域,但是您已经将第一个节点的next
指针指向堆上的第二个节点对象,因此它仍然在那里。