前言
最近做毕设时发现了一个问题,无头链表并不能通过结构体指针进行函数传参插入数据,这种方法只适用于附带头结点的链表,
错误示例
假设结构体为:
typedef struct link
{
int data;
struct link *next;
}Listnode
插入数据的函数为:
//错误示例
void fun(Listnode *head,int n)
{
Listnode *cur=head;
Listnode *tmp=(Listnode*)malloc(sizeof(Listnode));
scanf("%d",&tmp->data);
if(cur==NULL){
cur=tmp;
}
else{
while(cur!=NULL)
{
cur=cur->next;
}
cur->next=NULL;
}
}
主函数为:
//无头节点的链表创建
Listnode *head;
head=(Listnode*)malloc(sizeof(Listnode));
fun(head,4);
这样是行不通的,这种定义结构体指针传参的方法只可用于附带头结点的链表,对于无头节点链表不适用
附带头结点的链表创建是这样的:
Listnode *head;
head=(Listnode*)malloc(sizeof(Listnode));
head->next=NULL;
问题分析
经过一下午的冥想以及测试才明白,这种定义结构体指针函数数传参的方法,只适用于附带头结点的链表,因为认真学过C语言的都知道,函数传参的参数只是实参的拷贝(叫做形参),形参在函数执行完毕后便从栈内销毁,无法改变外部实参
如果想要改变外部形参,我们可以利用指针传递参数地址,例如:
void fun1(int *a,int *b)
{
*a=*a+1;
*b=*b+1;
}
fun(&a,&b);
由此可得,在上文中定义的函数void fun(Listnode *head,int n)只是传递的结构体指针头结点的形参,在函数里进行操作的只是头节点的一份拷贝,如果函数要对头结点数据域进行改变,并不会对函数外的链表头结点进行改变.
但是假如我们传入的是附带头结点的链表,那么就不需要对头结点进行赋值操作,只需对头结点指向的下面的节点进行操作
传入的头节点虽然是形参,无论是形参还是实参,它们next指针指向的空间都是相同的,但对于无头结点的链表我们就需要传入指针结构体的指针,将指针结构体的地址传入函数,这样才能真正改变这个指针结构体
正确代码
该代码通过定义二级指针,传入了指针结构体的地址,可对头节点进行更改
void add(Listnode** head_ptr)
{
float sr,so=0.01;
int a;
Ctf* new_ctf = (Ctf*) malloc(sizeof(Ctf));
new_ctf->next = NULL;
scanf("%d", &new_ctf->data);
if (*head_ptr == NULL)
{
*head_ptr = new_ctf;
}
else
{
Ctf *current = *head_ptr;
while (current->next != NULL)
{
current = current->next;
}
current->next = new_ctf;
}
}
总结
印象中数构老师好像顺便讲过,后悔没仔细听