指针解除引用如何工作?

时间:2011-03-21 09:19:39

标签: c pointers dereference

#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;
}

此代码来自此处,this question的所选答案。

我在这里无法理解3行:

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

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

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

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

 list = list-> next; 

4 个答案:

答案 0 :(得分:3)

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

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

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

list2
|
V
o->o->o...

交换是为了确保较小的元素是list1的第一个元素。这些行的作用是:

一步一步走:

*pnext = list1;

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

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

list2
|
V
o->o->o...

pnext = &list1->next;

这是棘手的部分,如前所述&amp;运算符的优先级较低。它也很难以图形方式显示,因为它实际上是在查看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

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

答案 1 :(得分:2)

pnext是指向Node 指针的指针。

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

*pnext = list1;

表示指向pnext的任何指针现在指向与list1相同的东西。


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

pnext = &(list1->next);

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


最后一行:

list1 = *pnext;

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

答案 2 :(得分:1)

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

*pnext = list1;

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

pnext = &list1->next;

此处->的优先级高于&。因此,它返回指针的地址(即Node *类型的地址)

list1 = *pnext;

这与第一个陈述正好相反。取消引用pnext会将Node*提供给list1


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

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

list1 = list1->next ;

但是,你有一个声明 -

 *pnext = list2;

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

答案 3 :(得分:0)

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