详解C语言中二级指针与链表的应用

 更新时间:2022年07月06日 14:05:38   作者:叶落秋白  
对于初学者而言,有很多地方肯定是费解的。比如函数的参数列表的多样化,动态分配内存空间函数malloc等,其实这些知识和指针联系紧密,尤其是二级指针,快跟随小编来学习一下吧

前言

这篇文章即将解决你看不懂或者不会写链表的基本操作的问题,对于初学者而言,有很多地方肯定是费解的。比如函数的参数列表的多样化,动态分配内存空间函数malloc等,其实这些知识和指针联系紧密,尤其是二级指针。那么开始好好的学习这篇文章吧!

二级指针讲解

简述:其实就是一个指针指向另一个指针的地址。

我们都知道指针指向地址,但是指针自身也是一个变量,当然也可以被二级指针所指向。

语法:形如 int x = 10; int *q = &x; int **p = & q;

那么这里的q指针指向x的地址,p指针指向指针q的地址,*q可以得到x的值,*p可以得到q指针本身,**p也可以得到x的值。

代码示例:

int main(void)
{
    int x = 10; 
    int* q = &x;
    int** p = &q;    
    printf("x 的地址为:    %d\n", &x);
    printf("q 指向的地址为:%d\n", q);
    printf("*p的值为:      %d\n", *p);   //p指向指针q的地址,那么*p是解引用操作,
                                          //就等于了q本身
    printf("x 的值为:     %d\n", x);
    printf("q 存取的值为: %d\n", *q);
    printf("**p的值为:    %d\n", **p);    //**p相当于解引用解了两次,第一次先得到q本身,
                                          //第二次得到q指向地址的值
    return 0;
}

运行结果:

链表的应用 

这里以带头结点的双链表为例

定义双链表的结构体

typedef int ElemType;//将整型数据重命名为int
typedef int Status;//整型重命名为Status
 
//双链表的数据结构定义
typedef struct DouNode {
    ElemType data;               //数据域
    struct DouNode* head;        //前驱指针
    struct DouNode* next;        //后继指针
}DousList, * LinkList;// 结点指针

代码解释:

利用typedef对数据类型进行重命名,只要在后面遇到的 ElemType和 Status都是整型就够了。双链表结构体包含三个部分:数据域、前驱指针、后继指针,与单链表的区别就是多了一个前驱指针。然后大括号结束部分也是重命名,此时DousList和DouNode效果一样,都是结构体名,然后LinkList是指向结点的指针。

具体使用:

LinkList L,L是一个指针,DousList *P,P也是一个指针,属于两种创建方式。

创建双链表

使用两种正确的创建链表形式和一种错误的形式,对比着记忆创建方法

传入一级指针

这种方式并不能成功创建

代码演示:

void CreateDouList(LinkList L, int n)
{
    LinkList  ptr;
    int i;
    L = (LinkList)malloc(sizeof(DousList));    //为头结点申请空间
    L->next = NULL;
    L->head = NULL;
    L->data = n;//L->data记录结点的个数
    ptr = L;
    for (i = 0; i < n; i++)
    {
        int value = 0;
        scanf("%d",&value);
        LinkList me = (LinkList)malloc(sizeof(DouNode));
        me->data = value;    //节点数据域
        me->next = NULL;
        me->head = NULL;
        ptr->next = me;     
        me->head = ptr;
        ptr = ptr->next;     //尾插法建表
    }
}

代码解析: 

这里的参数列表是 LinkList L 和 整型数据 n,L是传入的链表头结点指针,n是用来记录插入数据的个数的,在下面的for循环用做循环的次数。接下来使用malloc函数为L链表分配内存空间,malloc需要用指针来接收,左边的括号是分配的指针类型,右边的括号是分配的内存空间大小。分配空间完成之后初始化前驱和后继指针为空,数据域data记录数据的个数。ptr指针初始等于L指针,接下来进入n次循环,创建待插入结点指针me并进行分配内存空间和初始化,最后三行代码进行尾插法建立链表:

尾插法:

先让ptr的后继指针指向me,然后me的head指针指向ptr,这就相当于在链表头把me结点插入链表,然后ptr指向这个插入的新结点,这就保证了每次插入的结点都在上一个插入的结点之后。

但是这样真的在链表中插入数据了吗 ,来看看调试结果:

进入遍历的程序时,让创建的ptr指针指向L链表的后继,立马就出现了空指针异常,但是上面明明插入数据了,原因是什么呢? 很明显,这里的链表L并未完成插入数据。这是因为我们在创建链表的函数里传入的只是链表的指针L,那么在函数里这个指针只是一个副本,在这里给他增大内存空间并不会影响到实参链表,这和普通数据类型的值传递和地址传递的情况一致。

我们利用传入指针地址来解决这个问题,两个方法:指针的引用和二级指针

传入指针的引用

函数的实现部分完全不用修改,只要形参列表加上一个引用符"&"即可。

void CreateDouList(LinkList &L, int n);

查看调试结果:

同样的调试方法,传入指针的引用之后可以清晰的看到L的data等于5,也就是存了五个数据,然后对于的后继结点的值都和尾插的结果一致,最后一个结点的后继指针正好指向NULL,完全符合我们的设计的代码。

传入指针的引用之后,函数里链表的空间变化会导致实参里的链表空间变化,这样做才能使插入操作完成,将结点插入到链表内。

传入二级指针

这个和指针的引用原理一样,我主要分享给你们使用的形式

注意调用的时候实参要加“&”符,例:CreateDouList(&L,n);

void CreateDouList(LinkList *L, int n)
{
    LinkList  ptr;
    int i;
     *L = (LinkList)malloc(sizeof(DousList));    //为头结点申请空间
    (*L)->next = NULL;
    (*L)->head = NULL;
    (*L)->data = n;//L->data记录结点的个数
    ptr = (*L);
    printf("开始插入数据:\n");
    for (i = 0; i < n; i++)
    {
        int value = 0;
        scanf("%d",&value);
        LinkList me = (LinkList)malloc(sizeof(DouNode));
        me->data = value;    //节点数据域
        me->next = NULL;
        me->head = NULL;
        ptr->next = me;     
        me->head = ptr;
        ptr = ptr->next;     //尾插法建表
    }
}

这里形参列表的参数是 LinkList *L,和DousLIst **L效果一样,是一个二级指针。如果用到指向链表的指针就需要一次接引用操作,写成(*L)的形式。然后再去分配空间、进行初始化、赋值给链表指针ptr等操作,这样链表二级指针L的改变也会使实参的链表发生改变,可以查看调试结果。

调试结果:

以上就是详解C语言中二级指针与链表的应用的详细内容,更多关于C语言 二级指针 链表的资料请关注脚本之家其它相关文章!

相关文章

  • 利用C++实现最长公共子序列与最长公共子串

    利用C++实现最长公共子序列与最长公共子串

    这篇文章主要给大家介绍了如何利用C++实现最长公共子序列与最长公共子串,文章一开始就给大家简单的介绍了什么是子序列,子串应该比较好理解就不用多介绍了,人后通过算法及示例代码详细介绍了C++实现的方法,有需要的朋友们可以参考借鉴,下面来一起看看吧。
    2016-12-12
  • 基于Matlab实现有雪花飘落的圣诞树的绘制

    基于Matlab实现有雪花飘落的圣诞树的绘制

    圣诞节快到了(虽然还有十天),一起来用MATLAB画个简单圣诞树叭~代码几乎取消了全部的循环,因此至少需要17b之后的版本,仅存的循环用来让树旋转起来,让雪花飘落起来,让树顶上的星光摇曳起来~感兴趣的可以试一试
    2022-12-12
  • MFC中Radio Button的用法详解

    MFC中Radio Button的用法详解

    这篇文章主要介绍了MFC中Radio Button的用法,需要的朋友可以参考下
    2014-07-07
  • C++学习之虚函数表与多态详解

    C++学习之虚函数表与多态详解

    这篇文章主要为大家详细介绍了C++中虚函数表与多态的相关知识,文中的示例代码讲解详细,对我们学习C++有一定的帮助,感兴趣的小伙伴可以了解一下
    2023-03-03
  • 基于Matlab实现数字音频分析处理系统

    基于Matlab实现数字音频分析处理系统

    这篇文章主要为大家介绍了如何利用Matlab制作一个带GUI的数字音频分析与处理系统。文中的示例代码讲解详细,感兴趣的小伙伴可以学习一下
    2022-02-02
  • C++中gSOAP的使用详解

    C++中gSOAP的使用详解

    这篇文章主要介绍了C++中gSOAP的使用详解,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2021-11-11
  • C语言中的数据整除判断问题

    C语言中的数据整除判断问题

    这篇文章主要介绍了C语言中的数据整除判断问题,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2022-11-11
  • C/C++ QT实现解析JSON文件的示例代码

    C/C++ QT实现解析JSON文件的示例代码

    JSON是一种轻量级的数据交换格式,它是基于ECMAScript的一个子集,使用完全独立于编程语言的文本格式来存储和表示数据。这篇文章主要介绍了QT实现解析JSON文件的示例代码,需要的可以参考一下
    2022-01-01
  • C 语言简单加减乘除运算

    C 语言简单加减乘除运算

    本篇文章主要介绍了C语言的基本运算方法,这里对加法,减法,乘法,除法,求余数,做了详细讲解,有需要的朋友可以参考下
    2016-07-07
  • 详解C++实现线程安全的单例模式

    详解C++实现线程安全的单例模式

    这篇文章主要介绍了C++实现线程安全的单例模式,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2019-03-03

最新评论