指针解除引用如何工作?

#define SWAP_PTRS(a, b) do { void *t = (a); (a) = (b); (b) = t; } while (0) Node* MergeLists(Node* list1, Node* list2) { Node *list = NULL, **pnext = &list; if (list2 == NULL) return list1; while (list1 != NULL) { if (list1->data > list2->data) SWAP_PTRS(list1, list2); *pnext = list1; pnext = &list1->next; list1 = *pnext; } *pnext = list2; return list; } 

这段代码来自这里,是这个问题的选择答案。

我在这里无法理解3行:

 *pnext = list1; pnext = &list1->next; list1 = *pnext; 

有人可以帮助我吗? 为我解释一下?

编辑:我可以更改这两行:

 pnext = &list1->next; list1 = *pnext; 

  list = list-> next; 

从一开始:您将有两个列表和一个新的列表头,您将返回。 pnext最初指向那个。

该代码旨在尽可能少地执行指针重新分配,因此尝试保持输入列表的初始“下一个”指针保持不变。

 list1 pnext->list->Null | V o->o->o... list2 | V o->o->o... 

Swap用于确保较小的元素是list1的第一个元素。 这些行的作用是:

一步一步走:

 *pnext = list1; 

获取* pnext(在第一次迭代之前是列表)以指向包含最小元素的节点:

 list1 | V o->o->o... ^ | list<-pnext list2 | V o->o->o... 

 pnext = &list1->next; 

这是棘手的部分,如前所述&运营商优先级低。 它也难以以图形方式显示,因为它实际上是查看Node构造的一部分。 虽然如此:

 list1 | V o---->o->o... ^ ^ | | list x<-pnext list2 | V o->o->o... 

其中x是list1指向的o的下一个指针。

 list1 = *pnext; 

在处理第一个元素时,使list1 head前进。

  list1<-pnext | V o->o->o->... ^ | list list2 | V o->o->o->... 

您从此处与列表无关,因为您希望将其作为合并列表的头部返回。

不变量存在pnext指向最后处理的元素的下一个指向的位置,这是list1-2中最小元素应该去的位置。 有趣的东西发生在交换中,尝试自己计算出确切的过程(很难像这样绘制,并且很好地练习以了解**的作用)。 如果我找到一个很好的方法来绘制它,我可能会添加它。

你不能使用list = list-> next; 因为它会做这样的事情:

  list1 | V o->o->o->... ^ | list list2 | V o->o->o->... 

这意味着你失去了那个孤独的o(以及随着循环的进展最终的一切)。

编辑: *pnext = list2; 最后这样做:

循环终止(上述声明之前的状态):

  list1<-pnext | V o->o->o->null ^ | list o->o->o->... ^ | list2 

声明后:

  list1 | V o->o->o Null ^ | | | list | V o->o->o->... ^ | list2<-pnext 

该语句将剩余列表附加到列表的末尾。 然后返回Node * list,指向合并列表的头部。

EDIT2:

一直以来,pnext会更好地表示如下:

  list1 | V o->o->o Null ^ | | |<-pnext list | V o->o->o->... ^ | list2 

这意味着它指向最后处理的节点的下一个指针。

pnext指向Node的指针

*pnext ”表示您正在使用pnext指向的值。 从而:

 *pnext = list1; 

意味着指针pnext指向的任何东西现在指向与list1相同的东西。


为清楚起见,下一行应放在括号内:

 pnext = &(list1->next); 

list1->next表示您正在访问list1指向的next属性,而&表示获取该元素的地址。 本质上意味着你正在将pnext指向指向下一个元素的指针。


最后一行:

list1 = *pnext;

表示您获取pnext指向的值并将其分配给list1

list1的类型为Node*pnext的类型为Node**这意味着它应该保存类型为Node*的变量的地址。

 *pnext = list1; 

当您取消引用pnext ,您将获得Node* 。 所以,这个任务是正确的。

 pnext = &list1->next; 

这里->优先于& 。 所以,它返回一个指针的地址(即Node *类型的地址)

 list1 = *pnext; 

这与第一个陈述正好相反。 pnext引用pnext会给出可以分配给list1 Node*


是的,你可以改变它(即,逻辑上他们做同样的事情) –

 pnext = &list1->next; list1 = *pnext; 

 list1 = list1->next ; 

但是,你有一个声明 –

  *pnext = list2; 

如果pnext两步序列初始化,则取消引用未初始化的指针(即*pnext )将导致分段错误。 这就是原因。

尝试安装visual studio express版。 在VS-2012中调试程序后,只需将鼠标hover在指针上,它就会通过取消引用地址来显示内容。