数据结构问题思考

版权声明:转载请标注出处与作者,写文不易,相互尊重从小事做起。 https://blog.csdn.net/JasonRaySHD/article/details/83340667

1、关于指针的空间分配malloc
问题背景:练习DS代码——将两个有序链表归并的算法

int main(){
	Linklist *L1,*L2,*L3,*p;
	<b>①L3 = (Linklist *)malloc(sizeof(Linklist));</b>
	<b>②L1 = IncreRearin();</b>
	<b>IncreRearin(L2);</b>
	Merge(L1,L2,L3);
	p = L3->next;
	while(p!=NULL){
		cout<<p->data<<"\t";
		p=p->next;
	}
    return 0;
}

最开始,主函数在引用Merge函数时,传入的L3没有分配空间,而是在Merge子函数中利用malloc分配了空间,结果在分配空间时报错。主要错因:指针作为参数传递时,要在被调用函数中改变传入指针的值时,应该讲形参修改为指向指针的指针,并将传入参数从指针指向的地址改为该指针的地址,例如:

被调函数test():
void test(int **p)
{
*p = (int*)malloc(sizeof(int))
}
传入方式:
int *p;
test(&p);

以后要注意,在调用其它函数,将指针作为形参传入时,可以:
一、确保该指针有明确的地址,提前利用malloc分配好地址。
二、传入方式改为传指针地址,并将被调函数参数设为指向指针的指针

实际解决方法:
1、在定义.h头文件的时候,将创建单链表的函数设置为有返回值类型的如代码②,这样只用使指针在原函数中重新定向。
2、 在调用函数中提前利用malloc分配好地址,如代码①
3、 函数设置形式参数时,使用*&L传递(如: int *&p),因为这里传入的参数是指针指向的地址的参数(*&L 表示传入的参数用指向该参数地址的指针接收,而这里传入参数是指针指向变量的地址p,因此对指针取地址&p后得到该指针地址,再用指针指向该地址,也就是传入了指向指针的指针),因此这种形式类似于在被调函数中设置形参为指向指针的指针,如代码③。
4、与3类似,只是设置形参时直接设置为 int **p

2、关于指针的空间释放free
问题背景:编写程序要求释放指定树结点的子孙结点
通过以下代码实现:
思路说明:先序遍历查找到该节点——后序遍历删除该节点的子孙结点以及该节点。

void BLTreeFunction::DeleteNode(BLTree *&T,int x)
{
	BLTree *temp = T,*pre;
	TreeStack<BLTree> *stack;
	stack->initstack(stack);
	// 通过先序遍历找到结点 
	while(!stack->Empty()||temp)
	{
		if(temp)
		{
			if(x == temp->data)
				break;
			stack->push(temp);
			pre = temp;
			temp = temp->lchild;
		}
		else{
			temp = stack->pop();
			pre = temp;
			temp = temp->rchild;
		}
	}
	if(temp->data != x)
	{
		cout<<"结点不存在!";
		return;
	}
	// 找到该节点
	while(!stack->Empty())
		stack->pop(); // 清空栈中元素
	// 通过后序遍历删除结点及其子孙结点
	BLTree *r=NULL; 
	while(temp||!stack->Empty())
	{	
		if(temp)
		{
			stack->push(temp);
			temp = temp->lchild; 
		}
		else
		{
			temp = stack->pop();
			stack->push(temp);
			if(temp->rchild&&temp->rchild!=r)
			{
				temp = temp->rchild;
			}
			else
			{
				temp = stack->pop();
****(1)*************************free(r);*******************************************
				r = temp;
				temp = NULL;
			}//if(temp->rchild&&temp->rchild!=r) else
		}//if(temp) else
	}//while(!stack->Empty()||temp)
****2**************************************************************************
	if(pre->lchild == r)
		pre->lchild = NULL;
	else if(pre->rchild == r)
		pre->rchild = NULL;
	free(r);
	r->lchild = r->rchild = NULL;
}

发现执行(1)处的free语句之后,若不执行(2)处的代码,再次遍历该树的时候,结点依然可以访问,只是部分节点data出现乱码。在(1)处代码后添加cout语句,在每次释放结点时输出提示信息,检验发现程序执行正常。
正解:C语言中利用free释放空间后,只是告诉编译器这个内存自己不需要了,但要是有指针指向该内存,内存中的内容依旧可读。但该内存可能被用作于其他内容,因此可能部分出现乱码
以后在每次释放结点之后,应该添加语句将指向该内存的指针赋值为NULL(或指向其他未释放的内存)。

猜你喜欢

转载自blog.csdn.net/JasonRaySHD/article/details/83340667