前两天看到一个讲函数调用的帖子:http://blog.chinaunix.net/uid-23069658-id-3981406.html。突然想到以前自己犯过的一个错误,虽然现在不再犯了,但总觉得自己仍有理解不到位的地方,如下函数:
void fun(int *ps)
{ps = (int *)malloc(sizeof(int));
}
void main()
{
int *p;
fun(p);
*p = 1;
}
这函数当然是错的,但突然要我很详细地讲解错点,恐怕逻辑上不能理顺,今天用一种最简洁的方法描述:key在于定义一个指针其实栈上已经给其分配4字节空间,用于保存地址,如果再malloc,则会在堆上再给其分配4字节,同时会修改栈上数据为堆的起始地址,所以一个分配完内存的整型指针所占用的空间为4个栈+4个堆。记住一点:任何时候定义的变量所占据的栈都是不一样的。
上述代码定义p时为其分了4个栈,里面是随机值,定义ps时为其分配4个栈,里面的值等于入参p,两个栈里的数据相同(*p==*ps),但两者栈地址不一样,当为ps进行malloc操作成功后,会修改ps对应栈里的数据变为malloc出来的堆的地址,对于p对应栈里的数据没有任何修改,所以当函数执行完走到*p=1这一步时,会报地址写入冲突错误。
void fun(int **ps)
{*ps = (int *)malloc(sizeof(int));
}
void main()
{
int *p;
fun(&p);
*p = 1;
}
函数修改如上后,p的栈位置与栈内数据同上,ps定义时会分配4个栈,存在ps=&p,即表示ps的栈数据(*ps)与&p的站内数据(*(&p),即p)相同,此时调用malloc为*ps分配堆并修改其栈内数据,即等同于修改p的栈内数据,于是p的栈内数据成功变为malloc出来的堆地址。
fun函数内:
fun函数结束,走到*p=1处:
《C与指针》都看到山沟里了,想想第一次看这本书还是7年前,可惜忘了很多,现在看来到了翻出来回味的时候了。