关于C语言实现单链表中的指针问题

导言

笔者最近学习严薇敏教授的《数据结构》,同时也参考B站上王道考研的数据结构视频,发现单链表传入函数参数这一方面教材与视频,与网络上的一些实现写法各有不同,有点迷惑。经过查了一些资料以后,终于拨云见日。写下这篇文章,希望为后来的同学们有所帮助。水平不足,还请多多指正!

指针

指针是指向内存中一定大小内存区域的变量。定义一个指针如:

int *p;
 

但这样只是声明了一个指针变量p,p指向哪里我们不清楚,需要指定这个指针变量指向的内存区域

int x = 2;
int *p = NULL; //初始化,避免p是野指针
p = &x;        //让p指向x

 

指针变量实际上存放的是目标区域的内存地址。

我们要注意区分*p = 和 p =这两种情况

*p = 2;       //让p指向的内存区域中的值变成2
p = &a;       //让指针p指向内存中的区域a,也就是让p的值为a的地址

 

注意:指针变量的值是地址,取内容符号与指针变量搭配,改变的不是指针的值,而是指针指向的内存区域的值

函数中参数传递问题

C语言中,参数传递有两种,一个是值传递,一个是地址传递。值传递情况下,C程序只是获得了值,也就是变量的拷贝,在C程序内对变量的任何操作都不会引起内存中原本的变量的变化。想要改变传递进来的参数,就需要进行地址传递。

void test(int *a){
    *a = 2; 
}
int main(){
    int x = 0;
    test(&a);         //传入变量的地址
    printf("%d\n",x); //输出结果为2
    return 0;
}
 

链表中指针的使用(带头结点为例)

我们在单链表中,用到了指针来实现单链表

typedef struct LNode{
    int data;
    struct LNode *next;
}LNode, *LinkList;
​
LinkList L;
 

怎么理解这个L?

我们要知道,LinkList本质上是一个指针,它指向的是内存中大小为的LNode类型区域。那么,L这个指针,存储的应该是目标区域的地址。

一开始我们只是声明了这么一个指针L,还没有将它指向一片内存区域。为了将它指向一片内存区域,我们需要使用malloc函数来分配内存空间

L = (LNode *)malloc(sizeof(LNode));  //注意要用(LNode *)或者(LinkList)
//来对malloc函数返回的地址进行类型转换
if (L == NULL) return false;

 

这个时候我们就要注意,这个对单链表进行初始化的函数initList,接收的参数应该是怎么样的?

经过验证,我们得知,如果直接传入指针L,那么我们将不能更改内存中L的指向区域。为了改变指针L,我们有两种方案可以选择:

  1. 通过return语句来返回地址

    LinkList initList(LinkList L){
        L = (LinkList)malloc(sizeof(LNode));
        if (L == NULL) return NULL;
        else{
            L->next = NULL; //设置L指向的区域(头结点)的next域的值
            return L;
        }
    }
    ​
    int main(){
        LinkList L;
        L = initList(L);
        return 0;
    }
     
  2. 使用二级指针,来对一级指针L的值(指向的内存区域是哪一片)进行改变。

    int initList(LinkList *L){ //此处的L是二级指针,指向的是:指向头结点的头指针
        *L = (LinkList)malloc(sizeof(LNode));  
    //*L就是二级指针的内容,也就是一级指针存储的值,也就是目标区域地址。所以,可以直接把*L当头指针用 if (*L == NULL) return 0; else{ (*L)->next = NULL; return 1; } } ​ int main(){ LinkList L; initList(&L); return 0; }
     

必须使用二级指针的操作

根据单链表的基本操作,我们总结一下必须要用二级指针的情况,实际上也就是对单链表内容进行更改的情况:

  • initList 链表初始化

  • listInsert 向指定位置插入

  • listDelete 删除指定位置元素

  • destoryList 链表销毁

  • getElem 获取具体某个元素的结点(这个看情况,如果只是找到链表中第几个元素的值,那么就没必要用二级指针)



posted @ 2020-09-20 20:51  penguin1022  阅读(1023)  评论(0编辑  收藏  举报