为什么链表的插入删除要用二级指针?

25 篇文章 0 订阅

#include <iostream>
using namespace std;

typedef struct listnode
{
    int date;
    struct listnode *next;
}listnode;


void Init(listnode **head)  //链表初始化
{
    listnode *p=new listnode;
    p->date=0;
    p->next=NULL;
    *head=p;
    printf("初始化带头接点的链表\n");
}

void Insert(listnode **head,int date)  //插入
{
    if (!head)
    {
        return;
    }
    listnode *p=new listnode;
    p->date=date;
    p->next=NULL;
    listnode *temp=*head;
    while(temp->next)
    {
        temp=temp->next;
    }
    temp->next=p;
}


void print(listnode *head)  //打印
{
    listnode *temp=head;
    while(temp->next)
    {
        cout<<temp->next->date<<" ";
        temp=temp->next;
    }
    cout<<endl;
}

void Reserve(listnode *head)   //链表逆序
{
    listnode *p1,*p2,*p3;
    if (head->next==NULL)
    {
        printf("链表为空\n");
        return;
    }
    p1=head,p2=p1->next;  //p1指向头结点 p2指向头结点下一个结点即第一结点
    while(p2)
    {
        p3=p2->next;  //p3刚开始是第一个结点的后继,如果null,则跳出循环
        p2->next=p1;  //改变结点的方向
        p1=p2;        //把p1移动到p2
        p2=p3;        //p2移动到p3
    }
    p2=new listnode;  //循环跳出后p2指向null,要把p2重新指向一个空结点,作为新的头结点
    p2->next=p1;       //头节点的后继指向原始链表的最后一个结点
    head->next->next=NULL;//原始链表的头结点后的第一个结点作为新的链表的末尾
    head=p2;        //头指针指向反转后的头结点
    print(head);  //打印出9 8 7 6 5 4 3 2 1 0 
}

int main()
{
    listnode *l;
    Init(&l);//为什么要对l取地址?因为我们需要用二级指针
    for (int i = 0; i < 10; ++i)
    {
        Insert(&l,i); //
    }
    print(l);  //打印出0 1 2 4 5 6 7 8 9
    Reserve(l);//链表逆序
    print(l);//打印出 0
    return 0;
}

//为什么我么要用二级指针?
//因为一级指针我们只能修改指针指向的内容,不能修改指针自身的值,当我们没有给一级指针分配内存时,直接传递指针到
//函数内,只是该指针的拷贝,函数操作完只能在本函数内实现功能如上面Reserve()函数里的print()可以打印出逆序的效果,但是
//main函数里调用完Reserve(),在调用print函数却打印不出逆序的效果,应为l并没有指向修改过的链表

详细点理解二级指针:

 #include <iostream>    
#include <string.h>    
using namespace std;    

void fun1(char* str)    
{    
    str = new char[20];    
    strcpy (str, "test string");    
}    

void fun2(char** str)    
{    
    *str = new char[20];    
    strcpy (*str, "test string");    
}    

int main()    
{    
    char* s = NULL;        
    cout << "call function fun1" << endl;    
    fun1 (s);    
    if (!s)    
        cout << "s is null!" << endl;    
    else    
        cout << s << endl;    

    cout << "call function fun2" << endl;    
    fun2 (&s);    
    if (!s)    
        cout << "s is null!" << endl;    
    else    
        cout << s << endl;    
    return 0;    
}  

结果: 
这里写图片描述

分析:

在fun1中,当调用str = new char[20]时,str和s已经没什么关系了,相当于在fun1中复制了一个指针,这个指针指向的空间存储了字符串“test string”,但s仍指针NULL。当调用fun2时,因为是二级指针,s指向str,这里*str = new char[20],*str就是s,所以给*str分配空间就是给s分配空间。这样解释应该就很清楚了。

画图为例:

fun1执行时 
这里写图片描述 
fun2执行时 
这里写图片描述 
如图所示,在fun1种str是s的拷贝,给str分配空间跟s没有关系,在fun2种str是二级指针,指向s,能够通过控制*str从而给s分配空间。

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

半岛铁盒.

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

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

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

打赏作者

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

抵扣说明:

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

余额充值