提示:我们知道C语言中,函数的参数表,总体上分为形参和实参,形参即:将函数1中变量A的值复制一份给到函数2的变量B中,函数2区域内对变量B修改不会改变函数1中的变量A,实参则是:将函数1中变量A的地址复制到函数2的指针变量B中,在函数2范围内对B所指地址的值修改,函数1中的变量A也会被改变。
但我出现的问题却复杂一点,涉及到结构体、指针、单链表及其尾插入节点;
所以让我把代码要实现的过程及其目的简明一下:
- 主函数中创建List * 类型的L1,将其作为单链表的头结点
- 将L1传递给函数operator,该函数作为对L1进行各种操作的汇总函数;
- 在函数operator中创建List * 类型的temp(作为链表L1的尾部指针),以及要插入链表的int型item;
- 把L1赋值给temp,并将输入数值给item;
- 将temp以及item传入sert函数中,执行表尾插入;
- 在sert函数中新建List * 类型的p(不同函数之间的变量名可以重复),并将item赋值给p->data、p->next赋值为NULL;
- 随后我们要让temp后面链接上p,而temp则要等于p(使temp一直指向链表L1的尾部);
问题描述:
问题出在上述过程7中,在代码中我令temp->next=p(链表尾部链接上p),再使temp=p(temp指向新的尾部p);
但是执行完sert函数后,返回operator函数,temp的值没有等于p的值(sert函数中的List类型节点指针);
问题代码如下:
struct List {
int data;
struct List* next;
};
typedef struct List* list;
void operator(list L1);
void sert(list p, int item);
int main()
{
list L1= (list)malloc(sizeof(struct List));
operator(L1);
return 0;
}
void operator(list L1)//对链表L1操作的函数
{
list temp = L1;
int item;
scanf("%d", &item);
sert(temp, item);
printf("%d", temp->data);
}
void sert(list temp, int item)//插入函数,将item插入尾结点节点p后,并将p指向item所在节点
{
list p = (list)malloc(sizeof(struct List));
p->data = item;
p->next = NULL;
temp->next = p;
temp = p;//问题出现部分
}
原因分析:
为什么temp的值在执行sert函数后没有得到改变,在sert函数中我明明设置传入的temp是指针类型的,属于“实参”啊?
经过我的编译器的调试,我发现虽然operator函数中的temp没有改变,但发现temp->next->data的值是我要插入表尾的节点的item值;
所以我确定和sert函数的参数表的传值以及传地址有关;
具体原因:
因为sert函数的参数struct List*temp传入的是operator函数中temp的副本,其作用区域只在sert函数范围内,所以operator函数中的temp不被改变,而节点p(sert函数)能链接上L1尾部,是因为temp的值是地址,而地址存放在内存中的堆区,只能被free()掉,在sert函数中(temp->next = p;)实际含义是:通过指针变量temp访问其中地址的next,并将指针变量p的值(地址)赋值给next;而(temp = p;)实际含义是:将sert函数的指针变量p的值赋值给临时指针变量temp(于是一离开sert函数临时指针变量temp就给释放掉了,自然不会影响operator函数中的temp)。
解决方案:
修改后的代码:
void operator(list L1)
{
list temp = L1;
int item;
scanf("%d", &item);
sert(&temp, item);//传入temp的地址
printf("%d", temp->data);
}
void sert(list *p, int item)//将list p,改为list *p
{
list temp = (list)malloc(sizeof(struct List));
temp->data = item;
temp->next = NULL;
(*p)->next = temp;//p表示operator函数中temp指针的地址
*p = temp;//*p表示间接访问operator函数中temp指针,并代表其
}
将sert函数参数表中的struct List *p改为struct List **p,也就是将指针类型改为指向指针的类型;(其它改变如上图所示)
sert函数原本只是对指针的值进行操作,作为传递后指针也属于形参,不会改变原来operator函数指针变量,所以要传入存放指针变量的地址(指针的指针),然后改变这个地址中的值,才会改变operator函数指针变量的值。
指导文章:
C语言的内存分区与malloc函数的用法
如何理解指针的指针?什么情况下使用?
这两篇文章在解决该问题的思路上给了我很多的帮助。