理解pointer to pointer

【中英字幕】【TED】【Linus Torvalds】The mind behind Linux

示例1

下边内容的来源

struct list {
  int item;
  struct list *next;
};
/* delete node containing i from list pointed to by lp */
struct list *lp, *prevlp;
for(lp = list; lp != NULL; lp = lp->next) {
  if(lp->item == i) {
    if(lp == list) {
      list = lp->next;
    } else {
	  prevlp->next = lp->next;
	}
	break;
  }
  prevlp = lp;
}
struct list **lpp;
for(lpp = &list; *lpp != NULL; lpp = &(*lpp)->next) {
  if((*lpp)->item == i) {
    *lpp = (*lpp)->next;
	break;
  }
}

That single line *lpp = (*lpp)->next; updates the correct pointer, to splice the node it refers to out of the list, regardless of whether the pointer being updated is the head pointer or one of the next pointers. (Of course, the payoff is not absolute, because the use of a pointer to a pointer to a struct list leads to an algorithm which might not be nearly as obvious at first glance.)

To illustrate the use of the pointer-to-pointer lpp graphically, here are two more figures illustrating the situation just before deleting node 1 (on the left) or node 2 (on the right).

注意 lpp 指向的位置!

在这里插入图片描述

In both cases, lpp points at a struct node pointer which points at the node to be deleted. In both cases, the pointer pointed to by lpp (that is, the pointer *lpp) is the pointer that needs to be updated. In both cases, the new pointer (the pointer that *lpp is to be updated to) is the next pointer of the node being deleted, which is always (*lpp)->next.

One other aspect of the code deserves mention. The expression (*lpp)->next describes the next pointer of the struct node which is pointed to by *lpp, that is, which is pointed to by the pointer which is pointed to by lpp. The expressionlpp = &(*lpp)->next sets lpp to point to the next field of the struct list pointed to by *lpp. In both cases, the parentheses around *lpp are needed because the precedence of * is lower than ->.

下面内容的来源,但是链接中的图画的并不是很准确,我在下边的图中做了调整

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

struct List{
  struct Node* head;
};

在这里插入图片描述
原本的程序代码:

void remove_list_node(List *list, Node *target) {
    Node *prev = NULL;
    Node *current = list->head;
    // Walk the list
    while (current != target) {
        prev = current;
        current = current->next;
    }
    // Remove the target by updating the head or the previous node.
    if (!prev)
        list->head = target->next;
    else
        prev->next = target->next;
}

有品位的程序代码:

void remove_list_node(List *list, Node *target) {
    // The "indirect" pointer points to the *address*
    // of the thing we'll update.
    Node **indirect = &list->head;
    // Walk the list, looking for the thing that 
    // points to the node we want to remove.
    while (*indirect != target)
        indirect = &(*indirect)->next;
    *indirect = target->next;
}

在这里插入图片描述
注意 indirect 指向的位置!
在这里插入图片描述

右侧的把自己的指针域的内容赋值给它左侧的指针域中。

在这里插入图片描述

示例2

在这里插入图片描述
上图的右侧代码段,在第 5 行 (含) 之前的記憶體示意:

在这里插入图片描述
上图的右侧代码段,第 6 行 ptrA 數值傳入 func 後的記憶體示意:
在这里插入图片描述
func 依據 函式呼叫篇 描述,將變數 p 的值指定為 &B

在这里插入图片描述
由上图可見,原本在 main 中的 ptrA 內含值沒有改變。這不是我們期望的結果,該如何克服呢?可透過「指標的指標」來改寫,写成左边代码段:

在左侧代码段,第 5 行 (含) 之前的記憶體示意:

在这里插入图片描述
第 6 行時,傳入 func 的參數是 &ptrA,也就是下圖中的 &ptrA(temp):

在这里插入图片描述
進入 func 執行後,在編譯器產生對應參數傳遞的程式碼中,會複製一份剛傳入的 &ptrA,產生一個自動變數 p,將 &ptrA 內的值存在其中,示意如下:

在这里插入图片描述
在 func 中把 p 指向到的值換成 &B:

在这里插入图片描述
經過上述「指標的指標」,*ptrA 的數值從 1 變成 2,而且 ptrA 指向的物件也改變了。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值