(链表.2)关于链表函数的参数是二级指针这件事

某一天,我在学习链表函数的时候,学习浙大老师翁恺的课看到有个问题很疑惑,把它简化了下

趁着有点感觉,赶紧把它写成blog,免得日后忘了

#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<stdlib.h>
typedef struct node {
	int value;
	struct node* next;
}Node;
void add(Node* head, int number)
{
	Node* p = (Node*)malloc(sizeof(Node));
	p->value = number;
	p->next = NULL;
	Node* last = head;
	if (last)
	{
		while (last->next)
		{
			last = last->next;
		}
		last->next = p;
	}
	else
	{
		head = p;//这里有问题!!!(1)
	}
}
int main(void)
{
	Node* head =NULL;
	int number;
	do {
		scanf("%d", &number);
		if (number != -1)
		{
			add(head, number);//这里有问题!!!
		}
	} while (number!=-1);
	return 0;
}

代码看起来好像有点长,而且我没写注释,可能看起来比较痛苦,没关系!那就看下面这个我把问题移植到一个小代码段的下面这个吧(甚至于我把这个简化到链表都不存在了好像,只用了一个结构体)

#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<stdlib.h>
typedef struct node {
	int value;
	struct node* next;
} Node;//这里定义一个结构体,里面存一个数据(整数)+一个指向下一个同类型结构体的指针为Node
void add(Node* head);//该函数在20多行代码里面的功能就是想让头结点链起那个创建的节点
int main()
{
	Node* head = NULL;//创建头结点,并初始化为NULL;
	add(head);


	printf("%d\n", head->value);
	return 0;
}
void add(Node* head)
{
	Node* p = malloc(sizeof(Node));
	p->value = 1;
	p->next = NULL;
	head = p;
}

 

结果看见了吗?啥也没有啊,按道理来讲p所指的那个结构体看起来已经完完全全赋给了head所指的那个结构体啊(虽然一开始head指向的是NULL)。但真的是这样吗?NO!

你再看看

看出来了?参数的形参换了,结果还是个寂寞!

原因:

        1)我们都知道,函数传参的本质是的传递!add(head);是啥子意思?head在这上面是个指向Node的指针,你把head作为参数传进去,相当于把head这个变量的值给传了进去,就算他是个指针变量,那也是变量!这个值是个NULL空咧!

        2)函数传参之形参的性质:我不管你这个值是什么,现在我的形参是kkk,那我add函数就临时造一个变量来存这个NULL,当然,该临时变量是Node*类型的,然后个临时被造出来的变量,当然跟你那个add函数外面的那个head变量没有八杠子关系啊,他俩住在不同的地方啊!你把那个动态分配内存的那个p(指向一个结构体)赋给了kkk,跟另一个地方head他没有任何关系咧,head还是个孤家寡人啊,p你这人给东西给错了啊。。。

所以解决办法呢?

        1):add函数返回那个临时变量kkk的地址,因为这个地址已经指向了一个p所指的结构体,你再把这个地址交给head呗,两人共用(应该也不是,毕竟add函数调用完毕之后,那个kkk就无了,没了,就只剩head了O(∩_∩)O哈哈~)

#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<stdlib.h>
typedef struct node {
	int value;
	struct node* next;
} Node;//这里定义一个结构体,里面存一个数据(整数)+一个指向下一个同类型结构体的指针为Node
Node* add(Node* head);//该函数在20多行代码里面的功能就是想让头结点链起那个创建的节点
int main()
{
	Node* head = NULL;//创建头结点,并初始化为NULL;
	head= add(head);
	printf("%d\n", head->value);
	return 0;
}
Node* add(Node* kkk)
{
	Node* p = malloc(sizeof(Node));
	p->value = 1;
	p->next = NULL;
	kkk = p;
	return kkk;
}

 

        2)二级指针法(链表函数常用到的,优先记住这种方法

        最终的目的是让这个head指向那个当前已经创建好的结构体p,那就试图传个head这个指针的地址传进去,通过head所在的地址对head动点手:解引用他的地址拿起来做左值,即*(head的地址)=p,

        那么形参应该怎么整呢?首先这形参肯定是一个指针用来存head的地址,那首先他的形式可以设置成...*kkk,表明kkk是个指针,至于指向啥类型?存head的地址,那就肯定指向的是head了,而head是个啥?它是个Node*类型的啊,所以我们就把它设置成Node** kkk,kkk是个指针,他指向的是是个Node*类型的数据,所以代码实现:

 

#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<stdlib.h>
typedef struct node {
	int value;
	struct node* next;
} Node;//这里定义一个结构体,里面存一个数据(整数)+一个指向下一个同类型结构体的指针为Node
void add(Node** head);//该函数在20多行代码里面的功能就是想让头结点链起那个创建的节点
int main()
{
	Node* head = NULL;//创建头结点,并初始化为NULL;
	add(&head);
	printf("%d\n", head->value);
	return 0;
}
void add(Node** kkk)//你要觉得别扭,那就把kkk全部换成head,反正这函数里面的是个形参
{
	Node* p = malloc(sizeof(Node));
	p->value = 1;
	p->next = NULL;
	*kkk = p;

}

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值