这不是我的代码。我把这个代码从这个网站上删除了:
http://www.macs.hw.ac.uk/~rjp/Coursewww/Cwww/linklist.html
我正在使用有关如何构建链接列表的参考资料。我对发生的事情感到有些困惑。有人可以向我解释发生了什么事。我会用1-5来标记令我困惑的事情。
#include<stdlib.h>
#include<stdio.h>
struct list_el {
int val;
struct list_el * next;
};
typedef struct list_el item;
void main() {
item * curr, * head;
int i;
head = NULL; //1
for(i=1;i<=10;i++) {
curr = (item *)malloc(sizeof(item));
curr->val = i;
curr->next = head; //2
head = curr; //3
}
curr = head; // 4
while(curr) { //5
printf("%d\n", curr->val);
curr = curr->next ;
}
head = NULL→为什么head被设置为NULL?我知道你应该(我是出于习惯),但我不知道为什么。
curr-&gt; next = head→我也从未真正理解过这一点。也许我对“head”的定义错了,但是在常规链表中,它是列表中的起始节点还是最后一个节点?我一直认为它是起始节点,但在这一行中它看起来像是最后一个节点。
head = curr→为什么我们将它设置为等于curr?
curr = head→然后在循环完成后设置curr = head。
while(curr)→只是为了确保,这是遍历列表,它等同于while(curr!= NULL)对吗?
答案 0 :(得分:19)
#1:
head = NULL
初始化指针。建议通常 将声明初始化为NULL(1)或声明后立即(2)。如果程序员错误地取消引用未初始化的指针,则返回垃圾值。如果静态分析器和编译器没有显示未初始化指针的警告或错误消息,通常很难调试。
有关详情,请参阅Steve McConnell's Code Complete: A Practical Handbook of Software Construction上的Defensive Programming或维基百科页面。
#2:
curr->next = head
构建链接列表。 curr
节点正在“链接”到序列中先前创建的节点。
#3:
head = curr
更新头部指针。 head
指针正在更新,指向最近的malloc
ed节点。
下图说明了步骤#2和#3:
#4:
curr = head
重新初始化指针。此步骤类似于步骤2:curr->next = head
。通过将curr
节点设置为head
,curr
可以“准备好”while
循环中的链接列表遍历。从类比来看,这就像在循环开始时将迭代变量初始化为0(即i = 0
)。要使此步骤可视化,请参阅下面显示执行此语句之前/之后的插图:
#5:
while(curr)
遍历列表。
鉴于curr
指向第一个节点(来自步骤#4),此while
循环遍历列表,直到curr->next
返回NULL。在一个不太抽象的形式中,我们可以将此语句重写为while(curr != NULL)
。
答案 1 :(得分:5)
答案 2 :(得分:3)
(1)。你需要将它设置为某种东西,使用NULL是一种说它不指向任何东西的方式。通常NULL与0相同。在某些语言中,您不需要初始化变量,因为它会自动将其设置为nil。但是C不这样做,所以你必须自己做。
(2)。 head
指向列表的第一个节点。首先,它是NULL,这意味着列表为空,因此head
没有指向任何东西。 cur
是一个想要插入列表的新节点。 curr->next
想要指向现有列表的第一个节点,这就是curr->next
设置为head
的原因。
(3)。此时head
不再指向第一个节点。第一次通过循环,它看起来像这样:
curr-->node1-->NULL head--^
但总的来说它看起来像这样
curr-->node3-->node2-->node1-->NULL head--^
因此我们需要更新head
以指向第一个节点。由于curr
指向位于前面的新创建的节点,因此我们只需将head
设置为指向与curr
相同的节点。
(4)。该计划的第一部分已完成。不再需要curr
,因为它用于跟踪我们创建的新节点。这是一个临时变量。这一行curr = head
表示我们要将curr
初始化到列表的开头。我们可以使用另一个变量来使其更具可读性,但您通常会看到临时变量的重用。
(5)。对。您可能会将NULL
定义为(void*)0
,因此它与0相同。除了60年代或70年代的旧机器外,您可能永远不会看到0以外的其他值。从逻辑上讲,它相当于:
while (curr != 0)
与while (curr)
相同。
答案 3 :(得分:2)
<强> 1。 head = NULL→为什么head被设置为NULL?
初始化变量是一种很好的做法。在一些系统中,声明的变量具有在抓取地址空间时在内存中发生的任何事情。
<强> 2。 curr-&gt; next = head→我也从未真正理解过这一点。也许我对“head”的定义错了,但是在常规链表中,它是列表中的起始节点还是最后一个节点?我一直认为它是起始节点,但在这一行中它看起来像是最后一个节点。
是的,头部是起始节点。
第3。 head = curr→为什么我们将它设置为curr?
此循环在此处添加新节点作为头部。像堆栈一样。其他方法可以在尾部添加新节点。两种方式仍然是“链表”。
<强> 4。 curr = head→然后在循环完成后设置curr = head。
curr
就像一个索引,一个工作变量,因此您不会破坏数据结构。他完成后正在重置它。如果愿意的话,“复卷”。
<强> 5。 while(curr)→只是为了确保,这是遍历列表,它等于while(curr!= NULL)对吗?
是的,这是你在C中找到的那些隐含的东西之一。在while循环中任何东西都是隐含的while(whatnot != 0)
和null == 0。
答案 4 :(得分:2)
首先,您可以在Linked List Head Is Always Null和Simple C++ Linked List中找到问题的答案,为什么head始终为NULL。您可以找到singly linked list in c的初学者教程。语句head = curr将指针头的值与通过分配内存接收非零值的当前指针的值的NULL相关联。 while(curr)是一个循环,当long curr与NULL不同时运行,NULL作为指向地址的宏关联零值。
答案 5 :(得分:2)
我们从没有开始。那就是
head = NULL;
告诉我们。我们还没有列表,所以我们无法访问它。
现在我们从1到10循环。我们从后到前构建一个列表。 HEAD为NULL,因此“last”(第一次创建)指向NULL:
curr->next = head; // head is NULL in the first loop
HEAD现在设置为这个新元素:
head = curr;
第二次运行此循环时,head将指针存储到最后创建的项目。然后新创建的将指向它。我们在最后一项之前设置了这个新项目。
设置
head = curr;
需要完成,以确保头部在下一个循环中包含正确的指针。它被称为head,因为它始终存储在此之前创建的列表的开头。
// 4不是必需的。
之前的最后一次操作是:
head = curr;
所以
curr = head;
毫无意义。
第五个遍历列表。 “curr”指向第一个项目(带有非NULL地址),并在每个循环中设置为curr-&gt; next。一旦curr为NULL(在最后一项),语句就不再成立。
答案 6 :(得分:0)
在第4个问题中,我认为curr=head
是不必要的。因为当循环结束时,curr和head指针指向同一个节点(i = 10的节点)。
但这是个好习惯。