修改单链表时传入二级指针详解

修改单链表时传入二级指针详解

我们先来看一个例子:

1.通过调用函数改变a的值:

int *p = &a;
notice: p的值,*p,&p注意区分
p的值:就是变量a的地址:0x11
*p: 就是变量a的值:1
&p:就是p的地址:ox22

在这里插入图片描述
p代表的是a的地址,即:&a。如果要修改a的值,要传入p或者&a,即:func(p )或者func(&a)。
p 是一个指向 int 类型的指针(int*),&a也是一个指向 int 类型的指针(int*)
func(int * pa) 需要一个指向整数的指针 (int*)。函数 func 接受一个指向整数的指针 pa,并将 pa指向的值修改为2。
在这里插入图片描述

2.1.通过调用函数改变p的值:

p的值:就是变量a的地址:0x11
&p:就是p的地址:ox22

调用函数void fun(int **pa),将指针的地址&p传入,此时pa=&p;pa的值也就是p的地址(&p):0x22,而*pa就是p的值:ox11,我们需要修改p的值,也就是p的指向。
在这里插入图片描述

&p 的含义是取指针变量 p 的地址。因为 p 是一个指向 int 类型的指针(int*),所以 &p 的类型是 int**,即指向 int 指针的指针。

函数 func 的执行
当 func(&p) 被调用时,以下操作发生:

pa在函数 func 中被初始化为 p 的地址。
*pa解引用 pa,即 *pa 现在是指向 a 的指针 p。
*pa= &c 将 p 修改为指向 c 的地址。

所以在 func(&p) 调用之后,p 不再指向 a,而是指向 c。
在这里插入图片描述

如果理解了上面的例子那么就知道了为什么修改单链表时要传入二级指针

一、使用 struct Node** 情况

当修改原始链表的头指针时,需要使用二重指针 struct Node** head_ref。这种情况通常发生在以下场景:

1.在链表头部插入节点:因为插入新的头节点后,原来的头指针需要指向新的头节点。
2.删除链表中的某个节点:如果删除的是头节点,你需要修改头指针。

示例:在链表头部插入节点

void insertAtHead(struct Node** head_ref, int new_data) {
    struct Node* new_node = (struct Node*)malloc(sizeof(struct Node));
    new_node->data = new_data;
    new_node->next = (*head_ref);
    (*head_ref) = new_node;
}

示例:删除链表中的某个节点

void deleteNode(struct Node** head_ref, int key) {
    struct Node* temp = *head_ref, *prev;

    if (temp != NULL && temp->data == key) {
        *head_ref = temp->next;  // Changed head
        free(temp);  // free old head
        return;
    }

    while (temp != NULL && temp->data != key) {
        prev = temp;
        temp = temp->next;
    }

    if (temp == NULL) return;

    prev->next = temp->next;
    free(temp);
}

二、使用 struct Node* 情况

当不需要修改原始链表的头指针,只是遍历链表或修改链表中其他节点时,可以使用单指针 struct Node* head_ref。这种情况通常发生在以下场景:

1.在链表中间或尾部插入节点:你只需要修改特定节点的 next 指针,不需要修改头指针。
2.遍历链表:只需要读取头指针的值,而不需要修改它。

示例:在链表中间插入节点

void insertAfter(struct Node* prev_node, int new_data) {
    if (prev_node == NULL) {
        printf("The given previous node cannot be NULL");
        return;
    }
    struct Node* new_node = (struct Node*)malloc(sizeof(struct Node));
    new_node->data = new_data;
    new_node->next = prev_node->next;
    prev_node->next = new_node;
}

示例:在链表尾部插入节点

void insertAtEnd(struct Node* head_ref, int new_data) {
    struct Node* new_node = (struct Node*)malloc(sizeof(struct Node));
    struct Node* last = head_ref;
    new_node->data = new_data;
    new_node->next = NULL;

    if (head_ref == NULL) {
        head_ref = new_node;
        return;
    }

    while (last->next != NULL) {
        last = last->next;
    }

    last->next = new_node;
}

注意,如果链表为空,在尾部插入节点时,单指针版本可能会出现问题,因为它不能修改原始的头指针。可以改为二重指针以处理这种情况。

改进后的在链表尾部插入节点的函数:

void insertAtEnd(struct Node** head_ref, int new_data) {
    struct Node* new_node = (struct Node*)malloc(sizeof(struct Node));
    struct Node* last = *head_ref;
    new_node->data = new_data;
    new_node->next = NULL;

    if (*head_ref == NULL) {
        *head_ref = new_node;
        return;
    }

    while (last->next != NULL) {
        last = last->next;
    }

    last->next = new_node;
}

改变链表的头指针就传二级指针,即:指向指针的指针。改变头指针不能传一级指针因为传送的过程就是拷贝的过程,相当于将头指针复制了一份,形参的改变不会影响实参,因此要改变链表的头指针需要传送二级指针。
总结:
使用 struct Node**:当需要修改原始链表的头指针时。
使用 struct Node*:当不需要修改原始链表的头指针,仅进行遍历或修改其他节点时。

  • 9
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Comedy_宁

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值