问题背景
关于函数调用时的形参问题,很多人都会遇到坑,特别是一些指针的传参,可能因为理解上的疑惑,从而出现一些内存泄露问题!
知识点前提
- 栈的理解
- 函数调用过程
说明
先直接上一段代码:
#include <stdio.h>
void func(char *p, int *val)
{
int a = 100;
p = "hello world";
val = &a;
printf("val[%p] = %d \n", val, *val);
printf("p %p,%s\n", p, p);
}
int main()
{
char *p = NULL;
int *val = NULL;
printf("p=%p \n", &p);
func(p, val);
printf("p:%p, %s \n",p, p);
return 0;
}
问题
- 上面在调用func()函数后,发生了什么?
- 最后打印p的时候,p有没有值?
函数调用过程
- 简单来说,函数调用func()函数后,会进行保存上下文、形参压栈操作,即将p,val进行数据的拷贝到一个栈空间中,也就是在函数调用后,p的形参地址(压栈时的地址)和原来的p并不是同一个地址,但是其值一样。
- 也就说函数func()压栈之后,func()函数的2个指针指向内容都是NULL。后来将val指向函数内存的栈数据a,也就是100,所以后面*val就是100。但是需要注意,这个val只是一个拷贝,也就是说这个栈空间的数据指向了a这个地址,但是main()函数的值并没有发生改变!同样可以对p进行分析。
- func()函数结束后,这部分栈空间被回收,也就是这个val他是一个已被回收的空间,是一个垃圾值!如果你继续使用这个地址值,那可能会造成内存泄露!
- 执行完func(),p依旧是还是NULL;
提问
- 如果我想让val发生改变,我怎么做?
将func(p,val),改成func(p,&val),理解如下:
- 调用后,是对&val的拷贝,其值就是val的地址,如果操作*val=100,就代表这将这个val指向的值改成100,这里再理解一下,就是说这个拷贝的值是val指向的地址的地址,这个val指向地址就是外部val的地址,所以即使被调用销毁了,其外部val的值已经改变了。