c语言,关于初始化函数间链表地址传递问题浅析

//结构体
typedef struct node{
    
    
	int elem;
	int index;
	struct node* next;
}Node,* ListNode;
//打印链表
void print(ListNode root){
    
    
	ListNode temp = root->next;
	while (temp) {
    
    
		printf("index-%d  elem-%d\n", temp->index, temp->elem);
		temp = temp->next;
	}
}
//链表初始化
void initList(ListNode head, int size) {
    
    
	ListNode end;
	end = (ListNode)malloc(sizeof(Node));
	end = head;
	for (int i = 0; i < size; i++) {
    
    
		ListNode temp;
		temp = (ListNode)malloc(sizeof(Node));
		scanf("%d", &temp->elem);
		temp->index = i;
		end->next = temp;
		end = temp;
	}
	end->next = NULL;
}
int main() {
    
    
	ListNode root;
	root = (ListNode)malloc(sizeof(Node));
	root->elem = -1;
	root->index = -1;
	initList(root, 3);
	print(root);
	return 0;
}

问题描述

首先这是我已经改过正确的代码,代码的初衷是我想在主函数当中定义一个链表头root,并将他的地址传给函数initList进行初始化,因为我是直接将地址传给了函数,所以我不需要再通过返回值把函数中初始化完成的链表头节点通过return回主函数,便可直接去打印root链表。而不需要再root = initList(root,3);这样去接收初始化链表的头节点。

理论依据

首先我想去这样做,是因为c语言可以实现地址间的相互传递,及指针,从而规避形参与实参之间的问题,使得函数可以直接在主函数所定义的变量中进行更改,多应用于数组的操作,在主函数中将定义的数组地址传给函数,函数可以直接对数组进行各种操作,而不再需要重新定义形参数组,进而节省空间。

BUG出现

很不幸,想法很完美,可就是结果很悲惨,在确定函数中的执行流程没有任何问题的情况下,主函数中所定义的root节点,却总是和原先定义的一样,并未被初始化,这一度让我以为函数任然背着我悄悄的创建了形参,而绕开了我所传递的root根节点。

问题所在

经过长时间,大规模的不懈寻找,我终于知道了问题的关键所在,全都是因为这几行代码:

	root = (ListNode)malloc(sizeof(Node));
	root->elem = -1;
	root->index = -1;

原先的代码,我是把他们放在了函数中去执行,虽然功能完全一样,但是含义却发生了改变,理论上是没有问题的,传给函数一个NULL的头节点,函数要先给这个节点初始化,然后再去尾插法初始后续节点,但是!但是!但是! 当我在主函数定义root时,他就已经被分配了地址,虽然初始化为NULL,但是他已经有了属于它的地址我们假设这个地址为A,在进入函数之后,在我们再次初始化头节点的时候,root = (ListNode)malloc(sizeof(Node));我们再一次给头节点寻找了空间,我们再次假设这个地址为B,后续所有的初始化都是在以B为头节点的链表上进行操作,所以当我们完成整个初始化时,以A为地址的头节点root依旧时空,而这里以B为头节点的链表就相当于函数自己创建的形参一样被程序所“遗忘”,这就是为什么我们传递root地址给print函数打印时,会报错为空的原因。

解决问题

找到了问题的关键,我们便知道了该如何去解决他,仅仅是把分配头节点地址的几行代码提至主函数完成即可,寻找好了地址A,再将其传给函数,让函数仅仅只完成后续初始化操作即可!!!!(具体操作如文章开头所示代码)

感悟

虽然是一个很小很小的问题,但是他让我思索了很久,写代码往往总是那些不起眼的小问题才可能会让你代码全盘崩掉,因为你认为他不会错,你就主观上放弃了对他的检查和思考,再其次就是代码的顺序真的!!!真的!!!真的!!!非常重要,这也就是为社么操作系统或者数据库设计不好,就可能出现死锁,即使每条代码都没有问题,算法也是最优的,但是b代码比a代码先执行了就是可能会出现问题,编程还是要客观分析,以机器的思维去审视代码,少一些主观臆断。

猜你喜欢

转载自blog.csdn.net/baldicoot_/article/details/115577788