问题:在对二叉树的基本操作的函数用代码实现的过程中,出现的问题,现将问题代码浓缩以使问题更突出,代码如下:
#include<stdio.h>
#include<malloc.h>
voidfun(int *t)
{
t=(int *)malloc(sizeof(int));
if(!t) printf("malloc error!\n"); //若分配失败
}
intmain()
{
int *p;
printf("before malloc=%d\n",p);
fun(p);
printf("after malloc=%d\n",p);
return 0;
}
输出结果:
beforemalloc=-858993460
aftermalloc=-858993460
从输出结果可以看出,fun函数中的malloc根本就没有分配在p所指向的空间上。
反汇编的话我们不能预知malloc分配的空间的地址,所以也就无法从反汇编的角度去解决这个问题.(也可能是个人能力问题。)
但是我们可以通过构造不同的代码”陷阱”,从输出结果中看出端倪。
#include<stdio.h>
#include<malloc.h>
voidfun(int *t)
{
t=(int *)malloc(sizeof(int));
if(!t) printf("mallocerror!\n"); //若分配失败
printf("in the funmalloc=%x\n",t);
}
intmain()
{
int *p;
printf("before malloc=%d\n",p);
fun(p);
printf("after malloc=%d\n",p);
return 0;
}
输出结果:
beforemalloc=-858993460
inthe fun malloc=5a0f08
aftermalloc=-858993460
到这里,想到以前一个关于子函数值传递的问题:在子函数中改变形参的值不会影响到实参的值。从输出结果看出,malloc确实分配了空间,但是回到主函数还是没有改变。
依此再重新构造”陷阱”:(将分配空间的操作改为改变指针指向)
陷阱1:
#include<stdio.h>
voidfun(int *t)
{
printf("in the fun beforechange=%d\n",*t);
int b=99;
t=&b;
printf("int the fun afterchange=%d\n",*t);
}
intmain()
{
int a=10,*p=&a;
printf("int the main beforefun=%d\n",*p);
fun(p);
printf("in the main afterfun=%d\n",*p);
return 0;
}
输出结果:
intthe main before fun=10
inthe fun before change=10
intthe fun after change=99
inthe main after fun=10
请区别一下代码:
陷阱2:
#include<stdio.h>
voidfun(int *t)
{
printf("in the fun beforechange=%d\n",*t);
*t=99;
printf("int the fun afterchange=%d\n",*t);
}
intmain()
{
int a=10,*p=&a;
printf("int the main beforefun=%d\n",*p);
fun(p);
printf("in the main afterfun=%d\n",*p);
return 0;
}
输出结果:
intthe main before fun=10
inthe fun before change=10
intthe fun after change=99
inthe main after fun=99
分析:
在陷阱1中:在主函数的fun(p);中,我们传递给fun子函数的是p中的内容,也即一个指向a的地址,子函数会为这个参数临时分配空间以存储这个参数,而子函数进行的t=&b;操作会将b的地址送入这个原本为参数分配的空间中,跟p指向a没有半毛钱关系,在子函数被调用完成后,这个保存参数的空间就被释放了,不但b没有被指向了,连b所占的空间都释放了。此时p依然指向a。
而在陷阱2中:传递给fun子函数的同样是p中的内容,同样是指向a的地址,同样的子函数会为这个参数临时分配空间以存储这个参数,但是*t=99;的操作却是从这个临时分配的空间里面取出内容,也即指向a的地址,再将99赋给这个地址所指向的内容,这样的就是实打实的改变了a的值,但是p依然指向a。
由以上分析可以知道最初的问题代码的问题所在了:给子函数传递一个指向要分配空间的指针的参数,这个参数就是指向指针的指针,才能真正的给这个指针分配空间。
依此纠正错误,正确的代码如下:
#include<stdio.h>
#include<malloc.h>
voidfun(int **q)
{
printf("_fun_beforemalloc=%d\n",*q);
*q=(int *)malloc(sizeof(int));
if(!(*q)) printf("mallocerror!\n");
printf("_fun_aftermalloc=%d\n",*q);
}
intmain()
{
int *p;
printf("_main_before fun=%d\n",p);
fun(&p);
printf("_main_after fun=%d\n",p);
return 0;
}