简体   繁体   English

C链表指针理解

[英]C Linked List pointer understanding

I'm trying to understand how C linked list pointer works.我试图了解 C 链表指针的工作原理。 I understand that a pointer to a variable is a "link" to an address memory, and that a pointer to a pointer is, sometimes, a reference to a pointer itself.我知道指向变量的指针是指向地址存储器的“链接”,而指向指针的指针有时是对指针本身的引用。

What concerns me is how could, for example, a node reference modify the original list value, but not the list itself.我担心的是,例如,节点引用如何修改原始列表值,而不是列表本身。

I'll explain myself better:我会更好地解释自己:

void insertNode(struct node** head, int value) {

    struct node* new = malloc(sizeof(struct node*));
    struct node* ref = (*head); //this is a reference. -> same address.

    //base case 
    if((*head) == NULL) {
        //do things
    } else { // not null
        while(ref->next != null) {
            ref = ref->next; //THIS: how can this not modify the head itself?
        }

        //null spot found, set up node
        new->value = 10; //some int here
        new->next = NULL;

        ref->next = new; //Instead, how can this modify the head? and why?
    }
}

here's a little snippets of code, and my question is: Yes, i'm holding a reference to head through ref .这是一些代码片段,我的问题是:是的,我正在持有一个参考来通过ref But why但为什么

ref = ref->next;

only modify ref itself, while只修改 ref 本身,而

ref->next = new

modify also the head?还修改头?

through GDB i saw that both, at the beginning, share the same address memory, but ref only modify the referenced list on the new insert.通过 GDB,我看到两者在开始时共享相同的地址内存,但 ref 仅修改新插入的引用列表。

Can someone explain it?有人可以解释一下吗?

ref is just a pointer; ref只是一个指针; modifying ref will not modify what is pointed by ref .修改ref不会修改ref指向的内容。

The while loop is actually just looking for the last element of the list. while循环实际上只是在寻找列表的最后一个元素。 After the while loop , ref will simply point to the last element of the list.while循环之后, ref将简单地指向列表的最后一个元素。

First "mystery" line:第一个“神秘”线:

ref = ref->next; //THIS: how can this not modify the head itself?

Here we just read ref->next , so the head cannot be modified.这里我们只读取了ref->next ,所以 head 不能修改。

Second "mystery" line:第二个“神秘”线:

ref->next = new; //Instead, how can this modify the head? and why?

Here we modify what is pointed by ref .这里我们修改了ref指向的内容。 At this line ref points either to the last element of the list, or it points the head (which is also the last element of the list if there is only one element in the list, or which is the newly created head (to be done in //do things ) if the list was empty.在这一行, ref要么指向列表的最后一个元素,要么指向头部(如果列表中只有一个元素,它也是列表的最后一个元素,或者是新创建的头部(待完成) in //do things ) 如果列表为空。

Maybe some pictures will help.也许一些图片会有所帮助。

Before calling insertNode , you have a sequence of nodes linked like so:在调用insertNode之前,您有一个链接的节点序列,如下所示:

+-------+------+      +-------+------+      +-------+------+      
| value | next | ---> | value | next | ---> | value | next | ---|||
+-------+------+      +-------+------+      +-------+------+      

You have a pointer (call it h ) that points to the first element of the list:您有一个指向列表第一个元素的指针(称为h ):

+---+
| h |
+---+
  |
  V
+-------+------+      +-------+------+      +-------+------+      
| value | next | ---> | value | next | ---> | value | next | ---|||
+-------+------+      +-------+------+      +-------+------+      

When you call insertNode , you pass a pointer to h in as a parameter, which we call head :当你调用insertNode ,你传递一个指向h in的指针作为参数,我们称之为head

+------+
| head |
+------+
  |
  V
+---+
| h |
+---+
  |
  V
+-------+------+      +-------+------+      +-------+------+      
| value | next | ---> | value | next | ---> | value | next | ---|||
+-------+------+      +-------+------+      +-------+------+      

You create a pointer variable named ref that takes the value of *head ( h );您创建了一个名为ref的指针变量,该变量采用*head ( h ) 的值; IOW, ref winds up pointing to the first element of the list: IOW, ref最终指向列表的第一个元素:

+------+ +-----+
| head | | ref |
+------+ +-----+
  |        |       
  V        |
+---+      |
| h |      |
+---+      |
  |   +----+
  V   V
+-------+------+      +-------+------+      +-------+------+      
| value | next | ---> | value | next | ---> | value | next | ---|||
+-------+------+      +-------+------+      +-------+------+      

Then you create another node on the heap, and assign that pointer to a local variable named new :然后在堆上创建另一个节点,并将该指针分配给名为new的局部变量:

+------+ +-----+ +-----+      +-------+------+
| head | | ref | | new | ---> | value | next |
+------+ +-----+ +-----+      +-------+------+
  |        |       
  V        |       
+---+      |       
| h |      |    
+---+      |     
  |   +----+     
  V   V
+-------+------+      +-------+------+      +-------+------+      
| value | next | ---> | value | next | ---> | value | next | ---|||
+-------+------+      +-------+------+      +-------+------+      

So, the thing to notice is that while ref and *head ( h ) have the same value (the address of the first node in the list), they are different objects.因此,需要注意的是,虽然ref*head ( h ) 具有相同的(列表中第一个节点的地址),但它们是不同的对象。 Thus, anything that changes the value of ref does not affect either head or h .因此,任何改变ref值的事情都不会影响headh

So, if we execute this loop所以,如果我们执行这个循环

while(ref->next != null) {
    ref = ref->next; 

the result of the first iteration is第一次迭代的结果是

+------+ +-----+ +-----+      +-------+------+
| head | | ref | | new | ---> | value | next |
+------+ +-----+ +-----+      +-------+------+
  |        |       
  V        |       
+---+      |       
| h |      |    
+---+      |     
  |        +------------+     
  V                     V
+-------+------+      +-------+------+      +-------+------+      
| value | next | ---> | value | next | ---> | value | next | ---|||
+-------+------+      +-------+------+      +-------+------+      

After another iteration we get经过另一次迭代,我们得到

+------+ +-----+ +-----+      +-------+------+
| head | | ref | | new | ---> | value | next |
+------+ +-----+ +-----+      +-------+------+
  |        |       
  V        |       
+---+      |       
| h |      |    
+---+      |     
  |        +----------------------------------+     
  V                                           V
+-------+------+      +-------+------+      +-------+------+      
| value | next | ---> | value | next | ---> | value | next | ---|||
+-------+------+      +-------+------+      +-------+------+      

At this point, ref->next is NULL , so the loop exits.此时, ref->nextNULL ,因此循环退出。

We then assign values to new->value and new->next , such that new->next is NULL :然后我们将值分配给new->valuenew->next ,这样new->nextNULL

+------+ +-----+ +-----+      +-------+------+
| head | | ref | | new | ---> | value | next | ---|||
+------+ +-----+ +-----+      +-------+------+
  |        |       
  V        |       
+---+      |       
| h |      |    
+---+      |     
  |        +----------------------------------+     
  V                                           V
+-------+------+      +-------+------+      +-------+------+      
| value | next | ---> | value | next | ---> | value | next | ---|||
+-------+------+      +-------+------+      +-------+------+      

Finally, we set ref->next to the value of new , thus adding the node new points to to the end of the list:最后,我们将ref->next设置为new的值,从而将节点new指向列表的末尾:

+------+ +-----+ +-----+      +-------+------+
| head | | ref | | new | ---> | value | next | ---|||
+------+ +-----+ +-----+      +-------+------+               
  |        |                    ^                                
  V        |                    |                               
+---+      |                    +-------------------------------+
| h |      |                                                    |
+---+      |                                                    |
  |        +----------------------------------+                 |
  V                                           V                 |
+-------+------+      +-------+------+      +-------+------+    |  
| value | next | ---> | value | next | ---> | value | next | ---+
+-------+------+      +-------+------+      +-------+------+      

Note that ref->next isn't pointing to the variable new , it's pointing to the thing that new points to.需要注意的是ref->next没有指向new ,它所指向的东西, new点。

So, that's why updating ref does not affect head (or *head ( h )).所以,这就是为什么更新ref不会影响head (或*head ( h ))。 The base case, where the list is empty, will end up writing to *head ( h ), setting it to point to a new node allocated from the heap.列表为空的基本情况最终写入*head ( h ),将其设置为指向从堆分配的新节点。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM