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(或指向其他未释放的内存)。