在数据结构的学习过程当中,有时候会遇到一些一时没法理解的问题,深究起来倒是语言的底层的语法机制所限制.
就例如在链表的构建中,链表的初始化和销毁为什么须要使用一个二级指针,而不是只须要传递一个指针就能够了,其问题的关键就在于c语言的参数传递的方式是值传递
那么,这篇文章就来聊一聊在链表的初始化中一级指针的传递和二级指针的区别.数据结构
一级指针实例:函数
#include <stdio.h> #include <stdlib.h> #define MaxSize 100 typedef int ElemType; typedef struct SingleNode{ ElemType data; struct SingleNode *next; }SingleNodeList,*Linklist; void LinkedListInit(SingleNodeList *head){//用一个指针head接收传入的地址 Linklist p; if((head=(SingleNodeList *)malloc(sizeof(SingleNodeList)))==NULL){ exit(1);//给head分配内存,改变了head指针指向的地址(注意这里的head只是LinkedListInit的head,不是主函数那个) } head->next=NULL; }//这个函数结束后head被销毁了,主函数的那个head不变; int LinkedList_PushFront(SingleNodeList *head,ElemType x){//2单链表头插入 SingleNodeList *q; if((q=(struct SingleNode *)malloc(sizeof (struct SingleNode)))==NULL){ exit(1); } q->data=x; q->next=head->next;//头节点的数据域与指针域赋值 head->next=q;//头节点加入链表 return 1; } int LinkedList_PopFront(SingleNodeList *head,ElemType *x){//3单链表头删除 SingleNodeList *p=head,*q; if(p->next==NULL){ printf("There is no data in the Linkedlist to delete.\n"); *x = -12345;//未成功删除则在x指向单元赋特定值 return 0; } p=head->next; q=p; head->next=p->next; *x=q->data; free(q); return *x;//请填写多行代码 } int LinkedListGet_current(SingleNodeList *p,ElemType *x){//4取当前指针指数据 *x =p->data; return 1; } int LinkedListUpdata_current(SingleNodeList *p,ElemType x){//5修改当前指针数据 p->data=x; return 1; } int LinkedListShow(SingleNodeList *head){//6打印单链表 SingleNodeList *p=head; if(p->next==NULL){ printf("There is no data in the Linkedlist to print.\n"); return 0; } while(p->next!=NULL){ printf("%d ",p->next->data); p=p->next; } printf("\n"); return 1; } void LinkedListDestroy(SingleNodeList **head){//7释放链表 SingleNodeList *p=*head,*q; while(p!=NULL){ q=p; p=p->next; free(q); } *head=NULL; } int LinkedListLength(SingleNodeList *head){//8求单链表长度 SingleNodeList *p=head; int size=0; while(p->next!=NULL){ size++; p=p->next; } return size; } int main(){ SingleNodeList *head,*p; ElemType i,x; int switch_num; scanf("%d",&switch_num); switch(switch_num){ case 1: LinkedListInit(head); //传入指针变量head的地址 LinkedList_PushFront(head,1); LinkedList_PushFront(head,3); LinkedList_PushFront(head,2); LinkedListShow(head); break; } LinkedListDestroy(&head); return 0; }
传递流程如图所示学习
从图中能够看出,main函数中咱们定义了 一个指针head,假设它的地址是0x10010,可是还没给它初始化,也就是说它存的地址是随机的,咱们也假设它存的是0x12306spa
在main函数中,咱们把head这个指针做为参数传递进去初始化函数(值传递),按照值传递的原则,初始化函数首先开辟了一个*head指针,它的地址是0x12345(与main函数的0x10010不同),可是它的内容是是和主函数的head是同样的,都是指向0x12306这个地址指针
在初始化的过程当中,咱们用malloc函数对初始化函数内的head指针分配内存空间,也就是改变了head指针的值,由未初始化的随机值0x12306改变成了0x10086code
也就是说,因为这个head是做用在初始化函数内的,mallo做用的不是主函数的head,初始化函数结束后,这个head指针就被销毁掉了,主函数中的head不受影响,初始化失败,而分配了内存不能使用,形成了内存泄漏对象
二级指针传递实例:blog
#include <stdio.h> #include <stdlib.h> #define MaxSize 100 typedef int ElemType; typedef struct SingleNode{ ElemType data; struct SingleNode *next; }SingleNodeList,*Linklist; void LinkedListInit(SingleNodeList **head){//1初始化有头节点的单链表 Linklist p; if((*head=(SingleNodeList *)malloc(sizeof(SingleNodeList)))==NULL){ exit(1); } (*head)->next=NULL; } int LinkedList_PushFront(SingleNodeList *head,ElemType x){//2单链表头插入 SingleNodeList *q; if((q=(struct SingleNode *)malloc(sizeof (struct SingleNode)))==NULL){ exit(1); } q->data=x; q->next=head->next;//头节点的数据域与指针域赋值 head->next=q;//头节点加入链表 return 1; } int LinkedList_PopFront(SingleNodeList *head,ElemType *x){//3单链表头删除 SingleNodeList *p=head,*q; if(p->next==NULL){ printf("There is no data in the Linkedlist to delete.\n"); *x = -12345;//未成功删除则在x指向单元赋特定值 return 0; } p=head->next; q=p; head->next=p->next; *x=q->data; free(q); return *x;//请填写多行代码 } int LinkedListGet_current(SingleNodeList *p,ElemType *x){//4取当前指针指数据 *x =p->data; return 1; } int LinkedListUpdata_current(SingleNodeList *p,ElemType x){//5修改当前指针数据 p->data=x; return 1; } int LinkedListShow(SingleNodeList *head){//6打印单链表 SingleNodeList *p=head; if(p->next==NULL){ printf("There is no data in the Linkedlist to print.\n"); return 0; } while(p->next!=NULL){ printf("%d ",p->next->data); p=p->next; } printf("\n"); return 1; } void LinkedListDestroy(SingleNodeList **head){//7释放链表 SingleNodeList *p=*head,*q; while(p!=NULL){ q=p; p=p->next; free(q); } *head=NULL; } int LinkedListLength(SingleNodeList *head){//8求单链表长度 SingleNodeList *p=head; int size=0; while(p->next!=NULL){ size++; p=p->next; } return size; } int main(){ SingleNodeList *head,*p; ElemType i,x; int switch_num; scanf("%d",&switch_num); switch(switch_num){ case 1: LinkedListInit(&head); LinkedList_PushFront(head,1); LinkedList_PushFront(head,3); LinkedList_PushFront(head,2); LinkedListShow(head); break; } LinkedListDestroy(&head); return 0; }
如图所示,若是传递的是二级指针就不同了,首先咱们在main函数中的操做是和一级指针差很少,只是传递的时候传递的不是一个指针变量,而是这个指针变量的地址(地址传递),可是在初始化函数中咱们接收这个地址的是用一个二级指针,也就是用一个head指针指向传递主函数那个head指针的地址,从而来进行对初始化函数中head指针内容的改变去影响到主函数中的head的指向图片
如图所示,咱们在mian函数中传递了一个head的地址,也就是0x10010,这个地址是指向0x12306指针的地址
在初始化函数中,咱们用一个另外的head指针接受这块地址,也就是个二级指针,第一级是0x10010,指向0x12305),第二级是0x12345,指向0x10010ip
在初始化函数中,malloc函数操做的对象是head指针内的内容,也就是0x10010这块指针(主函数中的head指针),这样成功改变了主函数中的head指向的地址,而在销毁初始化函数的head指针的时候,主函数的的head指针不受影响